/** * EasySOA Registry * Copyright 2011 Open Wide * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Contact : easysoa-dev@googlegroups.com */ package org.easysoa.rest; import java.util.List; import java.util.SortedSet; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import org.easysoa.doctypes.AppliImpl; import org.easysoa.doctypes.Service; import org.easysoa.doctypes.Workspace; import org.easysoa.services.DeletedDocumentFilter; import org.easysoa.services.DocumentService; import org.easysoa.services.EventsHelper; import org.easysoa.services.ServiceValidationService; import org.easysoa.validation.CorrelationMatch; import org.easysoa.validation.ServiceValidator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.nuxeo.ecm.core.api.ClientException; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; import org.nuxeo.ecm.core.api.DocumentRef; import org.nuxeo.ecm.core.api.IdRef; import org.nuxeo.ecm.core.api.PathRef; import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl; import org.nuxeo.ecm.core.api.model.Property; import org.nuxeo.ecm.core.api.model.PropertyException; import org.nuxeo.ecm.core.api.model.impl.ListProperty; import org.nuxeo.ecm.webengine.jaxrs.session.SessionFactory; import org.nuxeo.runtime.api.Framework; @Path("easysoa/dashboard") public class DashboardRest { @GET @Path("/services/{workspace}") @Produces(MediaType.APPLICATION_JSON) public Object getServicesByWorkspace(@Context HttpServletRequest request, @PathParam("workspace") String workspace) throws Exception { // Init CoreSession session = SessionFactory.getSession(request); DocumentService docService = Framework.getService(DocumentService.class); JSONArray serviceEntries = new JSONArray(); try { // Find workspace DocumentModel workspaceModel = docService.findWorkspace(session, workspace); if (workspaceModel != null) { // Gather workspace services DocumentModelList workspaceServiceModels = session.query("SELECT * FROM " + Service.DOCTYPE + " WHERE ecm:path STARTSWITH '" + workspaceModel.getPathAsString() + "'" + " AND ecm:currentLifeCycleState <> 'deleted' AND ecm:currentLifeCycleState <> 'obsolete'"); // Find environment DocumentModel environmentModel = docService.findEnvironment(session, (String) workspaceModel.getProperty(Workspace.SCHEMA, Workspace.PROP_REFERENCEDENVIRONMENT)); if (environmentModel != null) { // Gather reference services DocumentModelList environmentServiceModels = session.query("SELECT * FROM " + Service.DOCTYPE + " WHERE ecm:path STARTSWITH '" + environmentModel.getPathAsString() + "'" + " AND ecm:currentLifeCycleState <> 'deleted'"); // Build response, with services in order: // 1. Matching services // 2. Reference services without match (= in environment only) // 3. Workspace services without match DocumentModelList matchedEnvironmentServiceModels = new DocumentModelListImpl(); for (DocumentModel environmentServiceModel : environmentServiceModels) { DocumentModelList matchingWorkspaceServiceModels = getLocalServices(environmentServiceModel, workspaceServiceModels); if (!workspaceServiceModels.isEmpty()) { for (DocumentModel workspaceServiceModel : matchingWorkspaceServiceModels) { serviceEntries.put(getServiceEntry(workspaceServiceModel, environmentServiceModel)); matchedEnvironmentServiceModels.add(environmentServiceModel); workspaceServiceModels.remove(workspaceServiceModel); } } } for (DocumentModel environmentServiceModel : environmentServiceModels) { if (!matchedEnvironmentServiceModels.contains(environmentServiceModel)) { serviceEntries.put(getServiceEntry(null, environmentServiceModel)); } } for (DocumentModel workspaceServiceModel : workspaceServiceModels) { serviceEntries.put(getServiceEntry(workspaceServiceModel, null)); } } else { return formatError("Workspace '" + workspace + "' has no reference environment"); } } else { return formatError("No such workspace: '" + workspace + "'"); } } catch (Exception e) { return formatError("Failed to query services state", e); } return serviceEntries.toString(); } @GET @Path("/service/{serviceid}") @Produces(MediaType.APPLICATION_JSON) public Object getServiceById(@Context HttpServletRequest request, @PathParam("serviceid") String serviceid) throws Exception { CoreSession session = SessionFactory.getSession(request); DocumentModel worskspaceServiceModel = session.getDocument(new IdRef(serviceid)); String referencePath = (String) worskspaceServiceModel.getProperty(Service.SCHEMA, Service.PROP_REFERENCESERVICE); DocumentModel referencedServiceModel = (referencePath != null) ? session.getDocument(new PathRef(referencePath)) : null; return getServiceEntry(session.getDocument(new IdRef(serviceid)), referencedServiceModel).toString(); } @GET @Path("/service/{serviceid}/matches") @Produces(MediaType.APPLICATION_JSON) public Object getServiceMatches(@Context HttpServletRequest request, @PathParam("serviceid") String serviceId) throws Exception { CoreSession session = SessionFactory.getSession(request); ServiceValidationService validationService = Framework.getService(ServiceValidationService.class); SortedSet<CorrelationMatch> findCorrelatedServices = validationService.findCorrelatedServices(session, session.getDocument(new IdRef(serviceId))); JSONArray result = new JSONArray(); for (CorrelationMatch match : findCorrelatedServices) { JSONObject matchJSON = new JSONObject(); matchJSON.put("id", match.getDocumentModel().getId()); matchJSON.put("title", match.getDocumentModel().getTitle()); matchJSON.put("correlationRate", match.getCorrelationRateAsPercentage()); result.put(matchJSON); } return result.toString(); } @GET @Path("/validators") @Produces(MediaType.APPLICATION_JSON) public Object getValidators(@Context HttpServletRequest request) throws Exception { ServiceValidationService validationService = Framework.getService(ServiceValidationService.class); JSONObject result = new JSONObject(); List<ServiceValidator> validators = validationService.getValidators(); for (ServiceValidator validator : validators) { result.put(validator.getName(), validator.getLabel()); } return result.toString(); } @POST @Path("/document/{docId}/validate") @Produces(MediaType.APPLICATION_JSON) public Object getValidators(@Context HttpServletRequest request, @PathParam("docId") String docId) throws Exception { CoreSession session = SessionFactory.getSession(request); DocumentModel doc = session.getDocument(new IdRef(docId)); JSONObject result = new JSONObject(); if (doc != null) { try { EventsHelper.fireDocumentEvent(session, EventsHelper.EVENTTYPE_VALIDATIONREQUEST, doc); result.put("result", "ok"); } catch (Exception e) { return formatError("Couldn't run validation", e); } } else { return formatError("Document not found"); } return result.toString(); } @GET @Path("/deployables/{workspace}") @Produces(MediaType.APPLICATION_JSON) public Object getDeployablesByWorkspace(@Context HttpServletRequest request, @PathParam("workspace") String workspace) throws Exception { // Init CoreSession session = SessionFactory.getSession(request); DocumentService docService = Framework.getService(DocumentService.class); JSONArray applications = new JSONArray(); // Fetch applications DocumentModel workspaceModel = docService.findWorkspace(session, workspace); DocumentModelList appliImplModels = session.getChildren(workspaceModel.getRef(), AppliImpl.DOCTYPE, new DeletedDocumentFilter(), null); for (DocumentModel appliImplModel : appliImplModels) { JSONObject application = new JSONObject(); application.put("title", appliImplModel.getTitle()); // Extract application deployables JSONArray deployables = new JSONArray(); ListProperty deployablesProp = (ListProperty) appliImplModel.getProperty(AppliImpl.SCHEMA_PREFIX + AppliImpl.PROP_DEPLOYABLES); for (Property deployableProp : deployablesProp.getChildren()) { JSONObject deployable = new JSONObject(); deployable.put("deployableName", deployableProp.get(AppliImpl.SUBPROP_DEPLOYABLENAME).getValue()); deployable.put("deployableVersion", deployableProp.get(AppliImpl.SUBPROP_DEPLOYABLEVERSION).getValue()); deployables.put(deployable); } application.put("deployables", deployables); applications.put(application); } return applications.toString(); } @POST @Path("/service/{serviceid}/linkto/{referenceid}") @Produces(MediaType.APPLICATION_JSON) public Object createServiceReference(@Context HttpServletRequest request, @PathParam("serviceid") String serviceid, @PathParam("referenceid") String referenceid) throws Exception { CoreSession session = SessionFactory.getSession(request); DocumentModel localServiceModel = session.getDocument(new IdRef(serviceid)); if (localServiceModel != null) { boolean referenceidIsNull = "null".equals(referenceid); DocumentRef referenceRef = new IdRef(referenceid); if (referenceidIsNull || session.exists(referenceRef)) { String newReferencePath = null, newReferenceOrigin = null; if (!referenceidIsNull) { newReferencePath = session.getDocument(referenceRef).getPathAsString(); newReferenceOrigin = "Manually set"; if (localServiceModel.getAllowedStateTransitions().contains("approve")) { localServiceModel.followTransition("approve"); } } else if (localServiceModel.getAllowedStateTransitions().contains("backToProject")) { localServiceModel.followTransition("backToProject"); } localServiceModel.setProperty(Service.SCHEMA, Service.PROP_REFERENCESERVICE, newReferencePath); localServiceModel.setProperty(Service.SCHEMA, Service.PROP_REFERENCESERVICEORIGIN, newReferenceOrigin); session.saveDocument(localServiceModel); session.save(); } else { return formatError("Referenced service doesn't exist anymore"); } } else { return formatError("Local service doesn't exist anymore"); } return new JSONObject("{result: 'ok'}").toString(); } @POST @Path("/service/{serviceid}/lifecycle/{transition}") @Produces(MediaType.APPLICATION_JSON) public Object followLifeCycleTransition(@Context HttpServletRequest request, @PathParam("serviceid") String serviceid, @PathParam("transition") String transition) throws Exception { CoreSession session = SessionFactory.getSession(request); DocumentModel localServiceModel = session.getDocument(new IdRef(serviceid)); if (localServiceModel != null) { try { localServiceModel.followTransition(transition); session.saveDocument(localServiceModel); session.save(); } catch (ClientException e) { return formatError("Failed to follow transition '" + transition + "': " + e.getMessage()); } } else { return formatError("Specified service doesn't exist anymore"); } return new JSONObject("{result: 'ok'}").toString(); } private JSONObject getServiceEntry(DocumentModel workspaceServiceModel, DocumentModel referencedServiceModel) throws JSONException, ClientException { JSONObject serviceEntry = getDocumentModelAsJSON(workspaceServiceModel); serviceEntry.put("referencedService", getDocumentModelAsJSON(referencedServiceModel)); return serviceEntry; } private JSONObject getDocumentModelAsJSON(DocumentModel model) throws JSONException, ClientException { JSONObject modelJSON = new JSONObject(); if (model != null) { modelJSON.put("id", model.getId()); modelJSON.put("name", model.getTitle()); modelJSON.put("url", model.getProperty(Service.SCHEMA, Service.PROP_URL)); modelJSON.put("isValidated", model.getProperty(Service.SCHEMA, Service.PROP_ISVALIDATED)); modelJSON.put("lifeCycleState", model.getCurrentLifeCycleState()); modelJSON.put("validationState", getValidationStateAsJSON(model)); } return modelJSON; } private JSONObject getValidationStateAsJSON(DocumentModel serviceModel) throws PropertyException, ClientException, JSONException { JSONObject validationStateJSON = new JSONObject(); ListProperty validationStateProperty = (ListProperty) serviceModel.getProperty(Service.SCHEMA_PREFIX + Service.PROP_VALIDATIONSTATE); for (Property validatorResult : validationStateProperty.getChildren()) { JSONObject validatorResultJSON = new JSONObject(); validatorResultJSON.put(Service.SUBPROP_ISVALIDATED, validatorResult.get(Service.SUBPROP_ISVALIDATED).getValue()); validatorResultJSON.put(Service.SUBPROP_VALIDATIONLOG, validatorResult.get(Service.SUBPROP_VALIDATIONLOG).getValue()); validationStateJSON.put((String) validatorResult.get(Service.SUBPROP_VALIDATORNAME).getValue(), validatorResultJSON); } return validationStateJSON; } private DocumentModelList getLocalServices(DocumentModel environmentServiceModel, DocumentModelList workspaceServiceModels) throws ClientException { String pathToMatch = environmentServiceModel.getPathAsString(); DocumentModelList matchingServices = new DocumentModelListImpl(); for (DocumentModel worskpaceServiceModel : workspaceServiceModels) { if (pathToMatch.equals(worskpaceServiceModel.getProperty(Service.SCHEMA, Service.PROP_REFERENCESERVICE))) { matchingServices.add(worskpaceServiceModel); } } return matchingServices; } private String formatError(String error) throws JSONException { return formatError(error, null); } private String formatError(String error, Exception e) throws JSONException { JSONObject errorObject = new JSONObject(); errorObject.put("result", error); if (e != null) { errorObject.put("stacktrace", e); } return errorObject.toString(); } }