mirror of
https://gitee.com/jmix/cuba.git
synced 2024-12-03 03:38:33 +08:00
Generic service invocation API #PL-3952
This commit is contained in:
parent
19abddf16a
commit
c26be59981
@ -10,6 +10,7 @@ import com.haulmont.cuba.core.entity.Entity;
|
||||
import com.haulmont.cuba.core.global.View;
|
||||
|
||||
import javax.activation.MimeType;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -33,6 +34,9 @@ public interface Convertor {
|
||||
Object process(Set<Entity> entities, String requestURI)
|
||||
throws InvocationTargetException, NoSuchMethodException, IllegalAccessException;
|
||||
|
||||
Object processServiceMethodResult(Object result, String requestURI, @Nullable String viewName)
|
||||
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException;
|
||||
|
||||
CommitRequest parseCommitRequest(String content);
|
||||
|
||||
void write(HttpServletResponse response, Object o) throws IOException;
|
||||
|
@ -11,7 +11,6 @@ import com.haulmont.chile.core.datatypes.impl.*;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.cuba.core.app.DataService;
|
||||
import com.haulmont.cuba.core.app.DomainDescriptionService;
|
||||
import com.haulmont.cuba.core.entity.BaseGenericIdEntity;
|
||||
import com.haulmont.cuba.core.entity.Entity;
|
||||
import com.haulmont.cuba.core.global.*;
|
||||
import com.haulmont.cuba.core.sys.AbstractViewRepository;
|
||||
@ -22,15 +21,18 @@ import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.activation.MimeType;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.ParseException;
|
||||
import java.util.*;
|
||||
|
||||
@ -67,6 +69,9 @@ public class DataServiceController {
|
||||
@Inject
|
||||
protected Authentication authentication;
|
||||
|
||||
@Inject
|
||||
protected RestServicePermissions restServicePermissions;
|
||||
|
||||
@RequestMapping(value = "/api/find.{type}", method = RequestMethod.GET)
|
||||
public void find(@PathVariable String type,
|
||||
@RequestParam(value = "e") String entityRef,
|
||||
@ -306,6 +311,115 @@ public class DataServiceController {
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/api/service.{type}", method = RequestMethod.GET)
|
||||
public void serviceByGet(@PathVariable(value = "type") String type,
|
||||
@RequestParam(value = "s") String sessionId,
|
||||
@RequestParam(value = "service") String serviceName,
|
||||
@RequestParam(value = "method") String methodName,
|
||||
@RequestParam(value = "view", required = false) String view,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
if (!authentication.begin(sessionId)) {
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
return;
|
||||
}
|
||||
if (!restServicePermissions.isPermitted(serviceName, methodName)) {
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
List<String> paramValuesString = new ArrayList<>();
|
||||
List<Class<?>> paramTypes = new ArrayList<>();
|
||||
|
||||
int idx = 0;
|
||||
while (true) {
|
||||
String[] _values = parameterMap.get("param" + idx);
|
||||
if (_values == null) break;
|
||||
if (_values.length > 1) {
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Multiple values for param" + idx);
|
||||
return;
|
||||
}
|
||||
paramValuesString.add(_values[0]);
|
||||
|
||||
String[] _types = parameterMap.get("param" + idx + "_type");
|
||||
if (_types != null) {
|
||||
if (_types.length > 1) {
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Multiple values for param" + idx + "_type");
|
||||
return;
|
||||
}
|
||||
paramTypes.add(idx, ClassUtils.forName(_types[0], null));
|
||||
} else if (!paramTypes.isEmpty()) {
|
||||
//types should be defined for all parameters or for none of them
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Parameter type for param" + idx +" is not defined");
|
||||
return;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
Object service = AppBeans.get(serviceName);
|
||||
Method serviceMethod;
|
||||
if (paramTypes.isEmpty()) {
|
||||
//trying to guess which method to invoke
|
||||
Method[] methods = service.getClass().getMethods();
|
||||
List<Method> appropriateMethods = new ArrayList<>();
|
||||
for (Method method : methods) {
|
||||
if (methodName.equals(method.getName()) && method.getParameterTypes().length == paramValuesString.size()) {
|
||||
appropriateMethods.add(method);
|
||||
}
|
||||
}
|
||||
if (appropriateMethods.size() == 1) {
|
||||
serviceMethod = appropriateMethods.get(0);
|
||||
} else if (appropriateMethods.size() > 1) {
|
||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "There are multiple methods with given argument numbers. Please define parameter types in request");
|
||||
return;
|
||||
} else {
|
||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Method not found");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
serviceMethod = service.getClass().getMethod(methodName, paramTypes.toArray(new Class[paramTypes.size()]));
|
||||
} catch (NoSuchMethodException e) {
|
||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Method not found");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
List<Object> paramValues = new ArrayList<>();
|
||||
Class<?>[] types = serviceMethod.getParameterTypes();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
Class<?> aClass = types[i];
|
||||
paramValues.add(toObject(aClass, paramValuesString.get(i)));
|
||||
}
|
||||
|
||||
Object result = serviceMethod.invoke(service, paramValues.toArray());
|
||||
|
||||
Convertor convertor = conversionFactory.getConvertor(type);
|
||||
Object converted = convertor.processServiceMethodResult(result, request.getRequestURI(), view);
|
||||
convertor.write(response, converted);
|
||||
} catch (Throwable e) {
|
||||
sendError(request, response, e);
|
||||
} finally {
|
||||
authentication.end();
|
||||
}
|
||||
}
|
||||
|
||||
private Object toObject(Class clazz, String value) {
|
||||
if (Boolean.class == clazz || Boolean.TYPE == clazz) return Boolean.parseBoolean(value);
|
||||
if (Byte.class == clazz || Byte.TYPE == clazz) return Byte.parseByte(value);
|
||||
if (Short.class == clazz || Short.TYPE == clazz) return Short.parseShort(value);
|
||||
if (Integer.class == clazz || Integer.TYPE == clazz) return Integer.parseInt(value);
|
||||
if (Long.class == clazz || Long.TYPE == clazz) return Long.parseLong(value);
|
||||
if (Float.class == clazz || Float.TYPE == clazz) return Float.parseFloat(value);
|
||||
if (Double.class == clazz || Double.TYPE == clazz) return Double.parseDouble(value);
|
||||
if (UUID.class == clazz) return UUID.fromString(value);
|
||||
if (String.class == clazz) return value;
|
||||
throw new IllegalArgumentException("Parameters of type " + clazz.getName() + " are not supported");
|
||||
}
|
||||
|
||||
private void sendError(HttpServletRequest request, HttpServletResponse response, Throwable e) throws IOException {
|
||||
log.error("Error processing request: " + request.getRequestURI() + "?" + request.getQueryString(), e);
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
package com.haulmont.cuba.portal.restapi;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.haulmont.chile.core.datatypes.impl.StringDatatype;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.chile.core.model.MetaProperty;
|
||||
@ -36,6 +37,8 @@ import org.json.JSONObject;
|
||||
|
||||
import javax.activation.MimeType;
|
||||
import javax.activation.MimeTypeParseException;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Id;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.PropertyDescriptor;
|
||||
@ -116,6 +119,48 @@ public class JSONConvertor implements Convertor {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object processServiceMethodResult(Object result, String requestURI, @Nullable String viewName)
|
||||
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
MyJSONObject root = new MyJSONObject();
|
||||
if (result instanceof Entity) {
|
||||
Entity entity = (Entity) result;
|
||||
ViewRepository viewRepository = AppBeans.get(ViewRepository.class);
|
||||
if (Strings.isNullOrEmpty(viewName)) viewName = View.LOCAL;
|
||||
View view = viewRepository.getView(entity.getMetaClass(), viewName);
|
||||
MyJSONObject entityObject = process(entity, entity.getMetaClass(), "", view);
|
||||
root.set("result", entityObject);
|
||||
} else if (result instanceof Collection) {
|
||||
if (!checkCollectionItemTypes((Collection) result, Entity.class))
|
||||
throw new IllegalArgumentException("Items that are not instances of Entity found in service method result");
|
||||
ArrayList list = new ArrayList((Collection) result);
|
||||
MetaClass metaClass;
|
||||
if (!list.isEmpty())
|
||||
metaClass = ((Entity) list.get(0)).getMetaClass();
|
||||
else
|
||||
metaClass = AppBeans.get(Metadata.class).getClasses().iterator().next();
|
||||
ViewRepository viewRepository = AppBeans.get(ViewRepository.class);
|
||||
if (Strings.isNullOrEmpty(viewName)) viewName = View.LOCAL;
|
||||
View view = viewRepository.getView(metaClass, viewName);
|
||||
MyJSONObject.Array processed = process(list, metaClass, requestURI, view);
|
||||
root.set("result", processed);
|
||||
} else {
|
||||
root.set("result", result);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all collection items are instances of given class
|
||||
*/
|
||||
protected boolean checkCollectionItemTypes(Collection collection, Class<?> itemClass) {
|
||||
for (Object collectionItem : collection) {
|
||||
if (!itemClass.isAssignableFrom(collectionItem.getClass()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private MetaClass getMetaClass(Entity entity) {
|
||||
return metadata.getSession().getClassNN(entity.getClass());
|
||||
}
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
package com.haulmont.cuba.portal.restapi;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.*;
|
||||
|
||||
@ -33,8 +35,12 @@ public class MyJSONObject implements MyJSON {
|
||||
private final boolean _ref;
|
||||
private final Map<String, Object> _values;
|
||||
|
||||
public MyJSONObject() {
|
||||
this(null, false);
|
||||
}
|
||||
|
||||
public MyJSONObject(Object id, boolean ref) {
|
||||
_id = id.toString();
|
||||
_id = id != null ? id.toString() : null;
|
||||
_ref = ref;
|
||||
_values = new LinkedHashMap<String, Object>();
|
||||
}
|
||||
@ -52,14 +58,19 @@ public class MyJSONObject implements MyJSON {
|
||||
|
||||
public StringBuilder asString(int indent) {
|
||||
StringBuilder buf = new StringBuilder().append(OBJECT_START);
|
||||
buf.append(encodeField(_ref ? REF_MARKER : ID_MARKER, ior(), 0));
|
||||
if (!Strings.isNullOrEmpty(_id)) {
|
||||
buf.append(encodeField(_ref ? REF_MARKER : ID_MARKER, ior(), 0));
|
||||
buf.append(FIELD_SEPARATOR).append(NEWLINE);
|
||||
}
|
||||
if (_ref) {
|
||||
return buf.append(OBJECT_END);
|
||||
}
|
||||
StringBuilder tab = newIndent(indent+1);
|
||||
int i = 0;
|
||||
for (Map.Entry<String, Object> e : _values.entrySet()) {
|
||||
buf.append(FIELD_SEPARATOR).append(NEWLINE);
|
||||
buf.append(tab).append(encodeField(e.getKey(), e.getValue(), indent+1));
|
||||
if (i++ < _values.entrySet().size() - 1)
|
||||
buf.append(FIELD_SEPARATOR).append(NEWLINE);
|
||||
}
|
||||
buf.append(NEWLINE)
|
||||
.append(newIndent(indent))
|
||||
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2015 Haulmont. All rights reserved.
|
||||
* Use is subject to license terms, see http://www.cuba-platform.com/license for details.
|
||||
*/
|
||||
|
||||
package com.haulmont.cuba.portal.restapi;
|
||||
|
||||
import com.haulmont.bali.util.Dom4j;
|
||||
import com.haulmont.cuba.core.global.Resources;
|
||||
import com.haulmont.cuba.core.sys.AppContext;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.text.StrTokenizer;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import javax.annotation.ManagedBean;
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* Class holds an information about services that allowed to be invoked with REST API.
|
||||
* Configuration is loaded from {@code *-rest-services.xml} files.
|
||||
*
|
||||
* @author gorbunkov
|
||||
* @version $Id$
|
||||
*/
|
||||
@ManagedBean(RestServicePermissions.NAME)
|
||||
public class RestServicePermissions {
|
||||
|
||||
public static final String NAME = "cuba_RestServicePermissions";
|
||||
|
||||
public static final String CUBA_REST_SERVICES_CONFIG_PROP_NAME = "cuba.restServicesConfig";
|
||||
|
||||
@Inject
|
||||
protected Resources resources;
|
||||
|
||||
protected static Log log = LogFactory.getLog(RestServicePermissions.class);
|
||||
|
||||
protected Map<String, Set<String>> serviceMethods = new ConcurrentHashMap<>();
|
||||
|
||||
protected volatile boolean initialized;
|
||||
|
||||
protected ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
/**
|
||||
* Checks whether method of service is allowed to be invoked with REST API
|
||||
*/
|
||||
public boolean isPermitted(String serviceName, String methodName) {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
checkInitialized();
|
||||
Set<String> methods = serviceMethods.get(serviceName);
|
||||
return methods != null && methods.contains(methodName);
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkInitialized() {
|
||||
if (!initialized) {
|
||||
lock.readLock().unlock();
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (!initialized) {
|
||||
init();
|
||||
initialized = true;
|
||||
}
|
||||
} finally {
|
||||
lock.readLock().lock();
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
String configName = AppContext.getProperty(CUBA_REST_SERVICES_CONFIG_PROP_NAME);
|
||||
StrTokenizer tokenizer = new StrTokenizer(configName);
|
||||
for (String location : tokenizer.getTokenArray()) {
|
||||
Resource resource = resources.getResource(location);
|
||||
if (resource.exists()) {
|
||||
InputStream stream = null;
|
||||
try {
|
||||
stream = resource.getInputStream();
|
||||
loadConfig(Dom4j.readDocument(stream).getRootElement());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(stream);
|
||||
}
|
||||
} else {
|
||||
log.warn("Resource " + location + " not found, ignore it");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadConfig(Element rootElem) {
|
||||
for (Element serviceElem : Dom4j.elements(rootElem, "service")) {
|
||||
String serviceName = serviceElem.attributeValue("name");
|
||||
|
||||
for (Element methodElem : Dom4j.elements(serviceElem, "method")) {
|
||||
String methodName = methodElem.attributeValue("name");
|
||||
addServiceMethod(serviceName, methodName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void addServiceMethod(String serviceName, String methodName) {
|
||||
Set<String> methods = serviceMethods.get(serviceName);
|
||||
if (methods == null) {
|
||||
methods = new HashSet<>();
|
||||
serviceMethods.put(serviceName, methods);
|
||||
}
|
||||
methods.add(methodName);
|
||||
}
|
||||
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
|
||||
package com.haulmont.cuba.portal.restapi;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.haulmont.chile.core.datatypes.impl.StringDatatype;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.chile.core.model.MetaProperty;
|
||||
@ -40,6 +41,7 @@ import org.w3c.dom.ls.LSParserFilter;
|
||||
import org.w3c.dom.traversal.NodeFilter;
|
||||
|
||||
import javax.activation.MimeType;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
@ -69,6 +71,7 @@ public class XMLConvertor implements Convertor {
|
||||
public static final String MIME_STR = "text/xml;charset=UTF-8";
|
||||
|
||||
public static final String ELEMENT_INSTANCE = "instance";
|
||||
public static final String ELEMENT_RESULT = "result";
|
||||
public static final String ELEMENT_URI = "uri";
|
||||
public static final String ELEMENT_REF = "ref";
|
||||
public static final String ELEMENT_NULL_REF = "null";
|
||||
@ -159,6 +162,48 @@ public class XMLConvertor implements Convertor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object processServiceMethodResult(@Nullable Object result, String requestURI, String viewName)
|
||||
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
Element root = newDocument(ELEMENT_RESULT);
|
||||
if (result instanceof Entity) {
|
||||
Entity entity = (Entity) result;
|
||||
if (Strings.isNullOrEmpty(viewName)) viewName = View.LOCAL;
|
||||
ViewRepository viewRepository = AppBeans.get(ViewRepository.class);
|
||||
View view = viewRepository.getView(entity.getMetaClass(), viewName);
|
||||
Document convertedEntity = process(entity, entity.getMetaClass(), requestURI, view);
|
||||
Node importedNode = root.getOwnerDocument().importNode(convertedEntity.getDocumentElement(), true);
|
||||
root.appendChild(importedNode);
|
||||
} else if (result instanceof Collection) {
|
||||
if (!checkCollectionItemTypes((Collection) result, Entity.class))
|
||||
throw new IllegalArgumentException("Items that are not instances of Entity class found in service method result");
|
||||
ArrayList list = new ArrayList((Collection) result);
|
||||
MetaClass metaClass;
|
||||
if (!list.isEmpty())
|
||||
metaClass = ((Entity) list.get(0)).getMetaClass();
|
||||
else
|
||||
metaClass = AppBeans.get(Metadata.class).getClasses().iterator().next();
|
||||
|
||||
ViewRepository viewRepository = AppBeans.get(ViewRepository.class);
|
||||
if (Strings.isNullOrEmpty(viewName)) viewName = View.LOCAL;
|
||||
View view = viewRepository.getView(metaClass, viewName);
|
||||
Document processed = process(list, metaClass, requestURI, view);
|
||||
Node importedNode = root.getOwnerDocument().importNode(processed.getDocumentElement(), true);
|
||||
root.appendChild(importedNode);
|
||||
} else {
|
||||
root.setTextContent(result != null ? result.toString() : NULL_VALUE);
|
||||
}
|
||||
return root.getOwnerDocument();
|
||||
}
|
||||
|
||||
protected boolean checkCollectionItemTypes(Collection collection, Class<?> itemClass) {
|
||||
for (Object collectionItem : collection) {
|
||||
if (!itemClass.isAssignableFrom(collectionItem.getClass()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(HttpServletResponse response, Object o) throws IOException {
|
||||
Document doc = (Document) o;
|
||||
@ -421,14 +466,14 @@ public class XMLConvertor implements Convertor {
|
||||
Document doc = builder.newDocument();
|
||||
Element root = doc.createElement(rootTag);
|
||||
doc.appendChild(root);
|
||||
String[] nvpairs = new String[]{
|
||||
"xmlns:xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI,
|
||||
// "xsi:noNamespaceSchemaLocation", INSTANCE_XSD,
|
||||
ATTR_VERSION, "1.0",
|
||||
};
|
||||
for (int i = 0; i < nvpairs.length; i += 2) {
|
||||
root.setAttribute(nvpairs[i], nvpairs[i + 1]);
|
||||
}
|
||||
// String[] nvpairs = new String[]{
|
||||
// "xmlns:xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI,
|
||||
//// "xsi:noNamespaceSchemaLocation", INSTANCE_XSD,
|
||||
// ATTR_VERSION, "1.0",
|
||||
// };
|
||||
// for (int i = 0; i < nvpairs.length; i += 2) {
|
||||
// root.setAttribute(nvpairs[i], nvpairs[i + 1]);
|
||||
// }
|
||||
return root;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2008-2015 Haulmont. All rights reserved.
|
||||
~ Use is subject to license terms, see http://www.cuba-platform.com/license for details.
|
||||
-->
|
||||
|
||||
<xs:schema
|
||||
targetNamespace="http://schemas.haulmont.com/cuba/5.3/rest-services.xsd"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.haulmont.com/cuba/5.3/rest-services.xsd"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified"
|
||||
>
|
||||
|
||||
<xs:element name="services" type="servicesType"/>
|
||||
|
||||
<xs:complexType name="servicesType">
|
||||
<xs:sequence>
|
||||
<xs:element name="service" type="serviceType" maxOccurs="unbounded" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="serviceType">
|
||||
<xs:sequence>
|
||||
<xs:element name="method" type="methodType" maxOccurs="unbounded" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="methodType">
|
||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
@ -41,6 +41,7 @@ cuba.dispatcherSpringContextConfig=cuba-portal-dispatcher-spring.xml
|
||||
cuba.viewsConfig=cuba-views.xml
|
||||
cuba.persistenceConfig=cuba-persistence.xml
|
||||
cuba.metadataConfig=cuba-metadata.xml
|
||||
cuba.restServicesConfig=cuba-rest-services.xml
|
||||
|
||||
cuba.mainMessagePack=com.haulmont.cuba.core
|
||||
|
||||
|
12
modules/portal/src/cuba-rest-services.xml
Normal file
12
modules/portal/src/cuba-rest-services.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2008-2015 Haulmont. All rights reserved.
|
||||
~ Use is subject to license terms, see http://www.cuba-platform.com/license for details.
|
||||
-->
|
||||
|
||||
<services xmlns="http://schemas.haulmont.com/cuba/5.3/rest-services.xsd">
|
||||
<!--<service name="cuba_SampleService">-->
|
||||
<!--<method name="doSmth"/>-->
|
||||
<!--<method name="doSmthElse"/>-->
|
||||
<!--</service>-->
|
||||
</services>
|
Loading…
Reference in New Issue
Block a user