package org.axway.grapes.server.webapp.resources; import com.yammer.dropwizard.auth.Auth; import org.axway.grapes.commons.api.ServerAPI; import org.axway.grapes.commons.datamodel.Artifact; import org.axway.grapes.commons.datamodel.Dependency; import org.axway.grapes.commons.datamodel.License; import org.axway.grapes.commons.datamodel.Module; import org.axway.grapes.server.config.GrapesServerConfig; import org.axway.grapes.server.core.ArtifactHandler; import org.axway.grapes.server.core.options.FiltersHolder; import org.axway.grapes.server.core.options.filters.CorporateFilter; import org.axway.grapes.server.core.reports.DependencyReport; import org.axway.grapes.server.db.DataUtils; import org.axway.grapes.server.db.RepositoryHandler; import org.axway.grapes.server.db.datamodel.*; import org.axway.grapes.server.db.datamodel.DbCredential.AvailableRoles; import org.axway.grapes.server.webapp.DataValidator; import org.axway.grapes.server.webapp.views.*; import org.eclipse.jetty.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.net.URL; import java.util.*; /** * Module Resource * * <p>This server resource handles all the request about modules.<br/> * This resource extends DepManViews to holds its own documentation. * The documentation is available in ModuleResourceDocumentation.ftl file.</p> * @author jdcoffre */ @Path(ServerAPI.MODULE_RESOURCE) public class ModuleResource extends AbstractResource{ private static final Logger LOG = LoggerFactory.getLogger(ModuleResource.class); public ModuleResource(final RepositoryHandler repoHandler, final GrapesServerConfig dmConfig) { super(repoHandler, "ModuleResourceDocumentation.ftl", dmConfig); } /** * Handle the update/addition of a module in Grapes database * * @param credential DbCredential * @param module Module * @return Response */ @POST @Produces(MediaType.TEXT_HTML) public Response postModule(@Auth final DbCredential credential, final Module module){ if(!credential.getRoles().contains(AvailableRoles.DEPENDENCY_NOTIFIER)){ throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); } LOG.info("Got a post Module request."); // Checks if the data is corrupted DataValidator.validate(module); // turn it into DbModel final DbModule dbModule = getModelMapper().getDbModule(module); final DbOrganization organization = getOrganizationHandler().getMatchingOrganization(dbModule); if(organization != null){ dbModule.setOrganization(organization.getName()); } // Save the module getModuleHandler().store(dbModule); final ArtifactHandler artifactHandler = getArtifactHandler(); // Add the artifacts final Set<Artifact> artifacts = DataUtils.getAllArtifacts(module); for(final Artifact artifact: artifacts){ artifactHandler.store(getModelMapper().getDbArtifact(artifact)); } // Add dependencies that does not already exist for(final Dependency dep: DataUtils.getAllDependencies(module)){ final DbArtifact dbDependency = getModelMapper().getDbArtifact(dep.getTarget()); artifactHandler.storeIfNew(dbDependency); } return Response.ok().status(HttpStatus.CREATED_201).build(); } /** * Return a list of moduleNames, stored in Grapes, regarding the filters passed in the query parameters. * This method is call via GET <dm_url>/module/names * * @param uriInfo UriInfo * @return Response A list (in HTML or JSON) of moduleNames */ @GET @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) @Path(ServerAPI.GET_NAMES) public Response getNames(@Context final UriInfo uriInfo){ LOG.info("Got a get module names request."); final FiltersHolder filters = new FiltersHolder(); filters.init(uriInfo.getQueryParameters()); final ListView view = new ListView("Module names view", "name"); final List<String> moduleNames = getModuleHandler().getModuleNames(filters); Collections.sort(moduleNames); view.addAll(moduleNames); return Response.ok(view).build(); } @GET @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) @Path("/{name}") public Response getVersionsRedirection(@PathParam("name") final String name, @Context final UriInfo uriInfo){ LOG.info("Got a get module without version redirecting on get module versions request."); try { final String redirectPath = uriInfo.getPath() + ServerAPI.GET_VERSIONS; final URL redirectUrl = new URL(uriInfo.getBaseUri().toURL(), redirectPath); return Response.seeOther(redirectUrl.toURI()).build(); } catch (Exception e) { LOG.error("Failed to redirect Get module/{name} to Get module/{name}/versions",e); throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); } } /** * Return a list of moduleNames, stored in Grapes, regarding the filters passed in the query parameters. * This method is call via GET <dm_url>/module/<name>/versions * * @param name String * @param uriInfo UriInfo * @return Response A list (in HTML or JSON) of moduleNames */ @GET @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) @Path("/{name}" + ServerAPI.GET_VERSIONS) public Response getVersions(@PathParam("name") final String name, @Context final UriInfo uriInfo){ LOG.info("Got a get versions request."); final FiltersHolder filters = new FiltersHolder(); filters.init(uriInfo.getQueryParameters()); final ListView view = new ListView("Versions of " + name, "version"); final List<String> versions = getModuleHandler().getModuleVersions(name, filters); Collections.sort(versions); view.addAll(versions); return Response.ok(view).build(); } /** * Return a module. * This method is call via GET <dm_url>/module/<name>/<version> * * @param name String * @param version String * @return Response A list (in HTML or JSON) of moduleNames */ @GET @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) @Path("/{name}/{version}") public Response get(@PathParam("name") final String name, @PathParam("version") final String version){ LOG.info("Got a get module request."); final ModuleView view = new ModuleView(); final String moduleId = DbModule.generateID(name, version); final DbModule dbModule = getModuleHandler().getModule(moduleId); final Module module = getModelMapper().getModule(dbModule); view.setModule(module); view.setOrganization(dbModule.getOrganization()); return Response.ok(view).build(); } /** * Delete a module. * This method is call via DELETE <dm_url>/module/<name>/<version> * * @param credential DbCredential * @param name String * @param version String * @return Response */ @DELETE @Path("/{name}/{version}") public Response delete(@Auth final DbCredential credential, @PathParam("name") final String name, @PathParam("version") final String version){ if(!credential.getRoles().contains(AvailableRoles.DATA_DELETER)){ throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); } LOG.info("Got a delete module request."); final String moduleId = DbModule.generateID(name, version); getModuleHandler().deleteModule(moduleId); return Response.ok("done").build(); } /** * Return an Organization. * This method is call via GET <dm_url>/module/<name>/<version>/organization * * @param name String * @param version String * @return Response A list (in HTML or JSON) of moduleNames */ @GET @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) @Path("/{name}/{version}"+ ServerAPI.GET_ORGANIZATION) public Response getOrganization(@PathParam("name") final String name, @PathParam("version") final String version){ LOG.info("Got a get module's organization request."); final String moduleId = DbModule.generateID(name, version); final DbModule dbModule = getModuleHandler().getModule(moduleId); final DbOrganization organization = getModuleHandler().getOrganization(dbModule); final OrganizationView view = new OrganizationView(getModelMapper().getOrganization(organization)); return Response.ok(view).build(); } /** * Return ancestor list of a module. * This method is call via GET <dm_url>/module/<name>/<version>/ancestors * * @param name String * @param version String * @param uriInfo UriInfo * @return Response A list of module */ @GET @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) @Path("/{name}/{version}" + ServerAPI.GET_ANCESTORS) public Response getAncestors(@PathParam("name") final String name, @PathParam("version") final String version, @Context final UriInfo uriInfo){ LOG.info("Got a get module ancestors request."); final String moduleId = DbModule.generateID(name, version); final DbModule dbModule = getModuleHandler().getModule(moduleId); final DbOrganization dbOrganization = getModuleHandler().getOrganization(dbModule); final ArtifactHandler artifactHandler = getArtifactHandler(); final FiltersHolder filters = new FiltersHolder(); filters.getDecorator().setShowLicenses(false); filters.init(uriInfo.getQueryParameters()); filters.setCorporateFilter(new CorporateFilter(dbOrganization)); final AncestorsView view = new AncestorsView("Ancestor List Of " + name +" in version " + version , getLicenseHandler().getLicenses(), filters.getDecorator()); for(final String artifactId: DataUtils.getAllArtifacts(dbModule)){ final DbArtifact dbArtifact = artifactHandler.getArtifact(artifactId); final Artifact artifact = getModelMapper().getArtifact(dbArtifact); for(final DbModule dbAncestor: artifactHandler.getAncestors(artifactId, filters)){ if(!dbAncestor.getId().equals(dbModule.getId())){ final Module ancestor = getModelMapper().getModule(dbAncestor); view.addAncestor(ancestor, artifact); } } } return Response.ok(view).build(); } /** * * Return a module dependency list. * This method is call via GET <dm_url>/module/<name>/<version>/dependencies * * @param name String * @param version String * @param uriInfo UriInfo * @return Response A list of dependencies in HTML or JSON */ @GET @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) @Path("/{name}/{version}" + ServerAPI.GET_DEPENDENCIES) public Response getDependencies(@PathParam("name") final String name, @PathParam("version") final String version, @Context final UriInfo uriInfo){ LOG.info("Got a get module dependencies request."); final FiltersHolder filters = new FiltersHolder(); filters.init(uriInfo.getQueryParameters()); final DependencyListView view = new DependencyListView("Dependency List Of " + name + " in version " + version, getLicenseHandler().getLicenses(), filters.getDecorator()); final String moduleId = DbModule.generateID(name, version); view.addAll(getDependencyHandler().getModuleDependencies(moduleId, filters)); return Response.ok(view).build(); } /** * * Return a report about the targeted module dependencies. * This method is call via GET <dm_url>/module/<name>/<version>/dependencies/report * * @param name String * @param version String * @param uriInfo UriInfo * @return Response A list of dependencies in HTML or JSON */ @GET @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) @Path("/{name}/{version}" + ServerAPI.GET_DEPENDENCIES + ServerAPI.GET_REPORT) public Response getDependencyReport(@PathParam("name") final String name, @PathParam("version") final String version, @Context final UriInfo uriInfo){ LOG.info("Got a get dependency report request."); final FiltersHolder filters = new FiltersHolder(); filters.init(uriInfo.getQueryParameters()); final String moduleId = DbModule.generateID(name, version); final DependencyReport report = getDependencyHandler().getDependencyReport(moduleId, filters); return Response.ok(report).build(); } /** * Return license list of a module. * This method is call via GET <dm_url>/module/<name>/<version>/licenses * * @param name String * @param version String * @return Response A list of license */ @GET @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) @Path("/{name}/{version}" + ServerAPI.GET_LICENSES) public Response getLicenses(@PathParam("name") final String name, @PathParam("version") final String version){ LOG.info("Got a get module licenses request."); if(name == null || version == null){ return Response.serverError().status(HttpStatus.BAD_REQUEST_400).build(); } final LicenseListView view = new LicenseListView("Licenses of " + name + " in version " + version); final String moduleId = DbModule.generateID(name,version); final List<DbLicense> dbLicenses = getModuleHandler().getModuleLicenses(moduleId); for(final DbLicense dbLicense: dbLicenses){ final License license = getModelMapper().getLicense(dbLicense); view.add(license); } return Response.ok(view).build(); } /** * Promote a module. * This method is call via POST <dm_url>/module/<name>/<version>/promote * * @param credential DbCredential * @param name String * @param version String * @return Response */ @POST @Path("/{name}/{version}" + ServerAPI.PROMOTION) public Response promote(@Auth final DbCredential credential, @PathParam("name") final String name, @PathParam("version") final String version){ if(!credential.getRoles().contains(AvailableRoles.DEPENDENCY_NOTIFIER)){ throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); } LOG.info("Got a get promote module request."); final String moduleId = DbModule.generateID(name, version); getModuleHandler().promoteModule(moduleId); return Response.ok("done").build(); } /** * Check if a module can be promoted or not * This method is call via GET <dm_url>/module/<name>/<version>/promotion/check * * @param name String * @param version String * @return Response true if the module can be promoted, false otherwise. */ @GET @Produces(MediaType.APPLICATION_JSON) @Path("/{name}/{version}" + ServerAPI.PROMOTION + ServerAPI.GET_FEASIBLE) public Response canBePromoted(@PathParam("name") final String name, @PathParam("version") final String version){ LOG.info("Got a is the module promotable request."); final String moduleId = DbModule.generateID(name,version); final PromotionReportView promotionReportView = getModuleHandler().getPromotionReport(moduleId); return Response.ok(promotionReportView.canBePromoted()).build(); } /** * Return a promotion report * * @return Response A promotion report */ @GET @Produces(MediaType.TEXT_HTML) @Path("/{name}/{version}" + ServerAPI.PROMOTION + ServerAPI.GET_REPORT) public Response getPromotionStatusReport(@PathParam("name") final String name, @PathParam("version") final String version){ LOG.info("Got a get promotion report request."); final String moduleId = DbModule.generateID(name, version); final PromotionReportView promotionReportView = getModuleHandler().getPromotionReport(moduleId); return Response.ok(promotionReportView).build(); } /** * Check if a module is promoted or not * This method is call via GET <dm_url>/module/<name>/<version>/promotion * * @return Response true if the module is promoted, false otherwise. */ @GET @Produces(MediaType.APPLICATION_JSON) @Path("/{name}/{version}" + ServerAPI.PROMOTION) public Response isPromoted(@PathParam("name") final String name, @PathParam("version") final String version){ LOG.info("Got a get promotion status request."); final String moduleId = DbModule.generateID(name,version); final DbModule module = getModuleHandler().getModule(moduleId); final Boolean promoted = module.isPromoted(); return Response.ok(promoted).build(); } /** * Return a build info * * @return Response that contains a Json Map<String,String> */ @GET @Produces(MediaType.APPLICATION_JSON) @Path("/{name}/{version}" + ServerAPI.GET_BUILD_INFO) public Response getBuildInfo(@PathParam("name") final String name, @PathParam("version") final String version){ LOG.info("Got a get buildInfo request."); final String moduleId = DbModule.generateID(name, version); final DbModule dbModule = getModuleHandler().getModule(moduleId); return Response.ok(dbModule.getBuildInfo()).build(); } /** * Update a build info * * @return Response that contains a Json Map<String,String> */ @POST @Path("/{name}/{version}" + ServerAPI.GET_BUILD_INFO) public Response updateBuildInfo(@PathParam("name") final String name, @PathParam("version") final String version, final Map<String,String> buildInfo){ LOG.info("Got a post buildInfo report request."); final String moduleId = DbModule.generateID(name,version); final DbModule dbModule = getModuleHandler().getModule(moduleId); dbModule.getBuildInfo().putAll(buildInfo); getModuleHandler().store(dbModule); return Response.ok().status(Response.Status.CREATED).build(); } /** * Provide a list of module regarding the query parameter filters * * @param uriInfo * @return Response */ @GET @Produces(MediaType.APPLICATION_JSON) @Path(ServerAPI.GET_ALL) public Response getAllModules(@Context final UriInfo uriInfo){ LOG.info("Got a get all modules request."); final FiltersHolder filters = new FiltersHolder(); filters.init(uriInfo.getQueryParameters()); final List<Module> modules = new ArrayList<Module>(); final List<DbModule> dbModules = getModuleHandler().getModules(filters); for(final DbModule dbModule: dbModules){ final Module module = getModelMapper().getModule(dbModule); modules.add(module); } return Response.ok(modules).build(); } }