package org.axway.grapes.server.webapp.resources;
import com.yammer.dropwizard.auth.Auth;
import com.yammer.dropwizard.jersey.params.BooleanParam;
import org.axway.grapes.commons.api.ServerAPI;
import org.axway.grapes.commons.datamodel.Artifact;
import org.axway.grapes.commons.datamodel.Module;
import org.axway.grapes.commons.datamodel.Organization;
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.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.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Artifact Resource
*
* <p>This server resource handles all the request about artifacts.<br/>
* This resource extends DepManViews to holds its own documentation.
* The documentation is available in ArtifactResourceDocumentation.ftl file.</p>
* @author jdcoffre
*/
@Path(ServerAPI.ARTIFACT_RESOURCE)
public class ArtifactResource extends AbstractResource {
private static final Logger LOG = LoggerFactory.getLogger(ArtifactResource.class);
public ArtifactResource(final RepositoryHandler repoHandler, final GrapesServerConfig dmConfig) {
super(repoHandler, "ArtifactResourceDocumentation.ftl", dmConfig);
}
/**
* Handle artifact posts when the server got a request POST <grapes_url>/artifact & MIME that contains the artifact.
*
* @param credential DbCredential
* @param artifact The artifact to add to Grapes database
* @return Response An acknowledgment:<br/>- 400 if the artifact is MIME is malformed<br/>- 500 if internal error<br/>- 201 if ok
*/
@POST
public Response postArtifact(@Auth final DbCredential credential, final Artifact artifact){
if(!credential.getRoles().contains(AvailableRoles.DEPENDENCY_NOTIFIER)){
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
}
LOG.info("Got a post Artifact request.");
// Checks if the data is corrupted
DataValidator.validate(artifact);
// Store the Artifact
final ArtifactHandler artifactHandler = getArtifactHandler();
final DbArtifact dbArtifact = getModelMapper().getDbArtifact(artifact);
artifactHandler.store(dbArtifact);
// Add the licenses
for(String license: artifact.getLicenses()){
artifactHandler.addLicense(dbArtifact.getGavc(), license);
}
return Response.ok().status(HttpStatus.CREATED_201).build();
}
/**
* Return a list of gavc, stored in Grapes, regarding the filters passed in the query parameters.
* This method is call via GET <grapes_url>/artifact/gavcs
*
* @return Response A list (in HTML or JSON) of gavc
*/
@GET
@Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
@Path(ServerAPI.GET_GAVCS)
public Response getGavcs(@Context final UriInfo uriInfo){
LOG.info("Got a get gavc request.");
final ListView view = new ListView("GAVCS view", "gavc");
final FiltersHolder filters = new FiltersHolder();
filters.init(uriInfo.getQueryParameters());
final List<String> gavcs = getArtifactHandler().getArtifactGavcs(filters);
Collections.sort(gavcs);
view.addAll(gavcs);
return Response.ok(view).build();
}
/**
* Return a list of groupIds, stored in Grapes.
* This method is call via GET <grapes_url>/artifact/groupids
*
* @return Response A list (in HTML or JSON) of gavc
*/
@GET
@Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
@Path(ServerAPI.GET_GROUPIDS)
public Response getGroupIds(@Context final UriInfo uriInfo){
LOG.info("Got a get groupIds request.");
final ListView view = new ListView("GroupIds view", "groupId");
final FiltersHolder filters = new FiltersHolder();
filters.init(uriInfo.getQueryParameters());
final List<String> groupIds = getArtifactHandler().getArtifactGroupIds(filters);
Collections.sort(groupIds);
view.addAll(groupIds);
return Response.ok(view).build();
}
/**
* Returns the list of available versions of an artifact
* This method is call via GET <grapes_url>/artifact/<gavc>/versions
*
* @param gavc String
* @return Response a list of versions in JSON or in HTML
*/
@GET
@Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
@Path("/{gavc}" + ServerAPI.GET_VERSIONS)
public Response getVersions(@PathParam("gavc") final String gavc){
LOG.info("Got a get artifact versions request.");
final ListView view = new ListView("Versions View", "version");
final List<String> versions = getArtifactHandler().getArtifactVersions(gavc);
Collections.sort(versions);
view.addAll(versions);
return Response.ok(view).build();
}
/**
* Returns the list of available versions of an artifact
* This method is call via GET <grapes_url>/artifact/<gavc>/versions
*
* @param gavc String
* @return Response String version in JSON
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{gavc}" + ServerAPI.GET_LAST_VERSION)
public Response getLastVersion(@PathParam("gavc") final String gavc){
LOG.info("Got a get artifact last version request.");
final String lastVersion = getArtifactHandler().getArtifactLastVersion(gavc);
return Response.ok(lastVersion).build();
}
/**
* Return an Artifact regarding its gavc.
* This method is call via GET <grapes_url>/artifact/<gavc>
*
*
* @param gavc String
* @return Response An artifact in HTML or JSON
*/
@GET
@Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
@Path("/{gavc}")
public Response get(@PathParam("gavc") final String gavc){
LOG.info("Got a get artifact request.");
final ArtifactView view = new ArtifactView();
final DbArtifact dbArtifact = getArtifactHandler().getArtifact(gavc);
view.setShouldNotBeUse(dbArtifact.getDoNotUse());
final Artifact artifact = getModelMapper().getArtifact(dbArtifact);
view.setArtifact(artifact);
final DbOrganization dbOrganization = getArtifactHandler().getOrganization(dbArtifact);
if(dbOrganization != null){
final Organization organization = getModelMapper().getOrganization(dbOrganization);
view.setOrganization(organization);
}
return Response.ok(view).build();
}
/**
* Update an artifact download url.
* This method is call via GET <grapes_url>/artifact/<gavc>/downloadurl?url=<targetUrl>
*
* @param credential DbCredential
* @param gavc String
* @param downLoadUrl String
* @return Response
*/
@POST
@Path("/{gavc}" + ServerAPI.GET_DOWNLOAD_URL)
public Response updateDownloadUrl(@Auth final DbCredential credential, @PathParam("gavc") final String gavc, @QueryParam(ServerAPI.URL_PARAM) final String downLoadUrl){
if(!credential.getRoles().contains(AvailableRoles.DATA_UPDATER)){
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
}
LOG.info("Got an update downloadUrl request.");
if(gavc == null || downLoadUrl == null){
return Response.serverError().status(HttpStatus.NOT_ACCEPTABLE_406).build();
}
getArtifactHandler().updateDownLoadUrl(gavc, downLoadUrl);
return Response.ok("done").build();
}
/**
* Update an artifact download url.
* This method is call via GET <grapes_url>/artifact/<gavc>/downloadurl?url=<targetUrl>
*
*/
@POST
@Path("/{gavc}" + ServerAPI.GET_PROVIDER)
public Response updateProvider(@Auth final DbCredential credential, @PathParam("gavc") final String gavc, @QueryParam(ServerAPI.PROVIDER_PARAM) final String provider){
if(!credential.getRoles().contains(AvailableRoles.DATA_UPDATER)){
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
}
LOG.info("Got an update downloadUrl request.");
if(gavc == null || provider == null){
return Response.serverError().status(HttpStatus.NOT_ACCEPTABLE_406).build();
}
getArtifactHandler().updateProvider(gavc, provider);
return Response.ok("done").build();
}
/**
* Delete an Artifact regarding its gavc.
* This method is call via DELETE <grapes_url>/artifact/<gavc>
*
* @param credential DbCredential
* @param gavc String
* @return Response
*/
@DELETE
@Path("/{gavc}")
public Response delete(@Auth final DbCredential credential, @PathParam("gavc") final String gavc){
if(!credential.getRoles().contains(AvailableRoles.DATA_DELETER)){
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
}
LOG.info("Got a delete artifact request.");
getArtifactHandler().deleteArtifact(gavc);
return Response.ok().build();
}
/**
* Add "DO_NOT_USE" flag to an artifact
*
* @param credential DbCredential
* @param gavc String
* @param doNotUse boolean
* @return Response
*/
@POST
@Path("/{gavc}" + ServerAPI.SET_DO_NOT_USE)
public Response postDoNotUse(@Auth final DbCredential credential, @PathParam("gavc") final String gavc,@QueryParam(ServerAPI.DO_NOT_USE) final BooleanParam doNotUse){
if(!credential.getRoles().contains(AvailableRoles.ARTIFACT_CHECKER)){
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
}
LOG.info("Got a add \"DO_NOT_USE\" request.");
getArtifactHandler().updateDoNotUse(gavc, doNotUse.get());
return Response.ok("done").build();
}
/**
* Return true if the targeted artifact is flagged with "DO_NOT_USE".
* This method is call via GET <grapes_url>/artifact/<gavc>/donotuse
*
* @param gavc String
* @return Response
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{gavc}" + ServerAPI.SET_DO_NOT_USE)
public Response getDoNotUse(@PathParam("gavc") final String gavc){
LOG.info("Got a get doNotUse artifact request.");
final DbArtifact artifact = getArtifactHandler().getArtifact(gavc);
return Response.ok(artifact.getDoNotUse()).build();
}
/**
* Return the list of ancestor of an artifact.
* This method is call via GET <grapes_url>/artifact/<gavc>/ancestors
*
* @param gavc String
* @param uriInfo UriInfo
* @return Response A list of ancestor in HTML or JSON
*/
@GET
@Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
@Path("/{gavc}" + ServerAPI.GET_ANCESTORS)
public Response getAncestors(@PathParam("gavc") final String gavc, @Context final UriInfo uriInfo){
LOG.info("Got a get artifact request.");
final FiltersHolder filters = new FiltersHolder();
filters.getDecorator().setShowLicenses(false);
filters.init(uriInfo.getQueryParameters());
final AncestorsView view = new AncestorsView("Ancestor List Of " + gavc, getLicenseHandler().getLicenses(), filters.getDecorator());
final List<DbModule> dbAncestors = getArtifactHandler().getAncestors(gavc, filters);
final Artifact artifact = DataUtils.createArtifact(gavc);
for(DbModule dbAncestor : dbAncestors){
final Module ancestor = getModelMapper().getModule(dbAncestor);
view.addAncestor(ancestor, artifact);
}
return Response.ok(view).build();
}
/**
* Returns the list of licenses used by an artifact.
* This method is call via GET <grapes_url>/artifact/{gavc}/licenses
*
* @param gavc
* @return Response A list of dependencies in HTML or JSON
*/
@GET
@Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
@Path("/{gavc}" + ServerAPI.GET_LICENSES)
public Response getLicenses(@PathParam("gavc") final String gavc, @Context final UriInfo uriInfo){
LOG.info("Got a get artifact licenses request.");
final LicenseListView view = new LicenseListView("Licenses of " + gavc);
final FiltersHolder filters = new FiltersHolder();
filters.init(uriInfo.getQueryParameters());
final List<DbLicense> dbLicenses = getArtifactHandler().getArtifactLicenses(gavc,filters);
for(DbLicense license: dbLicenses){
view.add(getModelMapper().getLicense(license));
}
return Response.ok(view).build();
}
/**
* Add a license to an artifact
*
* @param credential DbCredential
* @param gavc String
* @param licenseId String
* @return Response
*/
@POST
@Path("/{gavc}" + ServerAPI.GET_LICENSES)
public Response addLicense(@Auth final DbCredential credential, @PathParam("gavc") final String gavc,@QueryParam(ServerAPI.LICENSE_ID_PARAM) final String licenseId){
if(!credential.getRoles().contains(AvailableRoles.DATA_UPDATER)){
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
}
LOG.info("Got a add license request.");
if(licenseId == null){
return Response.serverError().status(HttpStatus.NOT_ACCEPTABLE_406).build();
}
getArtifactHandler().addLicenseToArtifact(gavc, licenseId);
return Response.ok("done").build();
}
/**
* Removes a license from an artifact
*
* @param credential DbCredential
* @param gavc String
* @param licenseId String
* @return Response
*/
@DELETE
@Path("/{gavc}" + ServerAPI.GET_LICENSES)
public Response deleteLicense(@Auth final DbCredential credential, @PathParam("gavc") final String gavc,@QueryParam(ServerAPI.LICENSE_ID_PARAM) final String licenseId){
if(!credential.getRoles().contains(AvailableRoles.DATA_UPDATER)){
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
}
LOG.info("Got a delete license request.");
if(licenseId == null){
return Response.serverError().status(HttpStatus.NOT_ACCEPTABLE_406).build();
}
getArtifactHandler().removeLicenseFromArtifact(gavc, licenseId);
return Response.ok("done").build();
}
/**
* Returns the Module of an artifact.
* This method is call via GET <grapes_url>/artifact/{gavc}/module
*
* @param gavc String
* @return Response a module in HTML or JSON
*/
@GET
@Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
@Path("/{gavc}" + ServerAPI.GET_MODULE)
public Response getModule(@PathParam("gavc") final String gavc, @Context final UriInfo uriInfo){
LOG.info("Got a get artifact's module request.");
final ArtifactHandler artifactHandler = getArtifactHandler();
final DbArtifact artifact = artifactHandler.getArtifact(gavc);
final DbModule module = artifactHandler.getModule(artifact);
if(module == null){
return Response.noContent().build();
}
final ModuleView view = new ModuleView();
view.setModule(getModelMapper().getModule(module));
view.setOrganization(module.getOrganization());
return Response.ok(view).build();
}
/**
* Returns the Organization of an artifact.
* This method is call via GET <grapes_url>/artifact/{gavc}/module
*
* @param gavc String
* @return Response a module in HTML or JSON
*/
@GET
@Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
@Path("/{gavc}" + ServerAPI.GET_ORGANIZATION)
public Response getOrganization(@PathParam("gavc") final String gavc, @Context final UriInfo uriInfo){
LOG.info("Got a get artifact's organization request.");
final ArtifactHandler artifactHandler = getArtifactHandler();
final DbArtifact artifact = artifactHandler.getArtifact(gavc);
final DbModule module = artifactHandler.getModule(artifact);
if(module == null || module.getOrganization().isEmpty()){
return Response.noContent().build();
}
final DbOrganization organization = getOrganizationHandler().getOrganization(module.getOrganization());
final OrganizationView view = new OrganizationView(getModelMapper().getOrganization(organization));
return Response.ok(view).build();
}
/**
* Return all the artifacts that matches the filters.
* This method is call via GET <grapes_url>/artifact/<gavc>
* Following filters can be used: artifactId, classifier, groupId, hasLicense, licenseId, type, uriInfo, version
*
* @param uriInfo UriInfo
* @return Response An artifact in HTML or JSON
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path(ServerAPI.GET_ALL)
public Response getAll(@Context final UriInfo uriInfo){
LOG.info("Got a get all artifact request.");
final FiltersHolder filters = new FiltersHolder();
filters.init(uriInfo.getQueryParameters());
final List<Artifact> artifacts = new ArrayList<Artifact>();
final List<DbArtifact> dbArtifacts = getArtifactHandler().getArtifacts(filters);
for(DbArtifact dbArtifact: dbArtifacts){
artifacts.add(getModelMapper().getArtifact(dbArtifact));
}
return Response.ok(artifacts).build();
}
}