/** * 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.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.security.auth.login.LoginException; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.cxf.common.util.UrlUtils; import org.easysoa.api.EasySOAApiSession; import org.easysoa.api.EasySOADocument; import org.easysoa.api.EasySOALocalApiFactory; import org.easysoa.doctypes.AppliImpl; import org.easysoa.doctypes.EasySOADoctype; import org.easysoa.doctypes.Service; import org.easysoa.doctypes.ServiceAPI; import org.easysoa.doctypes.ServiceReference; import org.easysoa.services.PersonalWorkspaceFilter; 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.webengine.jaxrs.session.SessionFactory; import org.nuxeo.ecm.webengine.model.view.TemplateView; import com.sun.jersey.api.core.HttpContext; import com.sun.jersey.api.representation.Form; @Path("easysoa/discovery") public class DiscoveryRest { private static final Log log = LogFactory.getLog(DiscoveryRest.class); private static final String ERROR = "[ERROR] "; private JSONObject result = new JSONObject(); private Map<String, String> commonPropertiesDocumentation; public DiscoveryRest() { try { result.put("result", "ok"); } catch (JSONException e) { log.error("JSON init failure", e); } } @GET @Path("/") public Object doPostDiscoveryRoot() { return new TemplateView(new EasySOAModuleRoot(), "index.html"); } @GET @Path("/environments") public Object doGetEnvironmentNames(@Context HttpServletRequest request) throws ClientException { CoreSession session = SessionFactory.getSession(request); DocumentModelList models = session.query( "SELECT * FROM Workspace WHERE ecm:currentLifeCycleState <> 'deleted'", new PersonalWorkspaceFilter()); JSONArray result = new JSONArray(); for (DocumentModel model : models) { result.put(model.getTitle()); } return result.toString(); } @POST @Path("/appliimpl") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) public Object doPostAppliImpl(@Context HttpContext httpContext, @Context HttpServletRequest request) throws Exception { EasySOAApiSession api = EasySOALocalApiFactory.createLocalApi(SessionFactory.getSession(request)); Map<String, String> params = getFirstValues(request.getParameterMap()); try { EasySOADocument doc = api.notifyAppliImpl(params); result.put("documentId", doc.getId()); } catch (Exception e) { appendError(e.getMessage()); } return getFormattedResult(); } @GET @Path("/appliimpl") @Produces(MediaType.APPLICATION_JSON) public Object doGetAppliImpl() throws JSONException { result = new JSONObject(); JSONObject params = new JSONObject(); Map<String, String> commonDef = getCommonPropertiesDocumentation(AppliImpl.DOCTYPE); for (Entry<String, String> entry : commonDef.entrySet()) { params.put(entry.getKey(), entry.getValue()); } Map<String, String> appliImplDef = AppliImpl.getPropertyList(); for (Entry<String, String> entry : appliImplDef.entrySet()) { params.put(entry.getKey(), entry.getValue()); } Map<String, String> featureDef = AppliImpl.getFeaturePropertyList(); for (Entry<String, String> entry : featureDef.entrySet()) { params.put(entry.getKey(), entry.getValue()); } result.put("parameters", params); result.put("description", "Notification concerning an application implementation."); return getFormattedResult(); } @POST @Path("/api") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) public Object doPostApi(@Context HttpContext httpContext, @Context HttpServletRequest request) throws Exception { EasySOAApiSession api = EasySOALocalApiFactory.createLocalApi(SessionFactory.getSession(request)); Map<String, String> params = getFirstValues(request.getParameterMap()); try { EasySOADocument doc = api.notifyServiceApi(params); result.put("documentId", doc.getId()); } catch (Exception e) { appendError(e.getMessage()); } return getFormattedResult(); } @GET @Path("/api") @Produces(MediaType.APPLICATION_JSON) public Object doGetApi() throws JSONException { result = new JSONObject(); JSONObject params = new JSONObject(); Map<String, String> commonDef = getCommonPropertiesDocumentation(ServiceAPI.DOCTYPE); for (Entry<String, String> entry : commonDef.entrySet()) { params.put(entry.getKey(), entry.getValue()); } Map<String, String> apiDef = ServiceAPI.getPropertyList(); for (Entry<String, String> entry : apiDef.entrySet()) { params.put(entry.getKey(), entry.getValue()); } result.put("parameters", params); result.put("description", "API-level notification."); return getFormattedResult(); } @POST @Path("/service") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) public Object doPostService(@Context HttpContext httpContext, @Context HttpServletRequest request) throws Exception { EasySOAApiSession api = EasySOALocalApiFactory.createLocalApi(SessionFactory.getSession(request)); Map<String, String> params = getFirstValues(request.getParameterMap()); try { EasySOADocument doc = api.notifyService(params); result.put("documentId", doc.getId()); } catch (Exception e) { appendError(e.getMessage()); } return getFormattedResult(); } @GET @Path("/service") @Produces(MediaType.APPLICATION_JSON) public Object doGetService() throws JSONException { result = new JSONObject(); JSONObject params = new JSONObject(); Map<String, String> commonDef = getCommonPropertiesDocumentation(Service.DOCTYPE); for (Entry<String, String> entry : commonDef.entrySet()) { params.put(entry.getKey(), entry.getValue()); } Map<String, String> serviceDef = Service.getPropertyList(); for (Entry<String, String> entry : serviceDef.entrySet()) { params.put(entry.getKey(), entry.getValue()); } result.put("parameters", params); result.put("description", "Service-level notification."); return getFormattedResult(); } @GET @Path("/service/jsonp") @Produces("application/javascript") public Object doGetServiceJSONP(@Context HttpContext httpContext, @Context HttpServletRequest request, @QueryParam("callback") String callback) throws Exception { EasySOAApiSession api = EasySOALocalApiFactory.createLocalApi(SessionFactory.getSession(request)); Map<String, String> params = getFirstValues2(httpContext.getRequest().getQueryParameters()); try { EasySOADocument doc = api.notifyService(params); result.put("documentId", doc.getId()); } catch (Exception e) { appendError(e.getMessage()); } return getFormattedResult(callback); } @POST @Path("/servicereference") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) public Object doPostServiceReference(@Context HttpContext httpContext, @Context HttpServletRequest request, String body) throws Exception { EasySOAApiSession api = EasySOALocalApiFactory.createLocalApi(SessionFactory.getSession(request)); Map<String, String> params = getFirstValues(request.getParameterMap()); try { EasySOADocument doc = api.notifyServiceReference(params); result.put("documentId", doc.getId()); } catch (Exception e) { appendError(e.getMessage()); } return getFormattedResult(); } @GET @Path("/servicereference") @Produces(MediaType.APPLICATION_JSON) public Object doGetServiceReference() throws JSONException { result = new JSONObject(); JSONObject params = new JSONObject(); Map<String, String> commonDef = getCommonPropertiesDocumentation(ServiceReference.DOCTYPE); for (Entry<String, String> entry : commonDef.entrySet()) { params.put(entry.getKey(), entry.getValue()); } Map<String, String> serviceReferenceDef = ServiceReference.getPropertyList(); for (Entry<String, String> entry : serviceReferenceDef.entrySet()) { params.put(entry.getKey(), entry.getValue()); } result.put("parameters", params); result.put("description", "Service-level notification."); return getFormattedResult(); } @POST @Path("/{all:.*}") @Produces(MediaType.APPLICATION_JSON) public Object doPostInvalid() throws JSONException, LoginException { appendError("Content type should be 'application/x-www-form-urlencoded'"); return getFormattedResult(); } public static Form getStructuredParams(String query, String sep, boolean decode, boolean decodePlus) { // Taken from org.apache.cxf.jaxrs.utils.JAXRSUtils.getStructuredParams() // Could not link to the real one because of a classpath conflict with its dependencies Form queries = new Form(); if (query != null && query.length() != 0) { List<String> parts = Arrays.asList(query.split(sep)); for (String part : parts) { int index = part.indexOf('='); String name = null; String value = null; if (index == -1) { name = part; value = ""; } else { name = part.substring(0, index); value = index < part.length() ? part.substring(index + 1) : ""; if (decode || (decodePlus && value.contains("+"))) { value = (";".equals(sep)) ? UrlUtils.pathDecode(value) : UrlUtils.urlDecode(value); } } queries.add(UrlUtils.urlDecode(name), value); } } return queries; } public static Map<String, String> getFirstValues(Map<String, String[]> multivaluedMap) { Map<String, String> map = new HashMap<String, String>(); for (Entry<String, String[]> entry : multivaluedMap.entrySet()) { if (entry.getValue().length > 0) { map.put(entry.getKey(), entry.getValue()[0]); } } return map; } public static Map<String, String> getFirstValues2(Map<String, List<String>> multivaluedMap) { Map<String, String> map = new HashMap<String, String>(); for (Entry<String, List<String>> entry : multivaluedMap.entrySet()) { if (!entry.getValue().isEmpty()) { map.put(entry.getKey(), entry.getValue().get(0)); } } return map; } /** * Appends an error to a JSON object (in the "result" item) * @param json * @param msg * @throws JSONException */ private void appendError(String msg) { try { String formattedMsg = ERROR+msg; Object existingResult; existingResult = result.get("result"); if (existingResult.equals("ok")) { result.put("result", formattedMsg); } else { result.accumulate("result", formattedMsg); } } catch (JSONException e) { log.error("Failed to append error '"+msg+"' in response", e); } } private Map<String, String> getCommonPropertiesDocumentation(String doctype) throws JSONException { if (commonPropertiesDocumentation == null) { commonPropertiesDocumentation = new HashMap<String, String>(); Map<String, String> dcPropertyList = EasySOADoctype.getDublinCorePropertyList(); for (Entry<String, String> entry : dcPropertyList.entrySet()) { commonPropertiesDocumentation.put(entry.getKey(), entry.getValue()); } Map<String, String> commonPropertyList = EasySOADoctype.getCommonPropertyList(doctype); for (Entry<String, String> entry : commonPropertyList.entrySet()) { commonPropertiesDocumentation.put(entry.getKey(), entry.getValue()); } } return commonPropertiesDocumentation; } /** * Formats the JSONObject into a string * @param result * @return */ private String getFormattedResult() { try { return result.toString(2); } catch (JSONException e) { return "{ result: \""+ERROR+"Could not format results to JSON.\"}"; } } private String getFormattedResult(String callback) { String result = getFormattedResult(); if (callback != null) { result = callback + '(' + result + ')'; } return result; } }