OpenMBEE是一个用于支持系统工程师进行并发协作设计的软件平台,它通过集成化的软件应用程序和服务,实现了工程模型和文档的一致性、可追溯性和精确性,从而提高了系统工程的效率和质量。本文将对Open-MBEE中部分模块进行分析,以更加了解其功能与逻辑。
Crud模块-controller部分
-CRUD是指Create(创建)、Read(读取)、Update(更新)和Delete(删除)这四个基本操作,应用于组织(orgs)、项目(projects)、分支(branches)、元素(elements)和提交(commits)等对象的操作。
-服务工厂(Service Factory)位于services下,其主要功能是根据特定的项目类型/模式获取正确的服务bean。当创建或获取项目或元素时,工厂会根据项目模式在"ProjectService" 或"NodeService"前加上前缀来构造 bean 的名称。
-CRUD 框架和服务工厂机制允许用户根据不同的项目模式和需求,通过扩展和自定义服务来灵活地管理数据对象。这种设计使得系统能够支持多种项目类型和模式,同时保持核心逻辑的通用性和可维护性。
-
Controller
-权限控制:所有方法都使用了@PreAuthorize注解进行权限控制。这确保了在执行方法之前,用户必须具有相应的权限。权限检查通过调用mss.hasBranchPrivilege方法实现,该方法根据提供的参数判断用户是否具有特定的权限。
-异常处理:代码能够捕获MMSException异常,并在发生异常时向response对象中添加一个Rejection对象,以记录被拒绝的项目的详细信息。这有助于客户端了解哪些项目处理失败以及失败的原因。
1)BaseController
-定义了一个名为BaseController的抽象类,用于Spring框架中的控制器基类。它包含了一些保护级别的成员变量和方法,以及通过Spring的@Autowired注解进行自动注入的setter方法。
-其他部分Controller均在对BaseController类的扩展上实现
-方法getProjectType
接受一个projectId作为参数,并尝试从projectRepository中查找对应的项目。如果找到了项目,则返回项目的类型;如果没有找到,则抛出一个NotFoundException异常,表示项目未找到。
-方法getNodeService
接受一个projectId作为参数,并调用getProjectType方法来获取项目类型。然后,它使用serviceFactory的getNodeService方法,根据项目类型来获取相应的NodeService实例。
-方法handleSingleResponse
这个方法处理一个BaseResponse对象,并检查其getRejected方法返回的结果。如果响应包含拒绝信息,它会根据拒绝信息的代码抛出特定的异常。如果响应没有拒绝信息或代码未知,则方法不会执行任何特殊操作。
2)BranchController
-处理与项目的分支(通常指Git分支)相关的RESTful API请求。
-通过 GET 请求,提供获取项目中所有分支信息的功能。根据权限设置,过滤出用户有权查看的分支。
-通过 GET 请求,提供获取项目中特定分支信息的功能。这要求用户具有读取该分支的权限。
-创建分支:该方法允许用户通过发送一个包含分支信息的JSON请求体来创建新的分支。如果分支的ID没有提供,系统将为其生成一个随机的UUID。
-检查权限:使用@PreAuthorize注解来进行权限检查,确保只有拥有PROJECT_CREATE_BRANCH权限的用户才能创建分支。
-验证分支 ID:方法检查分支ID的有效性,如果 ID 无效,则在响应中添加一个拒绝信息。
-设置分支创建者:方法将当前认证用户的名称设置为新创建分支的创建者。
-初始化分支权限:在创建分支后,调用其他方法来初始化分支的权限设置。
-处理单个响应:如果请求中只包含一个分支,则调用handleSingleResponse方法来处理响应。
-删除分支:该方法根据提供的projectId和refId删除指定的分支。
-检查权限:使用@PreAuthorize注解来进行权限检查,确保只有拥有BRANCH_DELETE 权限的用户才能删除分支。
-返回响应:方法调用服务层branchService的deleteBranch方法来执行实际的删除操作
-静态方法isBranchIdValid
这个静态方法用于验证分支 ID 是否有效。
3)CommitController
-处理与项目提交(Commits)相关的HTTP GET请求。这个控制器提供了几个端点(endpoint),用于获取特定分支(ref)的提交、特定提交的详细信息以及特定元素的提交历史
-权限检查:每个方法都使用@PreAuthorize注解来检查当前认证用户是否拥有读取项目提交的权限。@mss.hasProjectPrivilege 方法负责执行这个权限检查。
-getRefCommits 方法:获取指定分支的提交列表。
-参数:项目ID,分支ID,返回的提交数量(可选),只返回时间戳小于或等于该值的提交(可选),其他查询参数(可选)。
-根据项目类型从serviceFactory获取CommitService。调用CommitService的getRefCommits方法,传入相应的参数,获取提交列表。返回CommitsResponse类型的响应。
-getCommit方法:获取指定提交的详细信息。
-参数:项目ID,提交ID。
-根据项目类型从serviceFactory获取CommitService,调用CommitService的getCommit方法,传入项目ID和提交ID。返回CommitsResponse类型的响应。
-getElementCommits方法
获取指定元素的提交历史。
参数:项目ID,分支ID,元素ID。其他查询参数(可选)。
-根据项目类型从serviceFactory获取CommitService。调用CommitService的getElementCommits方法,传入相应的参数,获取元素的提交历史。返回CommitsResponse类型的响应。
4)ElementController
-处理与项目的元素(elements)相关的请求
-getAllElements方法:处理GET请求,获取指定项目的所有元素。
-getElement方法:获取单个元素
通过NodeService的read方法读取指定项目的指定引用的单个元素。
调用方法处理响应,返回读取到的元素作为ElementsResponse对象。
-createOrUpdateElements方法:创建或更新元素
注入Authentication对象以获取当前认证信息。
调用embeddedHookService的hook方法触发一个元素更新的钩子
创建一个ElementsResponse对象用于响应。
如果请求中的元素列表不为空,则通过NodeService的createOrUpdate方法创建或更新元素,并返回响应。
如果元素列表为空,则抛出一个BadRequestException异常,并在响应中添加一条“Empty”消息。
-处理一个HTTP请求,该请求以流的形式接收JSON数据,然后解析这些数据,并根据解析的内容创建或更新项目元素。
通过路径变量获取projectId和refId。
获取请求中的参数,如果未提供,则为空。
获取请求头的Accept字段,如果不存在则默认为application/json。
Authentication auth: 获取当前认证信息。
HttpEntity<byte> requestEntity: 获取请求的实体内容
-生成提交ID:
生成一个随机的UUID作为提交ID,并添加到params映射中。
初始化请求对象和元素列表:
创建一个ElementsRequest对象req。
初始化一个空的元素列表elements。
-处理请求体:
从requestEntity中获取字节流,并转换为一个InputStream。
创建一个StreamingResponseBody对象,该对象在写入输出流时会执行提供的lambda函数。
-解析JSON流:
使用ObjectMapper和JsonParser来解析从输入流中读取的JSON数据。
检查JSON是否以对象开始,如果不是,则抛出一个BadRequestException异常。
遍历JSON对象,查找名为"elements"的数组。
如果找到"elements"数组,则遍历该数组,并使用ObjectMapper将每个元素解析为ElementJson对象,然后添加到elements列表中。
-处理解析后的元素:
将解析得到的元素列表设置到req对象中。
如果req中的元素列表不为空,则获取相应的NodeService实例,并调用其createOrUpdate方法来创建或更新元素。
-异常处理:
如果在处理流或解析JSON时发生IOException,则记录调试信息。
-getElements方法:使用post获取元素
创建一个ElementsResponse对象。
如果req中的元素列表不为空,则获取NodeService的实例并调用其read方法来读取元素,然后返回结果。
如果元素列表为空,则抛出一个BadRequestException,并添加一条"Empty"的消息到响应中。
-deleteElement方法:删除单个元素
调用getNodeService(projectId)获取NodeService的实例。
调用NodeService的delete方法来删除指定ID的元素,并返回ElementsCommitResponse对象。
调用handleSingleResponse方法处理返回的响应,返回处理后的响应。
-deleteElements方法:删除多个元素。
调用getNodeService(projectId)获取NodeService的实例。
调用NodeService的delete方法来删除请求中指定的多个元素,并返回ElementsResponse对象。
返回处理后的响应。
5)Orgscontroller
-用于处理与组织相关的 HTTP 请求
-getAllOrgs方法:获取所有用户有权限读取的组织。
创建一个OrganizationsResponse对象来收集结果。
从organizationRepository中获取所有组织。
遍历每个组织,检查用户是否有读取权限。
如果有权限,将组织转换为OrgJson对象并添加到响应中。
返回包含有权限读取的组织的响应。
-getOrg方法:根据组织 ID 获取单个组织。
创建一个 OrganizationsResponse 对象来收集结果。
使用 organizationRepository 的 findByOrganizationId 方法根据 ID 查找组织。
如果组织不存在,抛出 NotFoundException 异常。
如果组织存在,将其转换为 OrgJson 对象并添加到响应中。
返回包含单个组织的响应。
-createOrUpdateOrgs方法:创建或更新组织
-创建响应对象:
初始化一个OrganizationsResponse对象,用于收集方法的响应数据。
-验证请求体:
如果orgPost中的组织列表为空,则抛出一个BadRequestException异常,并添加一条消息说明没有提供组织信息。
-遍历组织列表:
对于请求体中的每个OrgJson对象(代表一个组织),执行以下操作:
a.处理新组织:
如果组织的ID为空或未设置,则为其生成一个新的UUID作为ID。
b.查找或创建组织:
使用组织的ID查找数据库中的Organization对象。如果找不到,则创建一个新的Organization对象。
c.权限检查:
如果找到了现有的Organization对象,并且当前用户没有编辑该组织的权限,则在响应中添加一条拒绝信息,并跳过当前组织的处理。
d.更新组织信息:
设置组织的ID和名称,并保存到数据库中。
e.初始化权限:
如果这是一个新创建的组织,则调用permissionService的initOrgPerms方法来初始化组织的权限。
f.更新响应对象:
将保存后的组织信息合并到OrgJson对象中,并添加到响应列表中。
-处理单组织响应:
如果请求体中只包含一个组织,则调用handleSingleResponse方法来处理响应
-返回响应:
返回包含所有处理后的组织的 OrganizationsResponse 对象。
-deleteOrg方法:创建响应对象:
初始化一个OrganizationsResponse对象,用于收集方法的响应数据。
-查找组织:
使用组织的ID从organizationRepository中查找对应的Organization对象。
-验证组织存在:
如果找不到对应的组织,则抛出一个NotFoundException异常,并添加一条消息说明组织未找到。
-检查组织是否为空:
如果组织中存在项目(即org.getProjects()返回的列表不为空),则抛出一个BadRequestException异常,并添加一条消息说明组织不为空,不能删除。
-删除组织:
如果以上检查都通过,则调用organizationRepository.delete(org)来删除该组织。
-返回响应:
最后,返回包含可能已添加的消息的OrganizationsResponse对象。
6)ProjectSchemasController
-提供了一个简单的 GET 端点,用于获取所有项目模式。通过依赖注入,它使用了ProjectSchemas服务或组件来获取这些模式,并将它们封装在一个SchemasResponse对象中返回。此外,这个控制器还通过注解进行了简单的OpenAPI文档标记,以便可以自动生成 API 文档。
7)ProjectController
-用于处理与项目相关的 HTTP 请求
-控制器依赖注入了三个服务或组件:ProjectDAO(用于数据访问)、ProjectIndex(可能用于搜索或索引)和 ProjectSchemas(用于处理项目模式)
getAllProjects方法:获取所有项目
-接受两个参数:
Authentication auth:用于身份验证的对象,通常包含用户的认证信息。
String orgId:组织ID,这是一个可选参数,用于过滤特定组织下的项目。
-创建一个新的 ProjectsResponse 对象来封装响应数据。
-根据orgId是否为null,从projectRepository中获取所有项目或特定组织下的项目。
-遍历获取到的所有项目,对每个项目执行操作:
使用mss.hasProjectPrivilege方法检查用户是否具有读取该项目的权限。
如果用户有权限,则设置项目ID到ContextHolder
检查项目是否已被删除,并且其docId是否不为null。
使用projectIndex的findById方法根据docId查找项目的 JSON 表示。
如果找到了 JSON 表示,则将其添加到响应中;否则,记录一条错误日志。
返回封装了所有符合条件项目的ProjectsResponse对象。
-getProject方法:获取指定ID的项目
-接受一个路径变量参数:
@PathVariable String projectId: 项目的 ID。
使用projectId设置ContextHolder的上下文。
创建一个新的ProjectsResponse对象来封装响应数据。
使用projectRepository的findByProjectId方法根据projectId查找项目。
如果找不到项目,则抛出一个NotFoundException异常,并向响应中添加相应的消息。
使用projectIndex的findById方法根据项目的docId查找项目的JSON表示。
如果找到了JSON表示,则将其添加到响应中;否则,抛出一个NotFoundException异常。
检查项目是否已被删除,如果已删除,则抛出一个DeletedException异常。
返回封装了指定项目的ProjectsResponse对象。
-deleteProject 方法:删除一个项目。
首先检查传入的projectId是否在数据库中存在,如果不存在,则抛出一个NotFoundException异常。
如果项目存在,将项目的deleted字段设置为true,这表示项目已被软删除(即逻辑删除,而非物理删除)。
创建一个ProjectJson对象,并将更新后的项目信息合并到这个对象中。
根据hard参数的值,该方法执行不同的操作:
如果hard为true,则直接从数据库中删除项目,并从索引中删除对应的条目。
如果hard为false(或未提供,默认值为false),则只更新数据库中的项目信息,不执行物理删除。
最后,该方法返回包含已删除(或标记为删除)项目的ProjectsResponse对象。
-getProjectService方法:获取特定类型的项目服务。
检查传入的ProjectJson对象是否包含项目类型(projectType)。
不包含,则尝试通过项目ID获取项目类型,并在发生NotFoundException异常时设置默认类型为"default"。
使用获取到的项目类型从serviceFactory中获取对应的ProjectService对象。
-isProjectIdValid方法:验证传入的projectId是否有效。
检查projectId是否非空,并且是否符合PROJECT_ID_VALID_PATTERN这个正则表达式定义的模式。都满足,则返回true,否则返回false。