Merged 5.2.N (5.2.1) to HEAD (5.2)

130165 gjames: Merged searchapi (5.2.1) to 5.2.N (5.2.1)
      129774 gjames: SEARCH-113: Moving more api logic to helper classes, using a "trait" style


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@130317 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2016-09-06 22:02:33 +00:00
parent a43d3a126f
commit c6dda1e7fa
26 changed files with 1521 additions and 1269 deletions

View File

@@ -37,6 +37,7 @@ import org.alfresco.rest.framework.core.exceptions.ApiException;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.jacksonextensions.JacksonHelper.Writer; import org.alfresco.rest.framework.jacksonextensions.JacksonHelper.Writer;
import org.alfresco.rest.framework.resource.parameters.Params; import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.tools.ResponseWriter;
import org.alfresco.rest.framework.webscripts.ApiWebScript; import org.alfresco.rest.framework.webscripts.ApiWebScript;
import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper; import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper;
import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonGenerationException;
@@ -48,7 +49,7 @@ import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse; import org.springframework.extensions.webscripts.WebScriptResponse;
public class NetworkWebScriptGet extends ApiWebScript public class NetworkWebScriptGet extends ApiWebScript implements ResponseWriter
{ {
private Networks networks; private Networks networks;
private ResourceWebScriptHelper helper; private ResourceWebScriptHelper helper;
@@ -108,11 +109,11 @@ public class NetworkWebScriptGet extends ApiWebScript
} }
catch (ApiException | WebScriptException apiException) catch (ApiException | WebScriptException apiException)
{ {
assistant.renderException(apiException, res); renderException(apiException, res, assistant);
} }
catch (RuntimeException runtimeException) catch (RuntimeException runtimeException)
{ {
assistant.renderException(runtimeException, res); renderException(runtimeException, res, assistant);
} }
} }
} }

View File

@@ -39,6 +39,8 @@ import org.alfresco.rest.framework.jacksonextensions.JacksonHelper.Writer;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging; import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Params; import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.alfresco.rest.framework.tools.ResponseWriter;
import org.alfresco.rest.framework.webscripts.ApiWebScript; import org.alfresco.rest.framework.webscripts.ApiWebScript;
import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper; import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper;
import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonGenerationException;
@@ -56,7 +58,7 @@ import org.springframework.extensions.webscripts.WebScriptResponse;
* @author steveglover * @author steveglover
* *
*/ */
public class NetworksWebScriptGet extends ApiWebScript public class NetworksWebScriptGet extends ApiWebScript implements RecognizedParamsExtractor, ResponseWriter
{ {
private Networks networks; private Networks networks;
private ResourceWebScriptHelper helper; private ResourceWebScriptHelper helper;
@@ -82,7 +84,7 @@ public class NetworksWebScriptGet extends ApiWebScript
@Override @Override
public Void execute() throws Throwable public Void execute() throws Throwable
{ {
final Paging paging = ResourceWebScriptHelper.findPaging(req); final Paging paging = findPaging(req);
// apply content type // apply content type
res.setContentType(Format.JSON.mimetype() + ";charset=UTF-8"); res.setContentType(Format.JSON.mimetype() + ";charset=UTF-8");
@@ -116,11 +118,11 @@ public class NetworksWebScriptGet extends ApiWebScript
} }
catch (ApiException | WebScriptException apiException) catch (ApiException | WebScriptException apiException)
{ {
assistant.renderException(apiException, res); renderException(apiException, res, assistant);
} }
catch (RuntimeException runtimeException) catch (RuntimeException runtimeException)
{ {
assistant.renderException(runtimeException, res); renderException(runtimeException, res, assistant);
} }
} }
} }

View File

@@ -33,12 +33,13 @@ import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.web.scripts.TenantWebScriptServletRuntime; import org.alfresco.repo.web.scripts.TenantWebScriptServletRuntime;
import org.alfresco.rest.framework.tools.ApiAssistant; import org.alfresco.rest.framework.tools.ApiAssistant;
import org.alfresco.rest.framework.tools.ResponseWriter;
import org.springframework.extensions.config.ServerProperties; import org.springframework.extensions.config.ServerProperties;
import org.springframework.extensions.surf.util.URLDecoder; import org.springframework.extensions.surf.util.URLDecoder;
import org.springframework.extensions.webscripts.*; import org.springframework.extensions.webscripts.*;
import org.springframework.extensions.webscripts.servlet.ServletAuthenticatorFactory; import org.springframework.extensions.webscripts.servlet.ServletAuthenticatorFactory;
public class PublicApiTenantWebScriptServletRuntime extends TenantWebScriptServletRuntime public class PublicApiTenantWebScriptServletRuntime extends TenantWebScriptServletRuntime implements ResponseWriter
{ {
private static final Pattern CMIS_URI_PATTERN = Pattern.compile(".*/cmis/versions/[0-9]+\\.[0-9]+/.*"); private static final Pattern CMIS_URI_PATTERN = Pattern.compile(".*/cmis/versions/[0-9]+\\.[0-9]+/.*");
private ApiAssistant apiAssistant; private ApiAssistant apiAssistant;
@@ -142,7 +143,7 @@ public class PublicApiTenantWebScriptServletRuntime extends TenantWebScriptServl
else else
{ {
try { try {
apiAssistant.renderException((Exception)exception, response); renderException((Exception)exception, response, apiAssistant);
} catch (IOException e) { } catch (IOException e) {
logger.error("Internal error", e); logger.error("Internal error", e);
throw new WebScriptException("Internal error", e); throw new WebScriptException("Internal error", e);

View File

@@ -32,6 +32,7 @@ import org.alfresco.rest.api.model.Person;
import org.alfresco.rest.api.model.Site; import org.alfresco.rest.api.model.Site;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper; import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper;
/** /**
@@ -44,9 +45,9 @@ public interface Queries
{ {
// General // General
static String PARAM_TERM = "term"; static String PARAM_TERM = "term";
static String PARAM_ORDERBY = ResourceWebScriptHelper.PARAM_ORDERBY; static String PARAM_ORDERBY = RecognizedParamsExtractor.PARAM_ORDERBY;
static String PARAM_FIELDS = ResourceWebScriptHelper.PARAM_FILTER_FIELDS; static String PARAM_FIELDS = RecognizedParamsExtractor.PARAM_FILTER_FIELDS;
static String PARAM_INCLUDE = ResourceWebScriptHelper.PARAM_INCLUDE; static String PARAM_INCLUDE = RecognizedParamsExtractor.PARAM_INCLUDE;
// Node query // Node query
static String PARAM_ROOT_NODE_ID = "rootNodeId"; static String PARAM_ROOT_NODE_ID = "rootNodeId";

View File

@@ -57,7 +57,7 @@ import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.framework.resource.parameters.Params; import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.resource.parameters.where.Query; import org.alfresco.rest.framework.resource.parameters.where.Query;
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper; import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper; import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalker; import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalker;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
@@ -107,7 +107,7 @@ import java.util.Set;
* *
* @since publicapi1.0 * @since publicapi1.0
*/ */
public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean public class QuickShareLinksImpl implements QuickShareLinks, RecognizedParamsExtractor, InitializingBean
{ {
private static final Log logger = LogFactory.getLog(QuickShareLinksImpl.class); private static final Log logger = LogFactory.getLog(QuickShareLinksImpl.class);
@@ -404,7 +404,7 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
// hmm ... can we simplify ? // hmm ... can we simplify ?
String filterStatusCreated = "(" + Renditions.PARAM_STATUS + "='" + Rendition.RenditionStatus.CREATED + "')"; String filterStatusCreated = "(" + Renditions.PARAM_STATUS + "='" + Rendition.RenditionStatus.CREATED + "')";
Query whereQuery = ResourceWebScriptHelper.getWhereClause(filterStatusCreated); Query whereQuery = getWhereClause(filterStatusCreated);
Params.RecognizedParams recParams = new Params.RecognizedParams(null, null, null, null, null, null, whereQuery, null, false); Params.RecognizedParams recParams = new Params.RecognizedParams(null, null, null, null, null, null, whereQuery, null, false);
Parameters params = Params.valueOf(recParams, null, null, null); Parameters params = Params.valueOf(recParams, null, null, null);

View File

@@ -29,6 +29,7 @@ import java.io.IOException;
import org.alfresco.rest.framework.resource.SerializablePagedCollection; import org.alfresco.rest.framework.resource.SerializablePagedCollection;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper; import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper;
import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonGenerator;
@@ -90,8 +91,8 @@ public class SerializerOfCollectionWithPaging extends SerializerBase<Serializabl
} }
if (pagedCol.getPaging() != null) if (pagedCol.getPaging() != null)
{ {
jgen.writeNumberField(ResourceWebScriptHelper.PARAM_PAGING_SKIP, pagedCol.getPaging().getSkipCount()); jgen.writeNumberField(RecognizedParamsExtractor.PARAM_PAGING_SKIP, pagedCol.getPaging().getSkipCount());
jgen.writeNumberField(ResourceWebScriptHelper.PARAM_PAGING_MAX, pagedCol.getPaging().getMaxItems()); jgen.writeNumberField(RecognizedParamsExtractor.PARAM_PAGING_MAX, pagedCol.getPaging().getMaxItems());
} }
jgen.writeEndObject(); jgen.writeEndObject();
} }

View File

@@ -56,34 +56,16 @@ public class ApiAssistant {
private static Log logger = LogFactory.getLog(ApiAssistant.class); private static Log logger = LogFactory.getLog(ApiAssistant.class);
public final static String UTF8 = "UTF-8";
public final static ContentInfo DEFAULT_JSON_CONTENT = new ContentInfoImpl(Format.JSON.mimetype(),UTF8, 0, null);
public final static Cache CACHE_NEVER = new Cache(new RequiredCache()
{
@Override
public boolean getNeverCache()
{
return true;
}
@Override
public boolean getIsPublic()
{
return false;
}
@Override
public boolean getMustRevalidate()
{
return true;
}
});
private ExceptionResolver<Exception> defaultResolver = new DefaultExceptionResolver(); private ExceptionResolver<Exception> defaultResolver = new DefaultExceptionResolver();
private ExceptionResolver<WebScriptException> webScriptExceptionResolver; private ExceptionResolver<WebScriptException> webScriptExceptionResolver;
private ExceptionResolver<Exception> resolver; private ExceptionResolver<Exception> resolver;
private JacksonHelper jsonHelper; private JacksonHelper jsonHelper;
/**
* Determines the api being used from the templateVars
* @param templateVars
* @return Api
*/
public static Api determineApi(Map<String, String> templateVars) public static Api determineApi(Map<String, String> templateVars)
{ {
String apiScope = templateVars.get("apiScope"); String apiScope = templateVars.get("apiScope");
@@ -92,6 +74,11 @@ public class ApiAssistant {
return Api.valueOf(apiName,apiScope,apiVersion); return Api.valueOf(apiName,apiScope,apiVersion);
} }
/**
* Resolves an exception as a json error.
* @param exception
* @return ErrorResponse
*/
public ErrorResponse resolveException(Exception ex) public ErrorResponse resolveException(Exception ex)
{ {
ErrorResponse error = null; ErrorResponse error = null;
@@ -110,99 +97,6 @@ public class ApiAssistant {
return error; return error;
} }
/**
* Sets the response headers with any information we know about the content
* @param res WebScriptResponse
* @param contentInfo Content Information
*/
public void setContentInfoOnResponse(WebScriptResponse res, ContentInfo contentInfo)
{
if (contentInfo != null)
{
//Set content info on the response
res.setContentType(contentInfo.getMimeType());
res.setContentEncoding(contentInfo.getEncoding());
if (res instanceof WrappingWebScriptResponse)
{
WrappingWebScriptResponse wrappedRes = ((WrappingWebScriptResponse) res);
res = wrappedRes.getNext();
}
if (res instanceof WebScriptServletResponse)
{
WebScriptServletResponse servletResponse = (WebScriptServletResponse) res;
if (contentInfo.getLength() > 0)
{
if (contentInfo.getLength() > 0 && contentInfo.getLength() < Integer.MAX_VALUE)
{
servletResponse.getHttpServletResponse().setContentLength((int) contentInfo.getLength());
}
}
if (contentInfo.getLocale() != null)
{
servletResponse.getHttpServletResponse().setLocale(contentInfo.getLocale());
}
}
}
}
/**
* Renders an exception to the output stream as Json.
* @param exception
* @param response
* @throws IOException
*/
public void renderException(Exception exception, final WebScriptResponse response) throws IOException {
renderErrorResponse(resolveException(exception), response);
}
/**
* Renders a JSON error response
* @param errorResponse The error
* @param res web script response
* @throws IOException
*/
public void renderErrorResponse(ErrorResponse errorResponse, final WebScriptResponse res) throws IOException {
String logId = "";
if (Status.STATUS_INTERNAL_SERVER_ERROR == errorResponse.getStatusCode() || logger.isDebugEnabled())
{
logId = org.alfresco.util.GUID.generate();
logger.error(logId+" : "+errorResponse.getStackTrace());
}
String stackMessage = I18NUtil.getMessage(DefaultExceptionResolver.STACK_MESSAGE_ID);
final ErrorResponse errorToWrite = new ErrorResponse(errorResponse.getErrorKey(),
errorResponse.getStatusCode(),
errorResponse.getBriefSummary(),
stackMessage,
logId,
errorResponse.getAdditionalState(),
DefaultExceptionResolver.ERROR_URL);
setContentInfoOnResponse(res, DEFAULT_JSON_CONTENT);
// Status must be set before the response is written by Jackson (which will by default close and commit the response).
// In a r/w txn, web script buffered responses ensure that it doesn't really matter but for r/o txns this is important.
res.setStatus(errorToWrite.getStatusCode());
jsonHelper.withWriter(res.getOutputStream(), new JacksonHelper.Writer()
{
@SuppressWarnings("unchecked")
@Override
public void writeContents(JsonGenerator generator, ObjectMapper objectMapper)
throws JsonGenerationException, JsonMappingException, IOException
{
JSONObject obj = new JSONObject();
obj.put("error", errorToWrite);
objectMapper.writeValue(generator, obj);
}
});
}
public JacksonHelper getJsonHelper() { public JacksonHelper getJsonHelper() {
return jsonHelper; return jsonHelper;
} }

View File

@@ -0,0 +1,451 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.framework.tools;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.jacksonextensions.BeanPropertiesFilter;
import org.alfresco.rest.framework.resource.parameters.InvalidSelectException;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.resource.parameters.SortColumn;
import org.alfresco.rest.framework.resource.parameters.where.InvalidQueryException;
import org.alfresco.rest.framework.resource.parameters.where.Query;
import org.alfresco.rest.framework.resource.parameters.where.QueryImpl;
import org.alfresco.rest.framework.resource.parameters.where.WhereCompiler;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonErrorNode;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.RewriteCardinalityException;
import org.antlr.runtime.tree.Tree;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.WebScriptRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
/*
* Extracts recognized parameters from the HTTP request.
*
* @author Gethin James
*/
public interface RecognizedParamsExtractor
{
public static final String PARAM_RELATIONS = "relations";
public static final String PARAM_FILTER_FIELDS = "fields";
@Deprecated
public static final String PARAM_FILTER_PROPERTIES = "properties";
public static final String PARAM_PAGING_SKIP = "skipCount";
public static final String PARAM_PAGING_MAX = "maxItems";
public static final String PARAM_ORDERBY = "orderBy";
public static final String PARAM_WHERE = "where";
public static final String PARAM_SELECT = "select";
public static final String PARAM_INCLUDE = "include";
public static final String PARAM_INCLUDE_SOURCE_ENTITY = "includeSource";
public static final List<String> KNOWN_PARAMS = Arrays.asList(
PARAM_RELATIONS, PARAM_FILTER_PROPERTIES, PARAM_FILTER_FIELDS,PARAM_PAGING_SKIP,PARAM_PAGING_MAX,
PARAM_ORDERBY, PARAM_WHERE, PARAM_SELECT, PARAM_INCLUDE_SOURCE_ENTITY);
default Log rpeLogger() {
return LogFactory.getLog(this.getClass());
}
/**
* Finds the formal set of params that any rest service could potentially have passed in as request params
* @param req WebScriptRequest
* @return RecognizedParams a POJO containing the params for use with the Params objects
*/
default Params.RecognizedParams getRecognizedParams(WebScriptRequest req)
{
Paging paging = findPaging(req);
List<SortColumn> sorting = getSort(req.getParameter(PARAM_ORDERBY));
Map<String, BeanPropertiesFilter> relationFilter = getRelationFilter(req.getParameter(PARAM_RELATIONS));
Query whereQuery = getWhereClause(req.getParameter(PARAM_WHERE));
Map<String, String[]> requestParams = getRequestParameters(req);
boolean includeSource = Boolean.valueOf(req.getParameter(PARAM_INCLUDE_SOURCE_ENTITY));
List<String> includedFields = getIncludeClause(req.getParameter(PARAM_INCLUDE));
List<String> selectFields = getSelectClause(req.getParameter(PARAM_SELECT));
String fields = req.getParameter(PARAM_FILTER_FIELDS);
String properties = req.getParameter(PARAM_FILTER_PROPERTIES);
if ((fields != null) && (properties != null))
{
if (rpeLogger().isWarnEnabled())
{
rpeLogger().warn("Taking 'fields' param [" + fields + "] and ignoring deprecated 'properties' param [" + properties + "]");
}
}
BeanPropertiesFilter filter = getFilter((fields != null ? fields : properties), includedFields);
return new Params.RecognizedParams(requestParams, paging, filter, relationFilter, includedFields, selectFields, whereQuery, sorting, includeSource);
}
/**
* Takes the web request and looks for a "fields" parameter (otherwise deprecated "properties" parameter).
*
* Parses the parameter and produces a list of bean properties to use as a filter A
* SimpleBeanPropertyFilter it returned that uses the bean properties. If no
* filter param is set then a default BeanFilter is returned that will never
* filter fields (ie. Returns all bean properties).
*
* If selectList is provided then it will take precedence (ie. be included) over the fields/properties filter
* for top-level entries (bean properties).
*
* For example, this will return entries from both select & properties, eg.
*
* select=abc,def&properties=id,name,ghi
*
* Note: it should be noted that API-generic "fields" clause does not currently work for sub-entries.
*
* Hence, even if the API-specific "select" clause allows selection of a sub-entries this cannot be used
* with "fields" filtering. For example, an API-specific method may implement and return "abc/blah", eg.
*
* select=abc/blah
*
* However the following will not return "abc/blah" if used with fields filtering, eg.
*
* select=abc/blah&fields=id,name,ghi
*
* If fields filtering is desired then it would require "abc" to be selected and returned as a whole, eg.
*
* select=abc&fields=id,name,ghi
*
* @param filterParams
* @param selectList
* @return
*/
default BeanPropertiesFilter getFilter(String filterParams, List<String> selectList)
{
if (filterParams != null)
{
StringTokenizer st = new StringTokenizer(filterParams, ",");
Set<String> filteredProperties = new HashSet<String>(st.countTokens());
while (st.hasMoreTokens())
{
filteredProperties.add(st.nextToken());
}
// if supplied, the select takes precedence over the filter (fields/properties) for top-level bean properties
if (selectList != null)
{
for (String select : selectList)
{
String[] split = select.split("/");
filteredProperties.add(split[0]);
}
}
rpeLogger().debug("Filtering using the following properties: " + filteredProperties);
BeanPropertiesFilter filter = new BeanPropertiesFilter(filteredProperties);
return filter;
}
return BeanPropertiesFilter.ALLOW_ALL;
}
/**
* Takes the "select" parameter and turns it into a List<String> property names
* @param selectParam String
* @return bean property names potentially using JSON Pointer syntax
*/
@SuppressWarnings("unchecked")
@Deprecated
default List<String> getSelectClause(String selectParam) throws InvalidArgumentException
{
return getClause(selectParam, "SELECT");
}
/**
* Takes the "include" parameter and turns it into a List<String> property names
* @param includeParam String
* @return bean property names potentially using JSON Pointer syntax
*/
@SuppressWarnings("unchecked")
default List<String> getIncludeClause(String includeParam) throws InvalidArgumentException
{
return getClause(includeParam, "INCLUDE");
}
/**
* Gets the clause specificed in paramName
* @param param
* @param paramName
* @return bean property names potentially using JSON Pointer syntax
*/
default List<String> getClause(String param, String paramName)
{
if (param == null) return Collections.emptyList();
try {
CommonTree selectedPropsTree = WhereCompiler.compileSelectClause(param);
if (selectedPropsTree instanceof CommonErrorNode)
{
rpeLogger().debug("Error parsing the "+paramName+" clause "+selectedPropsTree);
throw new InvalidSelectException(paramName, selectedPropsTree);
}
if (selectedPropsTree.getChildCount() == 0 && !selectedPropsTree.getText().isEmpty())
{
return Arrays.asList(selectedPropsTree.getText());
}
List<Tree> children = (List<Tree>) selectedPropsTree.getChildren();
if (children!= null && !children.isEmpty())
{
List<String> properties = new ArrayList<String>(children.size());
for (Tree child : children) {
properties.add(child.getText());
}
return properties;
}
}
catch (RewriteCardinalityException re)
{
//Catch any error so it doesn't get thrown up the stack
rpeLogger().debug("Unhandled Error parsing the "+paramName+" clause: "+re);
}
catch (RecognitionException e)
{
rpeLogger().debug("Error parsing the \"+paramName+\" clause: "+param);
}
catch (InvalidQueryException iqe)
{
throw new InvalidSelectException(paramName, iqe.getQueryParam());
}
//Default to throw out an invalid query
throw new InvalidSelectException(paramName, param);
}
/**
* Takes the "where" parameter and turns it into a Java Object that can be used for querying
* @param whereParam String
* @return Query a parsed version of the where clause, represented in Java
*/
default Query getWhereClause(String whereParam) throws InvalidQueryException
{
if (whereParam == null) return QueryImpl.EMPTY;
try {
CommonTree whereTree = WhereCompiler.compileWhereClause(whereParam);
if (whereTree instanceof CommonErrorNode)
{
rpeLogger().debug("Error parsing the WHERE clause "+whereTree);
throw new InvalidQueryException(whereTree);
}
return new QueryImpl(whereTree);
} catch (RewriteCardinalityException re) { //Catch any error so it doesn't get thrown up the stack
rpeLogger().info("Unhandled Error parsing the WHERE clause: "+re);
} catch (RecognitionException e) {
whereParam += ", "+WhereCompiler.resolveMessage(e);
rpeLogger().info("Error parsing the WHERE clause: "+whereParam);
}
//Default to throw out an invalid query
throw new InvalidQueryException(whereParam);
}
/**
* Takes the Sort parameter as a String and parses it into a List of SortColumn objects.
* The format is a comma seperated list of "columnName sortDirection",
* e.g. "name DESC, age ASC". It is not case sensitive and the sort direction is optional
* It default to sort ASCENDING.
* @param sortParams - String passed in on the request
* @return - the sort columns or an empty list if the params were invalid.
*/
default List<SortColumn> getSort(String sortParams)
{
if (sortParams != null)
{
StringTokenizer st = new StringTokenizer(sortParams, ",");
List<SortColumn> sortedColumns = new ArrayList<SortColumn>(st.countTokens());
while (st.hasMoreTokens())
{
String token = st.nextToken();
StringTokenizer columnDesc = new StringTokenizer(token, " ");
if (columnDesc.countTokens() <= 2)
{
String columnName = columnDesc.nextToken();
String sortOrder = SortColumn.ASCENDING;
if (columnDesc.hasMoreTokens())
{
String sortDef = columnDesc.nextToken().toUpperCase();
if (SortColumn.ASCENDING.equals(sortDef) || SortColumn.DESCENDING.equals(sortDef))
{
sortOrder = sortDef;
}
else
{
rpeLogger().debug("Invalid sort order definition ("+sortDef+"). Valid values are "+SortColumn.ASCENDING+" or "+SortColumn.DESCENDING+".");
}
}
sortedColumns.add(new SortColumn(columnName, SortColumn.ASCENDING.equals(sortOrder)));
}
// filteredProperties.add();
}
// logger.debug("Filtering using the following properties: " + filteredProperties);
// BeanPropertiesFilter filter = new BeanPropertiesFilter(filteredProperties);
return sortedColumns;
}
return Collections.emptyList();
}
/**
* Find paging setings based on the request parameters.
*
* @param req
* @return Paging
*/
default Paging findPaging(WebScriptRequest req)
{
int skipped = Paging.DEFAULT_SKIP_COUNT;
int max = Paging.DEFAULT_MAX_ITEMS;
String skip = req.getParameter(PARAM_PAGING_SKIP);
String maxItems = req.getParameter(PARAM_PAGING_MAX);
try
{
if (skip != null) { skipped = Integer.parseInt(skip);}
if (maxItems != null) { max = Integer.parseInt(maxItems); }
if (max < 0 || skipped < 0)
{
throw new InvalidArgumentException("Negative values not supported.");
}
}
catch (NumberFormatException error)
{
if (rpeLogger().isDebugEnabled())
{
rpeLogger().debug("Invalid paging params skip: " + skip + ",maxItems:" + maxItems);
}
throw new InvalidArgumentException();
}
return Paging.valueOf(skipped, max);
}
/**
* Takes the web request and looks for a "fields" parameter (otherwise deprecated "properties" parameter).
*
* Parses the parameter and produces a list of bean properties to use as a filter A
* SimpleBeanPropertyFilter it returned that uses the bean properties. If no
* filter param is set then a default BeanFilter is returned that will never
* filter fields (ie. Returns all bean properties).
*
* @param filterParams String
* @return BeanPropertyFilter - if no parameter then returns a new
* ReturnAllBeanProperties class
*/
default BeanPropertiesFilter getFilter(String filterParams)
{
return getFilter(filterParams, null);
}
/**
* Takes the web request and looks for a "relations" parameter Parses the
* parameter and produces a list of bean properties to use as a filter A
* SimpleBeanPropertiesFilter it returned that uses the properties If no
* filter param is set then a default BeanFilter is returned that will never
* filter properties (ie. Returns all bean properties).
*
* @param filterParams String
* @return BeanPropertiesFilter - if no parameter then returns a new
* ReturnAllBeanProperties class
*/
default Map<String, BeanPropertiesFilter> getRelationFilter(String filterParams)
{
if (filterParams != null)
{
// Split by a comma when not in a bracket
String[] relations = filterParams.split(",(?![^()]*+\\))");
Map<String, BeanPropertiesFilter> filterMap = new HashMap<String, BeanPropertiesFilter>(relations.length);
for (String relation : relations)
{
int bracketLocation = relation.indexOf("(");
if (bracketLocation != -1)
{
// We have properties
String relationKey = relation.substring(0, bracketLocation);
String props = relation.substring(bracketLocation + 1, relation.length() - 1);
filterMap.put(relationKey, getFilter(props));
}
else
{
// no properties so just get the String
filterMap.put(relation, getFilter(null));
}
}
return filterMap;
}
return Collections.emptyMap();
}
/**
* Finds all request parameters that aren't already know about (eg. not paging or filter params)
* and returns them for use.
*
* @param req - the WebScriptRequest object
* @return the request parameters
*/
default Map<String, String[]> getRequestParameters(WebScriptRequest req)
{
if (req!= null)
{
String[] paramNames = req.getParameterNames();
if (paramNames!= null)
{
Map<String, String[]> requestParameteters = new HashMap<String, String[]>(paramNames.length);
for (int i = 0; i < paramNames.length; i++)
{
String paramName = paramNames[i];
if (!KNOWN_PARAMS.contains(paramName))
{
String[] vals = req.getParameterValues(paramName);
requestParameteters.put(paramName, vals);
}
}
return requestParameteters;
}
}
return Collections.emptyMap();
}
}

View File

@@ -0,0 +1,103 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.framework.tools;
import org.alfresco.rest.framework.core.exceptions.ApiException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.jacksonextensions.JacksonHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.map.JsonMappingException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
/*
* Reads information from the request
*
* @author Gethin James
*/
public interface RequestReader
{
/**
* Extracts the body contents from the request
*
* @param req the request
* @param jsonHelper Jackson Helper
* @param requiredType the type to return
* @return the Object in the required type
*/
default <T> T extractJsonContent(WebScriptRequest req, JacksonHelper jsonHelper, Class<T> requiredType)
{
Reader reader;
try
{
reader = req.getContent().getReader();
return jsonHelper.construct(reader, requiredType);
}
catch (JsonMappingException e)
{
rrLogger().warn("Could not read content from HTTP request body.", e);
throw new InvalidArgumentException("Could not read content from HTTP request body.");
}
catch (IOException e)
{
throw new ApiException("Could not read content from HTTP request body.", e.getCause());
}
}
/**
* Extracts the body contents from the request as a List, the JSON can be an array or just a single value without the [] symbols
*
* @param req the request
* @param jsonHelper Jackson Helper
* @param requiredType the type to return (without the List param)
* @return A List of "Object" as the required type
*/
default <T> List<T> extractJsonContentAsList(WebScriptRequest req, JacksonHelper jsonHelper, Class<T> requiredType)
{
Reader reader;
try
{
reader = req.getContent().getReader();
return jsonHelper.constructList(reader, requiredType);
}
catch (IOException e)
{
throw new ApiException("Could not read content from HTTP request body.", e.getCause());
}
}
default Log rrLogger() {
return LogFactory.getLog(this.getClass());
}
}

View File

@@ -0,0 +1,258 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.framework.tools;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.core.exceptions.DefaultExceptionResolver;
import org.alfresco.rest.framework.core.exceptions.ErrorResponse;
import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationException;
import org.alfresco.rest.framework.jacksonextensions.BeanPropertiesFilter;
import org.alfresco.rest.framework.jacksonextensions.ExecutionResult;
import org.alfresco.rest.framework.jacksonextensions.JacksonHelper;
import org.alfresco.rest.framework.resource.SerializablePagedCollection;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.content.ContentInfo;
import org.alfresco.rest.framework.resource.content.ContentInfoImpl;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.webscripts.WithResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.json.simple.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.extensions.webscripts.*;
import org.springframework.extensions.webscripts.servlet.WebScriptServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/*
* Writes to the response
*
* @author Gethin James
*/
public interface ResponseWriter
{
String UTF8 = "UTF-8";
ContentInfo DEFAULT_JSON_CONTENT = new ContentInfoImpl(Format.JSON.mimetype(),UTF8, 0, null);
Cache CACHE_NEVER = new Cache(new Description.RequiredCache()
{
@Override
public boolean getNeverCache()
{
return true;
}
@Override
public boolean getIsPublic()
{
return false;
}
@Override
public boolean getMustRevalidate()
{
return true;
}
});
default Log resWriterLogger() {
return LogFactory.getLog(this.getClass());
}
/**
* Sets the response headers with any information we know about the content
* @param res WebScriptResponse
* @param contentInfo Content Information
*/
default void setContentInfoOnResponse(WebScriptResponse res, ContentInfo contentInfo)
{
if (contentInfo != null)
{
//Set content info on the response
res.setContentType(contentInfo.getMimeType());
res.setContentEncoding(contentInfo.getEncoding());
if (res instanceof WrappingWebScriptResponse)
{
WrappingWebScriptResponse wrappedRes = ((WrappingWebScriptResponse) res);
res = wrappedRes.getNext();
}
if (res instanceof WebScriptServletResponse)
{
WebScriptServletResponse servletResponse = (WebScriptServletResponse) res;
if (contentInfo.getLength() > 0)
{
if (contentInfo.getLength() > 0 && contentInfo.getLength() < Integer.MAX_VALUE)
{
servletResponse.getHttpServletResponse().setContentLength((int) contentInfo.getLength());
}
}
if (contentInfo.getLocale() != null)
{
servletResponse.getHttpServletResponse().setLocale(contentInfo.getLocale());
}
}
}
}
/**
* The response status must be set before the response is written by Jackson (which will by default close and commit the response).
* In a r/w txn, web script buffered responses ensure that it doesn't really matter but for r/o txns this is important.
*
* If you set content information via the contentInfo object and ALSO the headers then "headers" will win because they are
* set last.
*
* @param res
* @param status
* @param cache
* @param contentInfo
* @param headers
*/
default void setResponse(final WebScriptResponse res, int status, Cache cache, ContentInfo contentInfo, Map<String, List<String>> headers)
{
res.setStatus(status);
if (cache != null) res.setCache(cache);
setContentInfoOnResponse(res,contentInfo);
if (headers != null && !headers.isEmpty())
{
for (Map.Entry<String, List<String>> header:headers.entrySet())
{
for (int i=0; i < header.getValue().size(); i++) {
if (i==0)
{
//If its the first one then set the header overwriting.
res.setHeader(header.getKey(), header.getValue().get(i));
}
else
{
//If its not the first one than update the header
res.addHeader(header.getKey(), header.getValue().get(i));
}
}
}
}
}
/**
* Sets the response using the WithResponse object
* @param res
* @param withResponse
*/
default void setResponse(final WebScriptResponse res, WithResponse withResponse)
{
setResponse(res, withResponse.getStatus(), withResponse.getCache(), withResponse.getContentInfo(), withResponse.getHeaders());
}
/**
* Renders a JSON error response
* @param errorResponse The error
* @param res web script response
* @throws IOException
*/
default void renderErrorResponse(final ErrorResponse errorResponse, final WebScriptResponse res, final JacksonHelper jsonHelper) throws IOException {
String logId = "";
if (Status.STATUS_INTERNAL_SERVER_ERROR == errorResponse.getStatusCode() || resWriterLogger().isDebugEnabled())
{
logId = org.alfresco.util.GUID.generate();
resWriterLogger().error(logId+" : "+errorResponse.getStackTrace());
}
String stackMessage = I18NUtil.getMessage(DefaultExceptionResolver.STACK_MESSAGE_ID);
final ErrorResponse errorToWrite = new ErrorResponse(errorResponse.getErrorKey(),
errorResponse.getStatusCode(),
errorResponse.getBriefSummary(),
stackMessage,
logId,
errorResponse.getAdditionalState(),
DefaultExceptionResolver.ERROR_URL);
setContentInfoOnResponse(res, DEFAULT_JSON_CONTENT);
// Status must be set before the response is written by Jackson (which will by default close and commit the response).
// In a r/w txn, web script buffered responses ensure that it doesn't really matter but for r/o txns this is important.
res.setStatus(errorToWrite.getStatusCode());
jsonHelper.withWriter(res.getOutputStream(), new JacksonHelper.Writer()
{
@SuppressWarnings("unchecked")
@Override
public void writeContents(JsonGenerator generator, ObjectMapper objectMapper)
throws JsonGenerationException, JsonMappingException, IOException
{
JSONObject obj = new JSONObject();
obj.put("error", errorToWrite);
objectMapper.writeValue(generator, obj);
}
});
}
/**
* Renders an exception to the output stream as Json.
* @param exception
* @param response
* @throws IOException
*/
default void renderException(final Exception exception, final WebScriptResponse response, final ApiAssistant assistant) throws IOException {
renderErrorResponse(assistant.resolveException(exception), response, assistant.getJsonHelper());
}
/**
* Renders the result of an execution.
*
* @param res WebScriptResponse
* @param toSerialize result of an execution
* @throws IOException
*/
default void renderJsonResponse(final WebScriptResponse res, final Object toSerialize, final JacksonHelper jsonHelper)
throws IOException
{
jsonHelper.withWriter(res.getOutputStream(), new JacksonHelper.Writer()
{
@Override
public void writeContents(JsonGenerator generator, ObjectMapper objectMapper)
throws JsonGenerationException, JsonMappingException, IOException
{
objectMapper.writeValue(generator, toSerialize);
}
});
}
}

View File

@@ -53,6 +53,7 @@ import org.alfresco.rest.framework.resource.content.FileBinaryResource;
import org.alfresco.rest.framework.resource.content.NodeBinaryResource; import org.alfresco.rest.framework.resource.content.NodeBinaryResource;
import org.alfresco.rest.framework.resource.parameters.Params; import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.tools.ApiAssistant; import org.alfresco.rest.framework.tools.ApiAssistant;
import org.alfresco.rest.framework.tools.ResponseWriter;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -80,7 +81,7 @@ import org.springframework.http.HttpMethod;
*/ */
// TODO for requests that pass in input streams e.g. binary content for workflow, this is going to need a way to re-read the input stream a la // TODO for requests that pass in input streams e.g. binary content for workflow, this is going to need a way to re-read the input stream a la
// code in RepositoryContainer due to retrying transaction logic // code in RepositoryContainer due to retrying transaction logic
public abstract class AbstractResourceWebScript extends ApiWebScript implements HttpMethodSupport, ActionExecutor public abstract class AbstractResourceWebScript extends ApiWebScript implements HttpMethodSupport, ActionExecutor, ResponseWriter
{ {
private static Log logger = LogFactory.getLog(AbstractResourceWebScript.class); private static Log logger = LogFactory.getLog(AbstractResourceWebScript.class);
@@ -146,18 +147,18 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
} }
else else
{ {
renderJsonResponse(res, toSerialize); renderJsonResponse(res, toSerialize, assistant.getJsonHelper());
} }
} }
} }
catch (AlfrescoRuntimeException | ApiException | WebScriptException xception ) catch (AlfrescoRuntimeException | ApiException | WebScriptException xception )
{ {
assistant.renderException(xception, res); renderException(xception, res, assistant);
} }
catch (RuntimeException runtimeException) catch (RuntimeException runtimeException)
{ {
assistant.renderException(runtimeException, res); renderException(runtimeException, res, assistant);
} }
} }
@@ -165,7 +166,7 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
{ {
final String entityCollectionName = ResourceInspector.findEntityCollectionNameName(resource.getMetaData()); final String entityCollectionName = ResourceInspector.findEntityCollectionNameName(resource.getMetaData());
final ResourceOperation operation = resource.getMetaData().getOperation(getHttpMethod()); final ResourceOperation operation = resource.getMetaData().getOperation(getHttpMethod());
final WithResponse callBack = new WithResponse(operation.getSuccessStatus(), ApiAssistant.DEFAULT_JSON_CONTENT,ApiAssistant.CACHE_NEVER); final WithResponse callBack = new WithResponse(operation.getSuccessStatus(), DEFAULT_JSON_CONTENT,CACHE_NEVER);
Object toReturn = transactionService.getRetryingTransactionHelper().doInTransaction( Object toReturn = transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<Object>() new RetryingTransactionHelper.RetryingTransactionCallback<Object>()
{ {
@@ -199,7 +200,7 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
{ {
NodeBinaryResource nodeResource = (NodeBinaryResource) resource; NodeBinaryResource nodeResource = (NodeBinaryResource) resource;
ContentInfo contentInfo = nodeResource.getContentInfo(); ContentInfo contentInfo = nodeResource.getContentInfo();
assistant.setContentInfoOnResponse(res, contentInfo); setContentInfoOnResponse(res, contentInfo);
// if requested, set attachment // if requested, set attachment
boolean attach = StringUtils.isNotEmpty(nodeResource.getAttachFileName()); boolean attach = StringUtils.isNotEmpty(nodeResource.getAttachFileName());
Map<String, Object> model = getModelForCacheDirective(nodeResource.getCacheDirective()); Map<String, Object> model = getModelForCacheDirective(nodeResource.getCacheDirective());
@@ -217,70 +218,6 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
return null; return null;
} }
/**
* The response status must be set before the response is written by Jackson (which will by default close and commit the response).
* In a r/w txn, web script buffered responses ensure that it doesn't really matter but for r/o txns this is important.
*
* If you set content information via the contentInfo object and ALSO the headers then "headers" will win because they are
* set last.
*
* @param res
* @param status
* @param cache
* @param contentInfo
* @param headers
*/
public void setResponse(final WebScriptResponse res, int status, Cache cache, ContentInfo contentInfo, Map<String, List<String>> headers)
{
res.setStatus(status);
if (cache != null) res.setCache(cache);
assistant.setContentInfoOnResponse(res,contentInfo);
if (headers != null && !headers.isEmpty())
{
for (Map.Entry<String, List<String>> header:headers.entrySet())
{
for (int i=0; i < header.getValue().size(); i++) {
if (i==0)
{
//If its the first one then set the header overwriting.
res.setHeader(header.getKey(), header.getValue().get(i));
}
else
{
//If its not the first one than update the header
res.addHeader(header.getKey(), header.getValue().get(i));
}
}
}
}
}
protected void setResponse(final WebScriptResponse res, WithResponse withResponse)
{
setResponse(res, withResponse.getStatus(), withResponse.getCache(), withResponse.getContentInfo(), withResponse.getHeaders());
}
/**
* Renders the result of an execution.
*
* @param res WebScriptResponse
* @param toSerialize result of an execution
* @throws IOException
*/
protected void renderJsonResponse(final WebScriptResponse res, final Object toSerialize)
throws IOException
{
assistant.getJsonHelper().withWriter(res.getOutputStream(), new JacksonHelper.Writer()
{
@Override
public void writeContents(JsonGenerator generator, ObjectMapper objectMapper)
throws JsonGenerationException, JsonMappingException, IOException
{
objectMapper.writeValue(generator, toSerialize);
}
});
}
public void setLocator(ResourceLocator locator) public void setLocator(ResourceLocator locator)
{ {
this.locator = locator; this.locator = locator;

View File

@@ -38,6 +38,7 @@ import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResou
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceBinaryAction; import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceBinaryAction;
import org.alfresco.rest.framework.resource.parameters.Params; import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.tools.ApiAssistant; import org.alfresco.rest.framework.tools.ApiAssistant;
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse; import org.springframework.extensions.webscripts.WebScriptResponse;
@@ -48,7 +49,7 @@ import org.springframework.http.HttpMethod;
* *
* @author Gethin James * @author Gethin James
*/ */
public class ResourceWebScriptDelete extends AbstractResourceWebScript implements ParamsExtractor public class ResourceWebScriptDelete extends AbstractResourceWebScript implements ParamsExtractor, RecognizedParamsExtractor
{ {
public ResourceWebScriptDelete() public ResourceWebScriptDelete()
@@ -63,7 +64,7 @@ public class ResourceWebScriptDelete extends AbstractResourceWebScript implement
{ {
String entityId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.ENTITY_ID); String entityId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.ENTITY_ID);
String relationshipId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.RELATIONSHIP_ID); String relationshipId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.RELATIONSHIP_ID);
final Params.RecognizedParams params = ResourceWebScriptHelper.getRecognizedParams(req); final Params.RecognizedParams params = getRecognizedParams(req);
switch (resourceMeta.getType()) switch (resourceMeta.getType())
{ {
@@ -215,7 +216,7 @@ public class ResourceWebScriptDelete extends AbstractResourceWebScript implement
public Void execute(final ResourceWithMetadata resource, final Params params, final WebScriptResponse res, boolean isReadOnly) public Void execute(final ResourceWithMetadata resource, final Params params, final WebScriptResponse res, boolean isReadOnly)
{ {
final ResourceOperation operation = resource.getMetaData().getOperation(HttpMethod.DELETE); final ResourceOperation operation = resource.getMetaData().getOperation(HttpMethod.DELETE);
final WithResponse callBack = new WithResponse(operation.getSuccessStatus(), ApiAssistant.DEFAULT_JSON_CONTENT,ApiAssistant.CACHE_NEVER); final WithResponse callBack = new WithResponse(operation.getSuccessStatus(), DEFAULT_JSON_CONTENT,CACHE_NEVER);
transactionService.getRetryingTransactionHelper().doInTransaction( transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionCallback<Void>() new RetryingTransactionCallback<Void>()
{ {

View File

@@ -40,6 +40,7 @@ import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Params; import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.resource.parameters.Params.RecognizedParams; import org.alfresco.rest.framework.resource.parameters.Params.RecognizedParams;
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -51,7 +52,7 @@ import org.springframework.http.HttpMethod;
* *
* @author Gethin James * @author Gethin James
*/ */
public class ResourceWebScriptGet extends AbstractResourceWebScript implements ParamsExtractor public class ResourceWebScriptGet extends AbstractResourceWebScript implements ParamsExtractor, RecognizedParamsExtractor
{ {
private static Log logger = LogFactory.getLog(ResourceWebScriptGet.class); private static Log logger = LogFactory.getLog(ResourceWebScriptGet.class);
@@ -67,7 +68,7 @@ public class ResourceWebScriptGet extends AbstractResourceWebScript implements P
{ {
final String entityId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.ENTITY_ID); final String entityId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.ENTITY_ID);
final String relationshipId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.RELATIONSHIP_ID); final String relationshipId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.RELATIONSHIP_ID);
final RecognizedParams params = ResourceWebScriptHelper.getRecognizedParams(req); final RecognizedParams params = getRecognizedParams(req);
switch (resourceMeta.getType()) switch (resourceMeta.getType())
{ {

View File

@@ -67,6 +67,7 @@ import org.alfresco.rest.framework.resource.parameters.where.Query;
import org.alfresco.rest.framework.resource.parameters.where.QueryImpl; import org.alfresco.rest.framework.resource.parameters.where.QueryImpl;
import org.alfresco.rest.framework.resource.parameters.where.WhereCompiler; import org.alfresco.rest.framework.resource.parameters.where.WhereCompiler;
import org.alfresco.rest.framework.tools.ApiAssistant; import org.alfresco.rest.framework.tools.ApiAssistant;
import org.alfresco.rest.framework.tools.ResponseWriter;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
import org.alfresco.util.PropertyCheck; import org.alfresco.util.PropertyCheck;
import org.antlr.runtime.RecognitionException; import org.antlr.runtime.RecognitionException;
@@ -92,336 +93,10 @@ import org.springframework.http.HttpMethod;
public class ResourceWebScriptHelper public class ResourceWebScriptHelper
{ {
private static Log logger = LogFactory.getLog(ResourceWebScriptHelper.class); private static Log logger = LogFactory.getLog(ResourceWebScriptHelper.class);
public static final String PARAM_RELATIONS = "relations";
public static final String PARAM_FILTER_FIELDS = "fields";
@Deprecated
public static final String PARAM_FILTER_PROPERTIES = "properties";
public static final String PARAM_PAGING_SKIP = "skipCount";
public static final String PARAM_PAGING_MAX = "maxItems";
public static final String PARAM_ORDERBY = "orderBy";
public static final String PARAM_WHERE = "where";
public static final String PARAM_SELECT = "select";
public static final String PARAM_INCLUDE = "include";
public static final String PARAM_INCLUDE_SOURCE_ENTITY = "includeSource";
public static final List<String> KNOWN_PARAMS = Arrays.asList(
PARAM_RELATIONS, PARAM_FILTER_PROPERTIES, PARAM_FILTER_FIELDS,PARAM_PAGING_SKIP,PARAM_PAGING_MAX,
PARAM_ORDERBY, PARAM_WHERE, PARAM_SELECT, PARAM_INCLUDE_SOURCE_ENTITY);
private ResourceLocator locator; private ResourceLocator locator;
private ActionExecutor executor; private ActionExecutor executor;
/**
* Takes the web request and looks for a "fields" parameter (otherwise deprecated "properties" parameter).
*
* Parses the parameter and produces a list of bean properties to use as a filter A
* SimpleBeanPropertyFilter it returned that uses the bean properties. If no
* filter param is set then a default BeanFilter is returned that will never
* filter fields (ie. Returns all bean properties).
*
* @param filterParams String
* @return BeanPropertyFilter - if no parameter then returns a new
* ReturnAllBeanProperties class
*/
public static BeanPropertiesFilter getFilter(String filterParams)
{
return getFilter(filterParams, null);
}
/**
* Takes the web request and looks for a "fields" parameter (otherwise deprecated "properties" parameter).
*
* Parses the parameter and produces a list of bean properties to use as a filter A
* SimpleBeanPropertyFilter it returned that uses the bean properties. If no
* filter param is set then a default BeanFilter is returned that will never
* filter fields (ie. Returns all bean properties).
*
* If selectList is provided then it will take precedence (ie. be included) over the fields/properties filter
* for top-level entries (bean properties).
*
* For example, this will return entries from both select & properties, eg.
*
* select=abc,def&properties=id,name,ghi
*
* Note: it should be noted that API-generic "fields" clause does not currently work for sub-entries.
*
* Hence, even if the API-specific "select" clause allows selection of a sub-entries this cannot be used
* with "fields" filtering. For example, an API-specific method may implement and return "abc/blah", eg.
*
* select=abc/blah
*
* However the following will not return "abc/blah" if used with fields filtering, eg.
*
* select=abc/blah&fields=id,name,ghi
*
* If fields filtering is desired then it would require "abc" to be selected and returned as a whole, eg.
*
* select=abc&fields=id,name,ghi
*
* @param filterParams
* @param selectList
* @return
*/
public static BeanPropertiesFilter getFilter(String filterParams, List<String> selectList)
{
if (filterParams != null)
{
StringTokenizer st = new StringTokenizer(filterParams, ",");
Set<String> filteredProperties = new HashSet<String>(st.countTokens());
while (st.hasMoreTokens())
{
filteredProperties.add(st.nextToken());
}
// if supplied, the select takes precedence over the filter (fields/properties) for top-level bean properties
if (selectList != null)
{
for (String select : selectList)
{
String[] split = select.split("/");
filteredProperties.add(split[0]);
}
}
logger.debug("Filtering using the following properties: " + filteredProperties);
BeanPropertiesFilter filter = new BeanPropertiesFilter(filteredProperties);
return filter;
}
return BeanPropertiesFilter.ALLOW_ALL;
}
/**
* Takes the web request and looks for a "relations" parameter Parses the
* parameter and produces a list of bean properties to use as a filter A
* SimpleBeanPropertiesFilter it returned that uses the properties If no
* filter param is set then a default BeanFilter is returned that will never
* filter properties (ie. Returns all bean properties).
*
* @param filterParams String
* @return BeanPropertiesFilter - if no parameter then returns a new
* ReturnAllBeanProperties class
*/
public static Map<String, BeanPropertiesFilter> getRelationFilter(String filterParams)
{
if (filterParams != null)
{
// Split by a comma when not in a bracket
String[] relations = filterParams.split(",(?![^()]*+\\))");
Map<String, BeanPropertiesFilter> filterMap = new HashMap<String, BeanPropertiesFilter>(relations.length);
for (String relation : relations)
{
int bracketLocation = relation.indexOf("(");
if (bracketLocation != -1)
{
// We have properties
String relationKey = relation.substring(0, bracketLocation);
String props = relation.substring(bracketLocation + 1, relation.length() - 1);
filterMap.put(relationKey, getFilter(props));
}
else
{
// no properties so just get the String
filterMap.put(relation, getFilter(null));
}
}
return filterMap;
}
return Collections.emptyMap();
}
/**
* Takes the "select" parameter and turns it into a List<String> property names
* @param selectParam String
* @return bean property names potentially using JSON Pointer syntax
*/
@SuppressWarnings("unchecked")
@Deprecated
public static List<String> getSelectClause(String selectParam) throws InvalidArgumentException
{
return getClause(selectParam, "SELECT");
}
/**
* Takes the "include" parameter and turns it into a List<String> property names
* @param includeParam String
* @return bean property names potentially using JSON Pointer syntax
*/
@SuppressWarnings("unchecked")
public static List<String> getIncludeClause(String includeParam) throws InvalidArgumentException
{
return getClause(includeParam, "INCLUDE");
}
private static List<String> getClause(String param, String paramName)
{
if (param == null) return Collections.emptyList();
try {
CommonTree selectedPropsTree = WhereCompiler.compileSelectClause(param);
if (selectedPropsTree instanceof CommonErrorNode)
{
logger.debug("Error parsing the "+paramName+" clause "+selectedPropsTree);
throw new InvalidSelectException(paramName, selectedPropsTree);
}
if (selectedPropsTree.getChildCount() == 0 && !selectedPropsTree.getText().isEmpty())
{
return Arrays.asList(selectedPropsTree.getText());
}
List<Tree> children = (List<Tree>) selectedPropsTree.getChildren();
if (children!= null && !children.isEmpty())
{
List<String> properties = new ArrayList<String>(children.size());
for (Tree child : children) {
properties.add(child.getText());
}
return properties;
}
}
catch (RewriteCardinalityException re)
{
//Catch any error so it doesn't get thrown up the stack
logger.debug("Unhandled Error parsing the "+paramName+" clause: "+re);
}
catch (RecognitionException e)
{
logger.debug("Error parsing the \"+paramName+\" clause: "+param);
}
catch (InvalidQueryException iqe)
{
throw new InvalidSelectException(paramName, iqe.getQueryParam());
}
//Default to throw out an invalid query
throw new InvalidSelectException(paramName, param);
}
/**
* Takes the "where" parameter and turns it into a Java Object that can be used for querying
* @param whereParam String
* @return Query a parsed version of the where clause, represented in Java
*/
public static Query getWhereClause(String whereParam) throws InvalidQueryException
{
if (whereParam == null) return QueryImpl.EMPTY;
try {
CommonTree whereTree = WhereCompiler.compileWhereClause(whereParam);
if (whereTree instanceof CommonErrorNode)
{
logger.debug("Error parsing the WHERE clause "+whereTree);
throw new InvalidQueryException(whereTree);
}
return new QueryImpl(whereTree);
} catch (RewriteCardinalityException re) { //Catch any error so it doesn't get thrown up the stack
logger.info("Unhandled Error parsing the WHERE clause: "+re);
} catch (RecognitionException e) {
whereParam += ", "+WhereCompiler.resolveMessage(e);
logger.info("Error parsing the WHERE clause: "+whereParam);
}
//Default to throw out an invalid query
throw new InvalidQueryException(whereParam);
}
/**
* Takes the Sort parameter as a String and parses it into a List of SortColumn objects.
* The format is a comma seperated list of "columnName sortDirection",
* e.g. "name DESC, age ASC". It is not case sensitive and the sort direction is optional
* It default to sort ASCENDING.
* @param sortParams - String passed in on the request
* @return - the sort columns or an empty list if the params were invalid.
*/
public static List<SortColumn> getSort(String sortParams)
{
if (sortParams != null)
{
StringTokenizer st = new StringTokenizer(sortParams, ",");
List<SortColumn> sortedColumns = new ArrayList<SortColumn>(st.countTokens());
while (st.hasMoreTokens())
{
String token = st.nextToken();
StringTokenizer columnDesc = new StringTokenizer(token, " ");
if (columnDesc.countTokens() <= 2)
{
String columnName = columnDesc.nextToken();
String sortOrder = SortColumn.ASCENDING;
if (columnDesc.hasMoreTokens())
{
String sortDef = columnDesc.nextToken().toUpperCase();
if (SortColumn.ASCENDING.equals(sortDef) || SortColumn.DESCENDING.equals(sortDef))
{
sortOrder = sortDef;
}
else
{
logger.debug("Invalid sort order definition ("+sortDef+"). Valid values are "+SortColumn.ASCENDING+" or "+SortColumn.DESCENDING+".");
}
}
sortedColumns.add(new SortColumn(columnName, SortColumn.ASCENDING.equals(sortOrder)));
}
// filteredProperties.add();
}
// logger.debug("Filtering using the following properties: " + filteredProperties);
// BeanPropertiesFilter filter = new BeanPropertiesFilter(filteredProperties);
return sortedColumns;
}
return Collections.emptyList();
}
/**
* Extracts the body contents from the request
*
* @param req the request
* @param jsonHelper Jackson Helper
* @param requiredType the type to return
* @return the Object in the required type
*/
public static <T> T extractJsonContent(WebScriptRequest req, JacksonHelper jsonHelper, Class<T> requiredType)
{
Reader reader;
try
{
reader = req.getContent().getReader();
return jsonHelper.construct(reader, requiredType);
}
catch (JsonMappingException e)
{
logger.warn("Could not read content from HTTP request body.", e);
throw new InvalidArgumentException("Could not read content from HTTP request body.");
}
catch (IOException e)
{
throw new ApiException("Could not read content from HTTP request body.", e.getCause());
}
}
/**
* Extracts the body contents from the request as a List, the JSON can be an array or just a single value without the [] symbols
*
* @param req the request
* @param jsonHelper Jackson Helper
* @param requiredType the type to return (without the List param)
* @return A List of "Object" as the required type
*/
public static <T> List<T> extractJsonContentAsList(WebScriptRequest req, JacksonHelper jsonHelper, Class<T> requiredType)
{
Reader reader;
try
{
reader = req.getContent().getReader();
return jsonHelper.constructList(reader, requiredType);
}
catch (IOException e)
{
throw new ApiException("Could not read content from HTTP request body.", e.getCause());
}
}
/** /**
* Set the id of theObj to the uniqueId. Attempts to find a set method and * Set the id of theObj to the uniqueId. Attempts to find a set method and
* invoke it. If it fails it just swallows the exceptions and doesn't throw * invoke it. If it fails it just swallows the exceptions and doesn't throw
@@ -471,41 +146,6 @@ public class ResourceWebScriptHelper
} }
} }
// /**
// * Renders the response result
// *
// * @param response
// * @param result
// */
// public static void renderResponseDep(Map<String, Object> response, Object result)
// {
//
// if (result == null) { return; }
//
// if (result instanceof Collection)
// {
// response.put("list", result);
// }
// else if (result instanceof CollectionWithPagingInfo)
// {
// CollectionWithPagingInfo<?> col = (CollectionWithPagingInfo<?>) result;
// if (col.getCollection() !=null && !col.getCollection().isEmpty())
// {
// response.put("list", col);
// }
// }
// else if (result instanceof Pair<?,?>)
// {
// Pair<?,?> aPair = (Pair<?, ?>) result;
// response.put("entry", aPair.getFirst());
// response.put("relations", aPair.getSecond());
// }
// else
// {
// response.put("entry", result);
// }
// }
/** /**
* Looks at the object passed in and recursively expands any @EmbeddedEntityResource annotations or related relationship. * Looks at the object passed in and recursively expands any @EmbeddedEntityResource annotations or related relationship.
* {@link org.alfresco.rest.framework.resource.EmbeddedEntityResource EmbeddedEntityResource} is expanded by calling the ReadById method for this entity. * {@link org.alfresco.rest.framework.resource.EmbeddedEntityResource EmbeddedEntityResource} is expanded by calling the ReadById method for this entity.
@@ -677,7 +317,7 @@ public class ResourceWebScriptHelper
paramFilter = filters.get(resourceKey); paramFilter = filters.get(resourceKey);
} }
final Params executionParams = Params.valueOf(paramFilter, uniqueEntityId, params.getRequest()); final Params executionParams = Params.valueOf(paramFilter, uniqueEntityId, params.getRequest());
final WithResponse callBack = new WithResponse(Status.STATUS_OK, ApiAssistant.DEFAULT_JSON_CONTENT,ApiAssistant.CACHE_NEVER); final WithResponse callBack = new WithResponse(Status.STATUS_OK, ResponseWriter.DEFAULT_JSON_CONTENT,ResponseWriter.CACHE_NEVER);
//Read only because this only occurs for GET requests //Read only because this only occurs for GET requests
Object result = executor.executeAction(resource, executionParams, callBack); Object result = executor.executeAction(resource, executionParams, callBack);
return processAdditionsToTheResponse(null, api, null, executionParams, result); return processAdditionsToTheResponse(null, api, null, executionParams, result);
@@ -705,118 +345,6 @@ public class ResourceWebScriptHelper
return null; //default return null; //default
} }
/**
* Finds all request parameters that aren't already known about (eg. not paging or filter params)
* and returns them for use.
*
* @param req - the WebScriptRequest object
* @return the request parameters
*/
public static Map<String, String[]> getRequestParameters(WebScriptRequest req)
{
if (req!= null)
{
String[] paramNames = req.getParameterNames();
if (paramNames!= null)
{
Map<String, String[]> requestParameteters = new HashMap<String, String[]>(paramNames.length);
for (int i = 0; i < paramNames.length; i++)
{
String paramName = paramNames[i];
if (!KNOWN_PARAMS.contains(paramName))
{
String[] vals = req.getParameterValues(paramName);
requestParameteters.put(paramName, vals);
}
}
return requestParameteters;
}
}
return Collections.emptyMap();
}
/**
* Finds the formal set of params that any rest service could potentially have passed in as request params
* @param req WebScriptRequest
* @return RecognizedParams a POJO containing the params for use with the Params objects
*/
public static RecognizedParams getRecognizedParams(WebScriptRequest req)
{
Paging paging = findPaging(req);
List<SortColumn> sorting = getSort(req.getParameter(ResourceWebScriptHelper.PARAM_ORDERBY));
Map<String, BeanPropertiesFilter> relationFilter = getRelationFilter(req.getParameter(ResourceWebScriptHelper.PARAM_RELATIONS));
Query whereQuery = getWhereClause(req.getParameter(ResourceWebScriptHelper.PARAM_WHERE));
Map<String, String[]> requestParams = getRequestParameters(req);
boolean includeSource = Boolean.valueOf(req.getParameter(ResourceWebScriptHelper.PARAM_INCLUDE_SOURCE_ENTITY));
List<String> includedFields = getIncludeClause(req.getParameter(ResourceWebScriptHelper.PARAM_INCLUDE));
List<String> selectFields = getSelectClause(req.getParameter(ResourceWebScriptHelper.PARAM_SELECT));
String fields = req.getParameter(ResourceWebScriptHelper.PARAM_FILTER_FIELDS);
String properties = req.getParameter(ResourceWebScriptHelper.PARAM_FILTER_PROPERTIES);
if ((fields != null) && (properties != null))
{
if (logger.isWarnEnabled())
{
logger.warn("Taking 'fields' param [" + fields + "] and ignoring deprecated 'properties' param [" + properties + "]");
}
}
BeanPropertiesFilter filter = getFilter((fields != null ? fields : properties), includedFields);
return new RecognizedParams(requestParams, paging, filter, relationFilter, includedFields, selectFields, whereQuery, sorting, includeSource);
}
/**
* Find paging setings based on the request parameters.
*
* @param req
* @return Paging
*/
public static Paging findPaging(WebScriptRequest req)
{
int skipped = Paging.DEFAULT_SKIP_COUNT;
int max = Paging.DEFAULT_MAX_ITEMS;
String skip = req.getParameter(PARAM_PAGING_SKIP);
String maxItems = req.getParameter(PARAM_PAGING_MAX);
try
{
if (skip != null) { skipped = Integer.parseInt(skip);}
if (maxItems != null) { max = Integer.parseInt(maxItems); }
if (skipped < 0)
{
throw new InvalidArgumentException("Negative values not supported for skipCount.");
}
if (max < 1)
{
throw new InvalidArgumentException("Only positive values supported for maxItems.");
}
}
catch (NumberFormatException error)
{
String errorMsg = "Invalid paging parameters skipCount: " + skip + ", maxItems:" + maxItems;
if (logger.isDebugEnabled())
{
logger.debug(errorMsg);
}
if (skip == null)
{
errorMsg = "Invalid paging parameter maxItems:" + maxItems;
}
if (maxItems == null)
{
errorMsg = "Invalid paging parameter skipCount:" + skip;
}
throw new InvalidArgumentException(errorMsg);
}
return Paging.valueOf(skipped, max);
}
public void setLocator(ResourceLocator locator) public void setLocator(ResourceLocator locator)
{ {
this.locator = locator; this.locator = locator;

View File

@@ -45,6 +45,8 @@ import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResou
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Params; import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.resource.parameters.Params.RecognizedParams; import org.alfresco.rest.framework.resource.parameters.Params.RecognizedParams;
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.alfresco.rest.framework.tools.RequestReader;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptRequestImpl; import org.springframework.extensions.webscripts.WebScriptRequestImpl;
@@ -56,7 +58,8 @@ import org.springframework.http.HttpMethod;
* *
* @author Gethin James * @author Gethin James
*/ */
public class ResourceWebScriptPost extends AbstractResourceWebScript implements ParamsExtractor public class ResourceWebScriptPost extends AbstractResourceWebScript implements ParamsExtractor,
RecognizedParamsExtractor, RequestReader
{ {
public ResourceWebScriptPost() public ResourceWebScriptPost()
@@ -69,7 +72,7 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
@Override @Override
public Params extractParams(ResourceMetadata resourceMeta, WebScriptRequest req) public Params extractParams(ResourceMetadata resourceMeta, WebScriptRequest req)
{ {
final RecognizedParams params = ResourceWebScriptHelper.getRecognizedParams(req); final RecognizedParams params = getRecognizedParams(req);
final String entityId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.ENTITY_ID); final String entityId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.ENTITY_ID);
final String relationshipId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.RELATIONSHIP_ID); final String relationshipId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.RELATIONSHIP_ID);
final ResourceOperation operation = resourceMeta.getOperation(HttpMethod.POST); final ResourceOperation operation = resourceMeta.getOperation(HttpMethod.POST);
@@ -168,7 +171,7 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
Object jsonContent = null; Object jsonContent = null;
if (objType != null) if (objType != null)
{ {
jsonContent = ResourceWebScriptHelper.extractJsonContent(req, assistant.getJsonHelper(), objType); jsonContent = extractJsonContent(req, assistant.getJsonHelper(), objType);
} }
if (isTypeOperation) if (isTypeOperation)
@@ -203,11 +206,11 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
if (isTypeOperation) if (isTypeOperation)
{ {
// Operations don't support a List as json body // Operations don't support a List as json body
return ResourceWebScriptHelper.extractJsonContent(req, assistant.getJsonHelper(), objType); return extractJsonContent(req, assistant.getJsonHelper(), objType);
} }
else else
{ {
return ResourceWebScriptHelper.extractJsonContentAsList(req, assistant.getJsonHelper(), objType); return extractJsonContentAsList(req, assistant.getJsonHelper(), objType);
} }
} }

View File

@@ -44,6 +44,8 @@ import org.alfresco.rest.framework.resource.content.BasicContentInfo;
import org.alfresco.rest.framework.resource.content.ContentInfoImpl; import org.alfresco.rest.framework.resource.content.ContentInfoImpl;
import org.alfresco.rest.framework.resource.parameters.Params; import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.resource.parameters.Params.RecognizedParams; import org.alfresco.rest.framework.resource.parameters.Params.RecognizedParams;
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.alfresco.rest.framework.tools.RequestReader;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -57,7 +59,8 @@ import org.springframework.http.MediaType;
* *
* @author Gethin James * @author Gethin James
*/ */
public class ResourceWebScriptPut extends AbstractResourceWebScript implements ParamsExtractor public class ResourceWebScriptPut extends AbstractResourceWebScript implements ParamsExtractor,
RecognizedParamsExtractor, RequestReader
{ {
private static Log logger = LogFactory.getLog(ResourceWebScriptPut.class); private static Log logger = LogFactory.getLog(ResourceWebScriptPut.class);
@@ -75,7 +78,7 @@ public class ResourceWebScriptPut extends AbstractResourceWebScript implements P
final String relationshipId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.RELATIONSHIP_ID); final String relationshipId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.RELATIONSHIP_ID);
final String entityId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.ENTITY_ID); final String entityId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.ENTITY_ID);
final RecognizedParams params = ResourceWebScriptHelper.getRecognizedParams(req); final RecognizedParams params = getRecognizedParams(req);
final ResourceOperation operation = resourceMeta.getOperation(HttpMethod.PUT); final ResourceOperation operation = resourceMeta.getOperation(HttpMethod.PUT);
switch (resourceMeta.getType()) switch (resourceMeta.getType())
@@ -87,7 +90,7 @@ public class ResourceWebScriptPut extends AbstractResourceWebScript implements P
} else } else
{ {
Object putEnt = ResourceWebScriptHelper.extractJsonContent(req, assistant.getJsonHelper(), resourceMeta.getObjectType(operation)); Object putEnt = extractJsonContent(req, assistant.getJsonHelper(), resourceMeta.getObjectType(operation));
return Params.valueOf(entityId,params,putEnt, req); return Params.valueOf(entityId,params,putEnt, req);
} }
case RELATIONSHIP: case RELATIONSHIP:
@@ -96,7 +99,7 @@ public class ResourceWebScriptPut extends AbstractResourceWebScript implements P
throw new UnsupportedResourceOperationException("PUT is executed against the instance URL"); throw new UnsupportedResourceOperationException("PUT is executed against the instance URL");
} else } else
{ {
Object putRel = ResourceWebScriptHelper.extractJsonContent(req, assistant.getJsonHelper(), resourceMeta.getObjectType(operation)); Object putRel = extractJsonContent(req, assistant.getJsonHelper(), resourceMeta.getObjectType(operation));
ResourceWebScriptHelper.setUniqueId(putRel,relationshipId); ResourceWebScriptHelper.setUniqueId(putRel,relationshipId);
return Params.valueOf(entityId, params, putRel, req); return Params.valueOf(entityId, params, putRel, req);
} }

View File

@@ -39,6 +39,7 @@ import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.RelationshipResource; import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.parameters.Params; import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.tools.ApiAssistant; import org.alfresco.rest.framework.tools.ApiAssistant;
import org.alfresco.rest.framework.tools.ResponseWriter;
import org.alfresco.rest.framework.webscripts.AbstractResourceWebScript; import org.alfresco.rest.framework.webscripts.AbstractResourceWebScript;
import org.alfresco.rest.framework.webscripts.ApiWebScript; import org.alfresco.rest.framework.webscripts.ApiWebScript;
import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper; import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper;
@@ -81,7 +82,7 @@ public abstract class AbstractContextTest
static Params NOT_USED = Params.valueOf("notUsed", null, mock(WebScriptRequest.class)); static Params NOT_USED = Params.valueOf("notUsed", null, mock(WebScriptRequest.class));
static final Params.RecognizedParams NULL_PARAMS = new Params.RecognizedParams(null, null, null, null, null, null, null, null, false); static final Params.RecognizedParams NULL_PARAMS = new Params.RecognizedParams(null, null, null, null, null, null, null, null, false);
static final WithResponse callBack = new WithResponse(Status.STATUS_OK, ApiAssistant.DEFAULT_JSON_CONTENT,ApiAssistant.CACHE_NEVER); static final WithResponse callBack = new WithResponse(Status.STATUS_OK, ResponseWriter.DEFAULT_JSON_CONTENT,ResponseWriter.CACHE_NEVER);
static Api api = Api.valueOf("alfrescomock", "private", "1"); static Api api = Api.valueOf("alfrescomock", "private", "1");
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@@ -25,6 +25,7 @@
*/ */
package org.alfresco.rest.framework.tests.core; package org.alfresco.rest.framework.tests.core;
import org.alfresco.rest.framework.tools.RecognizedParamsExtractorTest;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses; import org.junit.runners.Suite.SuiteClasses;
@@ -37,7 +38,7 @@ import org.junit.runners.Suite.SuiteClasses;
@SuiteClasses({ InspectorTests.class, JsonJacksonTests.class, ParamsExtractorTests.class, @SuiteClasses({ InspectorTests.class, JsonJacksonTests.class, ParamsExtractorTests.class,
ResourceLocatorTests.class, ResourceWebScriptHelperTests.class, SerializeTests.class, ResourceLocatorTests.class, ResourceWebScriptHelperTests.class, SerializeTests.class,
WhereTests.class, ExecutionTests.class, WithResponseTest.class, WhereTests.class, ExecutionTests.class, WithResponseTest.class,
ExceptionResolverTests.class }) ExceptionResolverTests.class, RecognizedParamsExtractorTest.class})
public class AllRestFrameworkTest public class AllRestFrameworkTest
{ {

View File

@@ -51,6 +51,7 @@ import org.alfresco.rest.framework.tests.api.mocks.Grass;
import org.alfresco.rest.framework.tests.api.mocks.Sheep; import org.alfresco.rest.framework.tests.api.mocks.Sheep;
import org.alfresco.rest.framework.tests.api.mocks3.FlockEntityResource; import org.alfresco.rest.framework.tests.api.mocks3.FlockEntityResource;
import org.alfresco.rest.framework.tools.ApiAssistant; import org.alfresco.rest.framework.tools.ApiAssistant;
import org.alfresco.rest.framework.tools.ResponseWriter;
import org.alfresco.rest.framework.webscripts.AbstractResourceWebScript; import org.alfresco.rest.framework.webscripts.AbstractResourceWebScript;
import org.alfresco.rest.framework.webscripts.ApiWebScript; import org.alfresco.rest.framework.webscripts.ApiWebScript;
import org.junit.Test; import org.junit.Test;
@@ -80,7 +81,7 @@ import java.util.Map;
* Tests the execution of resources * Tests the execution of resources
*/ */
public class ExecutionTests extends AbstractContextTest public class ExecutionTests extends AbstractContextTest implements ResponseWriter
{ {
static final Api api3 = Api.valueOf("alfrescomock", "private", "3"); static final Api api3 = Api.valueOf("alfrescomock", "private", "3");
@@ -99,7 +100,7 @@ public class ExecutionTests extends AbstractContextTest
entityResource = locator.locateEntityResource(api,"cow", HttpMethod.GET); entityResource = locator.locateEntityResource(api,"cow", HttpMethod.GET);
result = executor.execute(entityResource, Params.valueOf((String)null, null, mock(WebScriptRequest.class)), response, true); result = executor.execute(entityResource, Params.valueOf((String)null, null, mock(WebScriptRequest.class)), response, true);
assertNotNull(result); assertNotNull(result);
verify(response, times(1)).setCache((Cache) ApiAssistant.CACHE_NEVER); verify(response, times(1)).setCache((Cache) ResponseWriter.CACHE_NEVER);
response = mock(WebScriptResponse.class); response = mock(WebScriptResponse.class);
result = executor.execute(entityResource, Params.valueOf("543", null, mock(WebScriptRequest.class)), response, true); result = executor.execute(entityResource, Params.valueOf("543", null, mock(WebScriptRequest.class)), response, true);
@@ -305,7 +306,7 @@ public class ExecutionTests extends AbstractContextTest
ErrorResponse defaultError = new DefaultExceptionResolver().resolveException(new NullPointerException()); ErrorResponse defaultError = new DefaultExceptionResolver().resolveException(new NullPointerException());
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
apiAssistant.renderErrorResponse(defaultError, mockResponse(out)); renderErrorResponse(defaultError, mockResponse(out), apiAssistant.getJsonHelper());
String errorMessage = out.toString(); String errorMessage = out.toString();
// System.out.println(errorMessage); // System.out.println(errorMessage);
assertTrue(errorMessage.contains("\"errorKey\":\"framework.exception.ApiDefault\"")); assertTrue(errorMessage.contains("\"errorKey\":\"framework.exception.ApiDefault\""));
@@ -316,7 +317,7 @@ public class ExecutionTests extends AbstractContextTest
ErrorResponse anError = simpleMappingExceptionResolver.resolveException(new ApiException("nothing")); ErrorResponse anError = simpleMappingExceptionResolver.resolveException(new ApiException("nothing"));
out = new ByteArrayOutputStream(); out = new ByteArrayOutputStream();
apiAssistant.renderErrorResponse(anError, mockResponse(out)); renderErrorResponse(anError, mockResponse(out),apiAssistant.getJsonHelper());
errorMessage = out.toString(); errorMessage = out.toString();
// System.out.println(errorMessage); // System.out.println(errorMessage);
assertTrue(errorMessage.contains("\"errorKey\":\"nothing\"")); assertTrue(errorMessage.contains("\"errorKey\":\"nothing\""));
@@ -326,7 +327,7 @@ public class ExecutionTests extends AbstractContextTest
anError = simpleMappingExceptionResolver.resolveException(new EntityNotFoundException("2")); anError = simpleMappingExceptionResolver.resolveException(new EntityNotFoundException("2"));
out = new ByteArrayOutputStream(); out = new ByteArrayOutputStream();
apiAssistant.renderErrorResponse(anError, mockResponse(out)); renderErrorResponse(anError, mockResponse(out),apiAssistant.getJsonHelper());
errorMessage = out.toString(); errorMessage = out.toString();
System.out.println(errorMessage); System.out.println(errorMessage);
assertTrue(errorMessage.contains("\"errorKey\":\"framework.exception.EntityNotFound\"")); assertTrue(errorMessage.contains("\"errorKey\":\"framework.exception.EntityNotFound\""));

View File

@@ -77,6 +77,7 @@ import org.alfresco.rest.framework.tests.api.mocks3.SheepBlackSheepResourceIsNoM
import org.alfresco.rest.framework.tests.api.mocks3.SheepEntityResourceWithDeletedMethods; import org.alfresco.rest.framework.tests.api.mocks3.SheepEntityResourceWithDeletedMethods;
import org.alfresco.rest.framework.tests.api.mocks3.SlimGoat; import org.alfresco.rest.framework.tests.api.mocks3.SlimGoat;
import org.alfresco.rest.framework.tools.ApiAssistant; import org.alfresco.rest.framework.tools.ApiAssistant;
import org.alfresco.rest.framework.tools.ResponseWriter;
import org.alfresco.rest.framework.webscripts.ApiWebScript; import org.alfresco.rest.framework.webscripts.ApiWebScript;
import org.alfresco.rest.framework.webscripts.WithResponse; import org.alfresco.rest.framework.webscripts.WithResponse;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
@@ -466,7 +467,7 @@ public class InspectorTests
OperationResourceMetaData operationResourceMetaData = (OperationResourceMetaData) resourceMetadata; OperationResourceMetaData operationResourceMetaData = (OperationResourceMetaData) resourceMetadata;
Method actionMethod = operationResourceMetaData.getOperationMethod(); Method actionMethod = operationResourceMetaData.getOperationMethod();
String result = null; String result = null;
final WithResponse wr = new WithResponse(Status.STATUS_OK, ApiAssistant.DEFAULT_JSON_CONTENT, ApiAssistant.CACHE_NEVER); final WithResponse wr = new WithResponse(Status.STATUS_OK, ResponseWriter.DEFAULT_JSON_CONTENT, ResponseWriter.CACHE_NEVER);
switch (resourceMetadata.getUniqueId()) switch (resourceMetadata.getUniqueId())
{ {

View File

@@ -49,6 +49,7 @@ import org.alfresco.rest.framework.tests.api.mocks.Farmer;
import org.alfresco.rest.framework.tests.api.mocks.Goat; import org.alfresco.rest.framework.tests.api.mocks.Goat;
import org.alfresco.rest.framework.tests.api.mocks.Grass; import org.alfresco.rest.framework.tests.api.mocks.Grass;
import org.alfresco.rest.framework.tests.api.mocks.UniqueIdMethodButNoSetter; import org.alfresco.rest.framework.tests.api.mocks.UniqueIdMethodButNoSetter;
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper; import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper;
import org.junit.Test; import org.junit.Test;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
@@ -63,329 +64,6 @@ import org.springframework.extensions.webscripts.WebScriptRequest;
public class ResourceWebScriptHelperTests public class ResourceWebScriptHelperTests
{ {
@Test
public void getFilterTest()
{
BeanPropertiesFilter theFilter = ResourceWebScriptHelper.getFilter(null);
assertNotNull(theFilter);
assertTrue("Null passed in so must return the default BeanPropertiesFilter.ALLOW_ALL class", BeanPropertiesFilter.AllProperties.class.equals(theFilter.getClass()));
theFilter = ResourceWebScriptHelper.getFilter("bob");
assertNotNull(theFilter);
assertTrue("Must return the BeanPropertiesFilter class", theFilter instanceof BeanPropertiesFilter);
theFilter = ResourceWebScriptHelper.getFilter("50,fred,b.z");
assertNotNull(theFilter);
assertTrue("Must return the BeanPropertiesFilter class", theFilter instanceof BeanPropertiesFilter);
theFilter = ResourceWebScriptHelper.getFilter("50,fred,");
assertNotNull(theFilter);
assertTrue("Must return the BeanPropertiesFilter class", theFilter instanceof BeanPropertiesFilter);
}
@Test
public void getSortingTest()
{
List<SortColumn> theSort = ResourceWebScriptHelper.getSort(null);
assertNotNull(theSort);
assertTrue("Null passed in so empty sort list should be returned.", theSort.isEmpty());
theSort = ResourceWebScriptHelper.getSort("name ASC");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc);
theSort = ResourceWebScriptHelper.getSort("name ");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc);
theSort = ResourceWebScriptHelper.getSort("name DESC");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(!theSort.get(0).asc); //desc
theSort = ResourceWebScriptHelper.getSort("name desc");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(!theSort.get(0).asc); //desc
theSort = ResourceWebScriptHelper.getSort("name,age desc");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 2);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc);
assertEquals("age", theSort.get(1).column);
assertTrue(!theSort.get(1).asc); //desc
theSort = ResourceWebScriptHelper.getSort(" name, age desc");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 2);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc);
assertEquals("age", theSort.get(1).column);
assertTrue(!theSort.get(1).asc); //desc
theSort = ResourceWebScriptHelper.getSort("name DESC, age desc");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 2);
assertEquals("name", theSort.get(0).column);
assertTrue(!theSort.get(0).asc); //desc
assertEquals("age", theSort.get(1).column);
assertTrue(!theSort.get(1).asc); //desc
theSort = ResourceWebScriptHelper.getSort("age Desc, name Asc");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 2);
assertEquals("age", theSort.get(0).column);
assertTrue(!theSort.get(0).asc); //desc
assertEquals("name", theSort.get(1).column);
assertTrue(theSort.get(1).asc);
theSort = ResourceWebScriptHelper.getSort("name des"); //invalid, should be desc
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc); //Defaults to ascending because the sort order was invalid
theSort = ResourceWebScriptHelper.getSort("name asc,"); //invalid, should be desc
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc);
}
@Test
public void getIncludeClauseTest()
{
getClauseTest("include");
}
@Test
public void getSelectClauseTest()
{
getClauseTest("select");
}
// at the moment select and include are parsed the same way, hence common/shared test
private void getClauseTest(String paramName)
{
List<String> theClause = getClause(paramName, null);
assertNotNull(theClause);
assertFalse("Null passed in so nothing in the "+paramName, theClause.size() > 0);
try
{
theClause = getClause(paramName, ",,,");
fail("Should throw an InvalidSelectException");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getClause(paramName, "(,,,");
fail("Should throw an InvalidSelectException");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getClause(paramName, "(,,,)");
fail("Should throw an InvalidSelectException");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getClause(paramName, "x/,z");
fail("Should throw an InvalidSelectException");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getClause(paramName, "/x'n,/z");
fail("Should throw an InvalidSelectException");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getClause(paramName, "/foo/0");
fail("Should throw an InvalidSelectException. Legal identifiers must start with a letter not zero");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getClause(paramName, "/");
fail("Should throw an InvalidSelectException. No identifier specified.");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getClause(paramName, "path, isLink");
fail("Should throw an InvalidSelectException. No identifier specified.");
}
catch (InvalidSelectException error)
{
//this is correct
}
theClause = getClause(paramName, "king/kong");
assertTrue("has a valid "+paramName, theClause.size() == 1);
assertEquals("king/kong",theClause.get(0));
theClause = getClause(paramName, "x,y");
assertTrue("has a valid "+paramName, theClause.size() == 2);
assertEquals("x",theClause.get(0));
assertEquals("y",theClause.get(1));
theClause = getClause(paramName, "x,/z");
assertTrue("has a valid "+paramName, theClause.size() == 2);
assertEquals("x",theClause.get(0));
assertEquals("/z",theClause.get(1));
theClause = getClause(paramName, "/b");
assertTrue("has a valid "+paramName, theClause.size() == 1);
assertEquals("/b",theClause.get(0));
theClause = getClause(paramName, "/be,/he");
assertTrue("has a valid "+paramName, theClause.size() == 2);
assertEquals("/be",theClause.get(0));
assertEquals("/he",theClause.get(1));
theClause = getClause(paramName, "/king/kong");
assertTrue("has a valid "+paramName, theClause.size() == 1);
assertEquals("/king/kong",theClause.get(0));
theClause = getClause(paramName, "/name,/person/age");
assertTrue("has a valid "+paramName, theClause.size() == 2);
assertEquals("/name",theClause.get(0));
assertEquals("/person/age",theClause.get(1));
theClause = getClause(paramName, "/foo");
assertTrue("has a valid select",theClause.size() == 1);
assertEquals("/foo",theClause.get(0));
theClause = getClause(paramName, "/foo/anArray/x");
assertTrue("has a valid "+paramName, theClause.size() == 1);
assertEquals("/foo/anArray/x",theClause.get(0));
theClause = getClause(paramName, "/foo/anArray/x,/person/age,/eggs/bacon/sausage,/p");
assertTrue("has a valid "+paramName, theClause.size() == 4);
assertEquals("/foo/anArray/x",theClause.get(0));
assertEquals("/person/age",theClause.get(1));
assertEquals("/eggs/bacon/sausage",theClause.get(2));
assertEquals("/p",theClause.get(3));
theClause = getClause(paramName, "/foo/_bar ");
assertTrue("has a valid "+paramName, theClause.size() == 1);
assertEquals("/foo/_bar",theClause.get(0));
}
private List<String> getClause(String paramName, String paramValue)
{
if (paramName.equalsIgnoreCase("include"))
{
return ResourceWebScriptHelper.getIncludeClause(paramValue);
}
else if (paramName.equalsIgnoreCase("select"))
{
return ResourceWebScriptHelper.getSelectClause(paramValue);
}
fail("Unexpected clause: "+paramName);
return null;
}
@Test
public void getRelationFilterTest()
{
Map<String, BeanPropertiesFilter> theFilter = ResourceWebScriptHelper.getRelationFilter(null);
assertNotNull(theFilter);
assertTrue("Null passed in so nothing to filter.",theFilter.isEmpty());
theFilter = ResourceWebScriptHelper.getRelationFilter("bob");
assertNotNull(theFilter);
assertTrue("Must be a single relationship", theFilter.size() == 1);
assertTrue("Must be a single relationship called bob", theFilter.containsKey("bob"));
BeanPropertiesFilter aFilter = theFilter.get("bob");
assertTrue("No bean properties specified so need a BeanPropertiesFilter.ALLOW_ALL class", BeanPropertiesFilter.AllProperties.class.equals(aFilter.getClass()));
theFilter = ResourceWebScriptHelper.getRelationFilter("bob,hope");
assertNotNull(theFilter);
assertTrue("Must be a two relationships", theFilter.size() == 2);
assertTrue("Must have hope.", theFilter.containsKey("hope"));
aFilter = theFilter.get("hope");
assertTrue("No bean properties specified so need a BeanPropertiesFilter.ALLOW_ALL class", BeanPropertiesFilter.AllProperties.class.equals(aFilter.getClass()));
theFilter = ResourceWebScriptHelper.getRelationFilter("bob(name),hope");
assertNotNull(theFilter);
assertTrue("Must be a two relationships", theFilter.size() == 2);
assertTrue("Must have bob.", theFilter.containsKey("bob"));
aFilter = theFilter.get("bob");
assertTrue("Bean properties specified so must be an BeanPropertiesFilter class", BeanPropertiesFilter.class.equals(aFilter.getClass()));
theFilter = ResourceWebScriptHelper.getRelationFilter("bob,hope(age,name)");
assertNotNull(theFilter);
assertTrue("Must be a two relationships", theFilter.size() == 2);
aFilter = theFilter.get("bob");
assertTrue("No bean properties specified so need a BeanPropertiesFilter.ALLOW_ALL class", BeanPropertiesFilter.AllProperties.class.equals(aFilter.getClass()));
aFilter = theFilter.get("hope");
assertTrue("Bean properties specified so must be an BeanPropertiesFilter class", BeanPropertiesFilter.class.equals(aFilter.getClass()));
theFilter = ResourceWebScriptHelper.getRelationFilter("bob(name,age),nohope,hope(height,width)");
assertNotNull(theFilter);
assertTrue("Must be a three relationships", theFilter.size() == 3);
aFilter = theFilter.get("bob");
assertTrue("Bean properties specified so must be an BeanPropertiesFilter class", BeanPropertiesFilter.class.equals(aFilter.getClass()));
aFilter = theFilter.get("nohope");
assertTrue("No bean properties specified so need a ReturnAllBeanProperties class", BeanPropertiesFilter.AllProperties.class.equals(aFilter.getClass()));
aFilter = theFilter.get("hope");
assertTrue("Bean properties specified so must be an BeanPropertiesFilter class", BeanPropertiesFilter.class.equals(aFilter.getClass()));
}
@Test @Test
public void setUniqueIdTest() public void setUniqueIdTest()
{ {
@@ -406,161 +84,4 @@ public class ResourceWebScriptHelperTests
assertNotNull("There should not be an error, errors should be swallowed up.",invalidbj); assertNotNull("There should not be an error, errors should be swallowed up.",invalidbj);
} }
@Test
public void findPagingTest()
{
WebScriptRequest request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("34");
when(request.getParameter("maxItems")).thenReturn("50");
Paging pagin = ResourceWebScriptHelper.findPaging(request);
assertNotNull(pagin);
assertTrue(pagin.getSkipCount() == 34);
assertTrue(pagin.getMaxItems() == 50);
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn(null);
when(request.getParameter("maxItems")).thenReturn(null);
pagin = ResourceWebScriptHelper.findPaging(request);
assertNotNull(pagin);
assertTrue(pagin.getSkipCount() == Paging.DEFAULT_SKIP_COUNT);
assertTrue(pagin.getMaxItems() == Paging.DEFAULT_MAX_ITEMS);
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("55");
pagin = ResourceWebScriptHelper.findPaging(request);
assertNotNull(pagin);
assertTrue(pagin.getSkipCount() == 55);
assertTrue(pagin.getMaxItems() == Paging.DEFAULT_MAX_ITEMS);
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn(null);
when(request.getParameter("maxItems")).thenReturn("45");
pagin = ResourceWebScriptHelper.findPaging(request);
assertNotNull(pagin);
assertTrue(pagin.getMaxItems() == 45);
assertTrue(pagin.getSkipCount() == Paging.DEFAULT_SKIP_COUNT);
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("apple");
when(request.getParameter("maxItems")).thenReturn("pear");
try
{
pagin = ResourceWebScriptHelper.findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("0");
when(request.getParameter("maxItems")).thenReturn("0");
try
{
pagin = ResourceWebScriptHelper.findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
//Test Case cloud-2198
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("0");
when(request.getParameter("maxItems")).thenReturn("a");
try
{
pagin = ResourceWebScriptHelper.findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("s");
when(request.getParameter("maxItems")).thenReturn("5");
try
{
pagin = ResourceWebScriptHelper.findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("0");
when(request.getParameter("maxItems")).thenReturn("-2");
try
{
pagin = ResourceWebScriptHelper.findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("-3");
when(request.getParameter("maxItems")).thenReturn("5");
try
{
pagin = ResourceWebScriptHelper.findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
request = mock(WebScriptRequest.class);
when(request.getParameter("maxItems")).thenReturn("5");
pagin = ResourceWebScriptHelper.findPaging(request);
assertNotNull(pagin);
assertTrue("skip count defaults to 0", pagin.getSkipCount() == Paging.DEFAULT_SKIP_COUNT);
//End of Test Case cloud-2198
}
@Test
public void paramsTest()
{
Map<String,List<String>> mockParams = new HashMap<String,List<String>>();
mockParams.put("age", Arrays.asList("23","45"));
mockParams.put("name", Arrays.asList("fred"));
WebScriptRequest request = mockRequest(mockParams);
Map<String, String[]> params = ResourceWebScriptHelper.getRequestParameters(request);
assertNotNull(params);
Params paramObj = ParamsExtender.valueOf(params);
assertNotNull(paramObj);
String aValue = paramObj.getParameter("age");
assertEquals("23", aValue);
aValue = paramObj.getParameter("name");
assertEquals("fred", aValue);
}
private WebScriptRequest mockRequest(final Map<String,List<String>> params)
{
final String[] paramNames = params.keySet().toArray(new String[]{});
WebScriptRequest request = mock(WebScriptRequest.class);
when(request.getParameterNames()).thenReturn(paramNames);
when(request.getParameterValues(anyString())).thenAnswer(new Answer<String[]>() {
@Override
public String[] answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return params.get((String) args[0]).toArray(new String[]{});
}
});
return request;
}
} }

View File

@@ -57,6 +57,7 @@ import org.alfresco.rest.framework.tests.api.mocks.Grass;
import org.alfresco.rest.framework.tests.api.mocks.Sheep; import org.alfresco.rest.framework.tests.api.mocks.Sheep;
import org.alfresco.rest.framework.tests.api.mocks3.Flock; import org.alfresco.rest.framework.tests.api.mocks3.Flock;
import org.alfresco.rest.framework.tests.api.mocks3.SlimGoat; import org.alfresco.rest.framework.tests.api.mocks3.SlimGoat;
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.alfresco.rest.framework.webscripts.AbstractResourceWebScript; import org.alfresco.rest.framework.webscripts.AbstractResourceWebScript;
import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper; import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -91,7 +92,7 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
public class SerializeTests extends AbstractContextTest public class SerializeTests extends AbstractContextTest implements RecognizedParamsExtractor
{ {
@Test @Test
@@ -197,7 +198,7 @@ public class SerializeTests extends AbstractContextTest
public void testExpandRelations() throws IOException public void testExpandRelations() throws IOException
{ {
assertNotNull(helper); assertNotNull(helper);
Map<String, BeanPropertiesFilter> rFilter = ResourceWebScriptHelper.getRelationFilter("blacksheep,baaahh"); Map<String, BeanPropertiesFilter> rFilter = getRelationFilter("blacksheep,baaahh");
ExecutionResult res = (ExecutionResult) helper.processAdditionsToTheResponse(mock(WebScriptResponse.class), api,"sheep",ParamsExtender.valueOf(rFilter,"1"),new Farmer("180")); ExecutionResult res = (ExecutionResult) helper.processAdditionsToTheResponse(mock(WebScriptResponse.class), api,"sheep",ParamsExtender.valueOf(rFilter,"1"),new Farmer("180"));
assertNotNull(res); assertNotNull(res);
String out = writeResponse(res); String out = writeResponse(res);
@@ -239,7 +240,7 @@ public class SerializeTests extends AbstractContextTest
public void testExpandRecursiveRelations() throws IOException public void testExpandRecursiveRelations() throws IOException
{ {
ExecutionResult exec1 = new ExecutionResult(new Farmer("180"),null); ExecutionResult exec1 = new ExecutionResult(new Farmer("180"),null);
ExecutionResult exec2 = new ExecutionResult(new Farmer("456"),ResourceWebScriptHelper.getFilter("age")); ExecutionResult exec2 = new ExecutionResult(new Farmer("456"),getFilter("age"));
CollectionWithPagingInfo<ExecutionResult> coll = CollectionWithPagingInfo.asPaged(null, Arrays.asList(exec1, exec2)); CollectionWithPagingInfo<ExecutionResult> coll = CollectionWithPagingInfo.asPaged(null, Arrays.asList(exec1, exec2));
ExecutionResult execResult = new ExecutionResult(new Sheep("ssheep"),null); ExecutionResult execResult = new ExecutionResult(new Sheep("ssheep"),null);
Map<String,Object> related = new HashMap<String,Object>(); Map<String,Object> related = new HashMap<String,Object>();
@@ -436,12 +437,12 @@ public class SerializeTests extends AbstractContextTest
public void testFilter() throws IOException, JSONException public void testFilter() throws IOException, JSONException
{ {
assertNotNull(helper); assertNotNull(helper);
BeanPropertiesFilter theFilter = ResourceWebScriptHelper.getFilter("age"); BeanPropertiesFilter theFilter = getFilter("age");
Object res = new ExecutionResult(new Sheep("bob"),theFilter); Object res = new ExecutionResult(new Sheep("bob"),theFilter);
String out = writeResponse(res); String out = writeResponse(res);
assertTrue("Filter must only return the age.", StringUtils.contains(out, "{\"age\":3}")); assertTrue("Filter must only return the age.", StringUtils.contains(out, "{\"age\":3}"));
theFilter = ResourceWebScriptHelper.getFilter("age,name"); theFilter = getFilter("age,name");
res = new ExecutionResult(new Sheep("bob"),theFilter); res = new ExecutionResult(new Sheep("bob"),theFilter);
out = writeResponse(res); out = writeResponse(res);
JSONObject jsonRsp = new JSONObject(new JSONTokener(out)); JSONObject jsonRsp = new JSONObject(new JSONTokener(out));
@@ -452,8 +453,8 @@ public class SerializeTests extends AbstractContextTest
assertTrue("The age should be 3", entry.getInt("age") == 3); assertTrue("The age should be 3", entry.getInt("age") == 3);
// unit test filter with "include" taking precendence over "fields" filter // unit test filter with "include" taking precendence over "fields" filter
List<String> theInclude = ResourceWebScriptHelper.getIncludeClause("name"); List<String> theInclude = getIncludeClause("name");
theFilter = ResourceWebScriptHelper.getFilter("age", theInclude); theFilter = getFilter("age", theInclude);
res = new ExecutionResult(new Sheep("bob"),theFilter); res = new ExecutionResult(new Sheep("bob"),theFilter);
out = writeResponse(res); out = writeResponse(res);
jsonRsp = new JSONObject(new JSONTokener(out)); jsonRsp = new JSONObject(new JSONTokener(out));
@@ -464,7 +465,7 @@ public class SerializeTests extends AbstractContextTest
assertTrue("The age should be 3", entry.getInt("age") == 3); assertTrue("The age should be 3", entry.getInt("age") == 3);
Api v3 = Api.valueOf(api.getName(), api.getScope().toString(), "3"); Api v3 = Api.valueOf(api.getName(), api.getScope().toString(), "3");
Map<String, BeanPropertiesFilter> relFiler = ResourceWebScriptHelper.getRelationFilter("herd"); Map<String, BeanPropertiesFilter> relFiler = getRelationFilter("herd");
res = helper.processAdditionsToTheResponse(mock(WebScriptResponse.class), v3,"goat",ParamsExtender.valueOf(relFiler, "notUsed"),new SlimGoat()); res = helper.processAdditionsToTheResponse(mock(WebScriptResponse.class), v3,"goat",ParamsExtender.valueOf(relFiler, "notUsed"),new SlimGoat());
out = writeResponse(res); out = writeResponse(res);
jsonRsp = new JSONObject(new JSONTokener(out)); jsonRsp = new JSONObject(new JSONTokener(out));
@@ -476,7 +477,7 @@ public class SerializeTests extends AbstractContextTest
assertEquals("The name should be 'bigun'", "bigun", entry.getString("name")); assertEquals("The name should be 'bigun'", "bigun", entry.getString("name"));
assertTrue("The quantity should be 56", entry.getInt("quantity") == 56); assertTrue("The quantity should be 56", entry.getInt("quantity") == 56);
relFiler = ResourceWebScriptHelper.getRelationFilter("herd(name)"); relFiler = getRelationFilter("herd(name)");
res = helper.processAdditionsToTheResponse(mock(WebScriptResponse.class), v3,"goat",ParamsExtender.valueOf(relFiler, "notUsed"),new SlimGoat()); res = helper.processAdditionsToTheResponse(mock(WebScriptResponse.class), v3,"goat",ParamsExtender.valueOf(relFiler, "notUsed"),new SlimGoat());
out = writeResponse(res); out = writeResponse(res);
assertTrue("Must return only the herd name.", StringUtils.contains(out, "{\"name\":\"bigun\"}")); assertTrue("Must return only the herd name.", StringUtils.contains(out, "{\"name\":\"bigun\"}"));

View File

@@ -37,16 +37,17 @@ import org.alfresco.rest.framework.resource.parameters.where.InvalidQueryExcepti
import org.alfresco.rest.framework.resource.parameters.where.Query; import org.alfresco.rest.framework.resource.parameters.where.Query;
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper; import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper.WalkerCallbackAdapter; import org.alfresco.rest.framework.resource.parameters.where.QueryHelper.WalkerCallbackAdapter;
import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper; import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.antlr.runtime.tree.CommonTree; import org.antlr.runtime.tree.CommonTree;
import org.junit.Test; import org.junit.Test;
public class WhereTests { public class WhereTests implements RecognizedParamsExtractor
{
@Test @Test
public void basicTest() throws IOException { public void basicTest() throws IOException {
Query theQuery = ResourceWebScriptHelper.getWhereClause(" ( fred > g ) "); Query theQuery = getWhereClause(" ( fred > g ) ");
CommonTree ast = theQuery.getTree(); CommonTree ast = theQuery.getTree();
//check AST structure //check AST structure
assertEquals(WhereClauseParser.GREATERTHAN, ast.getType()); assertEquals(WhereClauseParser.GREATERTHAN, ast.getType());
@@ -57,13 +58,13 @@ public class WhereTests {
@Test @Test
public void existClauseTest() public void existClauseTest()
{ {
Query theQuery = ResourceWebScriptHelper.getWhereClause(null); Query theQuery = getWhereClause(null);
assertNotNull(theQuery); assertNotNull(theQuery);
assertTrue("Null passed in so nothing to theQuery.", theQuery.getTree() == null); assertTrue("Null passed in so nothing to theQuery.", theQuery.getTree() == null);
try try
{ {
theQuery = ResourceWebScriptHelper.getWhereClause("fred"); theQuery = getWhereClause("fred");
fail("Should throw an InvalidQueryException"); fail("Should throw an InvalidQueryException");
} }
catch (InvalidQueryException error) catch (InvalidQueryException error)
@@ -73,7 +74,7 @@ public class WhereTests {
try try
{ {
theQuery = ResourceWebScriptHelper.getWhereClause("(noClosingBracket"); theQuery = getWhereClause("(noClosingBracket");
fail("Should throw an InvalidQueryException"); fail("Should throw an InvalidQueryException");
} }
catch (InvalidQueryException error) catch (InvalidQueryException error)
@@ -83,7 +84,7 @@ public class WhereTests {
try try
{ {
theQuery = ResourceWebScriptHelper.getWhereClause("noOpeningBracket)"); theQuery = getWhereClause("noOpeningBracket)");
fail("Should throw an InvalidQueryException"); fail("Should throw an InvalidQueryException");
} }
catch (InvalidQueryException error) catch (InvalidQueryException error)
@@ -94,7 +95,7 @@ public class WhereTests {
try try
{ {
theQuery = ResourceWebScriptHelper.getWhereClause("(EXISTS(target.file))"); theQuery = getWhereClause("(EXISTS(target.file))");
fail("Should throw an InvalidQueryException"); fail("Should throw an InvalidQueryException");
} }
catch (InvalidQueryException error) catch (InvalidQueryException error)
@@ -102,34 +103,34 @@ public class WhereTests {
//this is correct //this is correct
} }
theQuery = ResourceWebScriptHelper.getWhereClause("(exists(/target/file))"); theQuery = getWhereClause("(exists(/target/file))");
assertExistsPropertyEquals("/target/file", theQuery, false); assertExistsPropertyEquals("/target/file", theQuery, false);
theQuery = ResourceWebScriptHelper.getWhereClause("(EXISTS(b))"); theQuery = getWhereClause("(EXISTS(b))");
assertExistsPropertyEquals("b", theQuery, false); assertExistsPropertyEquals("b", theQuery, false);
theQuery = ResourceWebScriptHelper.getWhereClause(" ( EXISTS ( whitespace ) ) "); theQuery = getWhereClause(" ( EXISTS ( whitespace ) ) ");
assertExistsPropertyEquals("whitespace", theQuery, false); assertExistsPropertyEquals("whitespace", theQuery, false);
theQuery = ResourceWebScriptHelper.getWhereClause("(exists ( folder ))"); theQuery = getWhereClause("(exists ( folder ))");
assertExistsPropertyEquals("folder", theQuery, false); assertExistsPropertyEquals("folder", theQuery, false);
theQuery = ResourceWebScriptHelper.getWhereClause("(NOT EXISTS(b))"); theQuery = getWhereClause("(NOT EXISTS(b))");
assertExistsPropertyEquals("b", theQuery, true); assertExistsPropertyEquals("b", theQuery, true);
theQuery = ResourceWebScriptHelper.getWhereClause(" (NOT EXISTS(b))"); theQuery = getWhereClause(" (NOT EXISTS(b))");
assertExistsPropertyEquals("b", theQuery, true); assertExistsPropertyEquals("b", theQuery, true);
theQuery = ResourceWebScriptHelper.getWhereClause("( NOT EXISTS(b))"); theQuery = getWhereClause("( NOT EXISTS(b))");
assertExistsPropertyEquals("b", theQuery, true); assertExistsPropertyEquals("b", theQuery, true);
theQuery = ResourceWebScriptHelper.getWhereClause(" ( NOT EXISTS(b))"); theQuery = getWhereClause(" ( NOT EXISTS(b))");
assertExistsPropertyEquals("b", theQuery, true); assertExistsPropertyEquals("b", theQuery, true);
try try
{ {
theQuery = ResourceWebScriptHelper.getWhereClause("(exists folder)"); theQuery = getWhereClause("(exists folder)");
fail("Should throw an InvalidQueryException, 'folder' should have a bracket around it"); fail("Should throw an InvalidQueryException, 'folder' should have a bracket around it");
} }
catch (InvalidQueryException error) catch (InvalidQueryException error)
@@ -137,7 +138,7 @@ public class WhereTests {
//this is correct //this is correct
} }
theQuery = ResourceWebScriptHelper.getWhereClause("(EXISTS(/target/folder) AND NOT EXISTS(/target/site))"); theQuery = getWhereClause("(EXISTS(/target/folder) AND NOT EXISTS(/target/site))");
assertNotNull(theQuery); assertNotNull(theQuery);
CommonTree tree = theQuery.getTree(); CommonTree tree = theQuery.getTree();
assertNotNull(tree); assertNotNull(tree);
@@ -166,7 +167,7 @@ public class WhereTests {
try try
{ {
theQuery = ResourceWebScriptHelper.getWhereClause("(EXISTS(/target/folder)OR EXISTS(/target/site))"); theQuery = getWhereClause("(EXISTS(/target/folder)OR EXISTS(/target/site))");
fail("Should throw an InvalidQueryException, the OR should have a space before it."); fail("Should throw an InvalidQueryException, the OR should have a space before it.");
} }
catch (InvalidQueryException error) catch (InvalidQueryException error)
@@ -174,7 +175,7 @@ public class WhereTests {
//this is correct //this is correct
} }
theQuery = ResourceWebScriptHelper.getWhereClause("(NOT EXISTS(/target/folder) OR EXISTS(/target/site))"); theQuery = getWhereClause("(NOT EXISTS(/target/folder) OR EXISTS(/target/site))");
QueryHelper.walk(theQuery, new WalkerCallbackAdapter(){ QueryHelper.walk(theQuery, new WalkerCallbackAdapter(){
@Override @Override
public void exists(String propertyName, boolean negated) { public void exists(String propertyName, boolean negated) {
@@ -196,7 +197,7 @@ public class WhereTests {
}); });
theQuery = ResourceWebScriptHelper.getWhereClause("(EXISTS ( /target/folder ) OR EXISTS( /target/site ) )"); theQuery = getWhereClause("(EXISTS ( /target/folder ) OR EXISTS( /target/site ) )");
QueryHelper.walk(theQuery, new WalkerCallbackAdapter(){ QueryHelper.walk(theQuery, new WalkerCallbackAdapter(){
int i=0; int i=0;
@Override @Override
@@ -220,7 +221,7 @@ public class WhereTests {
}); });
theQuery = ResourceWebScriptHelper.getWhereClause("(EXISTS(target/file) AND EXISTS(target/folder) AND EXISTS(target/site))"); theQuery = getWhereClause("(EXISTS(target/file) AND EXISTS(target/folder) AND EXISTS(target/site))");
QueryHelper.walk(theQuery, new WalkerCallbackAdapter(){ QueryHelper.walk(theQuery, new WalkerCallbackAdapter(){
int i=0; int i=0;
@Override @Override
@@ -254,25 +255,25 @@ public class WhereTests {
@Test @Test
public void inClauseTest() public void inClauseTest()
{ {
Query theQuery = ResourceWebScriptHelper.getWhereClause("( dueAt in (5,8) )"); Query theQuery = getWhereClause("( dueAt in (5,8) )");
inChecks(theQuery, "dueAt", "5", "8"); inChecks(theQuery, "dueAt", "5", "8");
theQuery = ResourceWebScriptHelper.getWhereClause("( fred/bloggs in (head,elbow) )"); theQuery = getWhereClause("( fred/bloggs in (head,elbow) )");
inChecks(theQuery, "fred/bloggs", "head", "elbow"); inChecks(theQuery, "fred/bloggs", "head", "elbow");
theQuery = ResourceWebScriptHelper.getWhereClause("( nextOne in (5,8,4) )"); theQuery = getWhereClause("( nextOne in (5,8,4) )");
inChecks(theQuery, "nextOne", "5", "8", "4"); inChecks(theQuery, "nextOne", "5", "8", "4");
theQuery = ResourceWebScriptHelper.getWhereClause("( nextOne in (5,56,fred) )"); theQuery = getWhereClause("( nextOne in (5,56,fred) )");
inChecks(theQuery, "nextOne", "5", "56", "fred"); inChecks(theQuery, "nextOne", "5", "56", "fred");
theQuery = ResourceWebScriptHelper.getWhereClause("( nextOne in (5,56,'fred&') )"); theQuery = getWhereClause("( nextOne in (5,56,'fred&') )");
inChecks(theQuery, "nextOne", "5", "56", "fred&"); inChecks(theQuery, "nextOne", "5", "56", "fred&");
theQuery = ResourceWebScriptHelper.getWhereClause("( nextOne in ('me , you',56,egg) )"); theQuery = getWhereClause("( nextOne in ('me , you',56,egg) )");
inChecks(theQuery, "nextOne", "me , you", "56", "egg"); inChecks(theQuery, "nextOne", "me , you", "56", "egg");
theQuery = ResourceWebScriptHelper.getWhereClause("( NOT nextOne in (5,56,fred, king, kong, 'fred\\'^') )"); theQuery = getWhereClause("( NOT nextOne in (5,56,fred, king, kong, 'fred\\'^') )");
CommonTree tree = theQuery.getTree(); CommonTree tree = theQuery.getTree();
assertNotNull(tree); assertNotNull(tree);
QueryHelper.walk(theQuery, new WalkerCallbackAdapter(){ QueryHelper.walk(theQuery, new WalkerCallbackAdapter(){
@@ -293,15 +294,15 @@ public class WhereTests {
@Test @Test
public void betweenClauseTest() public void betweenClauseTest()
{ {
Query theQuery = ResourceWebScriptHelper.getWhereClause("( dueAt between (5,8) )"); Query theQuery = getWhereClause("( dueAt between (5,8) )");
betweenChecks(theQuery, "dueAt", "5", "8"); betweenChecks(theQuery, "dueAt", "5", "8");
theQuery = ResourceWebScriptHelper.getWhereClause("( fred/bloggs between (head,elbow) )"); theQuery = getWhereClause("( fred/bloggs between (head,elbow) )");
betweenChecks(theQuery, "fred/bloggs", "head", "elbow"); betweenChecks(theQuery, "fred/bloggs", "head", "elbow");
try try
{ {
theQuery = ResourceWebScriptHelper.getWhereClause("( nextOne between (5,8,4) )"); theQuery = getWhereClause("( nextOne between (5,8,4) )");
fail("Should throw an InvalidQueryException, between can have only two values."); fail("Should throw an InvalidQueryException, between can have only two values.");
} }
catch (InvalidQueryException error) catch (InvalidQueryException error)
@@ -311,7 +312,7 @@ public class WhereTests {
try try
{ {
theQuery = ResourceWebScriptHelper.getWhereClause("( nextOne between 5,8 )"); theQuery = getWhereClause("( nextOne between 5,8 )");
fail("Should throw an InvalidQueryException, Need brackets."); fail("Should throw an InvalidQueryException, Need brackets.");
} }
catch (InvalidQueryException error) catch (InvalidQueryException error)
@@ -319,7 +320,7 @@ public class WhereTests {
//this is correct //this is correct
} }
theQuery = ResourceWebScriptHelper.getWhereClause("(NOT dueAt between (5,8) AND nextOne between (green,blue))"); theQuery = getWhereClause("(NOT dueAt between (5,8) AND nextOne between (green,blue))");
QueryHelper.walk(theQuery, new WalkerCallbackAdapter(){ QueryHelper.walk(theQuery, new WalkerCallbackAdapter(){
@Override @Override
public void between(String property, String firstVal, String secondVal, boolean negated) { public void between(String property, String firstVal, String secondVal, boolean negated) {
@@ -349,18 +350,18 @@ public class WhereTests {
@Test @Test
public void matchesClauseTest() public void matchesClauseTest()
{ {
Query theQuery = ResourceWebScriptHelper.getWhereClause("(fred matches(bob))"); Query theQuery = getWhereClause("(fred matches(bob))");
matchesChecks(theQuery, "fred", "bob"); matchesChecks(theQuery, "fred", "bob");
theQuery = ResourceWebScriptHelper.getWhereClause("( king/kong/hair/shoulders/knees/toes matches ('fred%') )"); theQuery = getWhereClause("( king/kong/hair/shoulders/knees/toes matches ('fred%') )");
matchesChecks(theQuery, "king/kong/hair/shoulders/knees/toes", "fred%"); matchesChecks(theQuery, "king/kong/hair/shoulders/knees/toes", "fred%");
theQuery = ResourceWebScriptHelper.getWhereClause("( niceone matches (bob) )"); theQuery = getWhereClause("( niceone matches (bob) )");
matchesChecks(theQuery, "niceone", "bob"); matchesChecks(theQuery, "niceone", "bob");
try try
{ {
theQuery = ResourceWebScriptHelper.getWhereClause("( fred matches bob )"); theQuery = getWhereClause("( fred matches bob )");
fail("Should throw an InvalidQueryException, Need brackets."); fail("Should throw an InvalidQueryException, Need brackets.");
} }
catch (InvalidQueryException error) catch (InvalidQueryException error)
@@ -373,25 +374,25 @@ public class WhereTests {
@Test @Test
public void comparisonClauseTest() public void comparisonClauseTest()
{ {
Query theQuery = ResourceWebScriptHelper.getWhereClause("( dueAt > '12.04.345' )"); Query theQuery = getWhereClause("( dueAt > '12.04.345' )");
int comparisonOperator = WhereClauseParser.GREATERTHAN; int comparisonOperator = WhereClauseParser.GREATERTHAN;
comparisonChecks(theQuery, comparisonOperator, "dueAt", "12.04.345"); comparisonChecks(theQuery, comparisonOperator, "dueAt", "12.04.345");
theQuery = ResourceWebScriptHelper.getWhereClause("( dueAt >= '12.04.345' )"); theQuery = getWhereClause("( dueAt >= '12.04.345' )");
comparisonOperator = WhereClauseParser.GREATERTHANOREQUALS; comparisonOperator = WhereClauseParser.GREATERTHANOREQUALS;
comparisonChecks(theQuery, comparisonOperator, "dueAt", "12.04.345"); comparisonChecks(theQuery, comparisonOperator, "dueAt", "12.04.345");
theQuery = ResourceWebScriptHelper.getWhereClause("( dueAt < '12.04.345' )"); theQuery = getWhereClause("( dueAt < '12.04.345' )");
comparisonOperator = WhereClauseParser.LESSTHAN; comparisonOperator = WhereClauseParser.LESSTHAN;
comparisonChecks(theQuery, comparisonOperator, "dueAt", "12.04.345"); comparisonChecks(theQuery, comparisonOperator, "dueAt", "12.04.345");
theQuery = ResourceWebScriptHelper.getWhereClause("( dueAt <= '12.04.345' )"); theQuery = getWhereClause("( dueAt <= '12.04.345' )");
comparisonOperator = WhereClauseParser.LESSTHANOREQUALS; comparisonOperator = WhereClauseParser.LESSTHANOREQUALS;
comparisonChecks(theQuery, comparisonOperator, "dueAt", "12.04.345"); comparisonChecks(theQuery, comparisonOperator, "dueAt", "12.04.345");
try try
{ {
theQuery = ResourceWebScriptHelper.getWhereClause("( Fred/Bloggs = %$NICE&* )"); theQuery = getWhereClause("( Fred/Bloggs = %$NICE&* )");
fail("Should throw an InvalidQueryException, needs single quotes"); fail("Should throw an InvalidQueryException, needs single quotes");
} }
catch (InvalidQueryException error) catch (InvalidQueryException error)
@@ -399,13 +400,13 @@ public class WhereTests {
//this is correct //this is correct
} }
theQuery = ResourceWebScriptHelper.getWhereClause("( Fred/Bloggs = '%$NICE&*' )"); theQuery = getWhereClause("( Fred/Bloggs = '%$NICE&*' )");
comparisonOperator = WhereClauseParser.EQUALS; comparisonOperator = WhereClauseParser.EQUALS;
comparisonChecks(theQuery, comparisonOperator, "Fred/Bloggs", "%$NICE&*"); comparisonChecks(theQuery, comparisonOperator, "Fred/Bloggs", "%$NICE&*");
try try
{ {
theQuery = ResourceWebScriptHelper.getWhereClause("( Ken = (456) )"); theQuery = getWhereClause("( Ken = (456) )");
fail("Should throw an InvalidQueryException, needs single quotes no brackets"); fail("Should throw an InvalidQueryException, needs single quotes no brackets");
} }
catch (InvalidQueryException error) catch (InvalidQueryException error)
@@ -413,15 +414,15 @@ public class WhereTests {
//this is correct //this is correct
} }
theQuery = ResourceWebScriptHelper.getWhereClause("( Ken = '456' )"); theQuery = getWhereClause("( Ken = '456' )");
comparisonOperator = WhereClauseParser.EQUALS; comparisonOperator = WhereClauseParser.EQUALS;
comparisonChecks(theQuery, comparisonOperator, "Ken", "456"); comparisonChecks(theQuery, comparisonOperator, "Ken", "456");
theQuery = ResourceWebScriptHelper.getWhereClause("( DogHouse = 'Cat\\\'s House' )"); theQuery = getWhereClause("( DogHouse = 'Cat\\\'s House' )");
comparisonOperator = WhereClauseParser.EQUALS; comparisonOperator = WhereClauseParser.EQUALS;
comparisonChecks(theQuery, comparisonOperator, "DogHouse", "Cat\\\'s House"); comparisonChecks(theQuery, comparisonOperator, "DogHouse", "Cat\\\'s House");
theQuery = ResourceWebScriptHelper.getWhereClause("( KING_KONG >= 'Mighty Mouse' )"); theQuery = getWhereClause("( KING_KONG >= 'Mighty Mouse' )");
comparisonOperator = WhereClauseParser.GREATERTHANOREQUALS; comparisonOperator = WhereClauseParser.GREATERTHANOREQUALS;
comparisonChecks(theQuery, comparisonOperator, "KING_KONG", "Mighty Mouse"); comparisonChecks(theQuery, comparisonOperator, "KING_KONG", "Mighty Mouse");
@@ -442,25 +443,25 @@ public class WhereTests {
@Test @Test
public void getChildrenTests() public void getChildrenTests()
{ {
Query theQuery = ResourceWebScriptHelper.getWhereClause("(fred matches(bob))"); Query theQuery = getWhereClause("(fred matches(bob))");
assertNotNull(theQuery); assertNotNull(theQuery);
CommonTree tree = theQuery.getTree(); CommonTree tree = theQuery.getTree();
assertNotNull(tree); assertNotNull(tree);
assertTrue(2 == QueryHelper.getChildren(tree).size()); assertTrue(2 == QueryHelper.getChildren(tree).size());
theQuery = ResourceWebScriptHelper.getWhereClause("( dueAt between (5,8) )"); theQuery = getWhereClause("( dueAt between (5,8) )");
assertNotNull(theQuery); assertNotNull(theQuery);
tree = theQuery.getTree(); tree = theQuery.getTree();
assertNotNull(tree); assertNotNull(tree);
assertTrue(3 == QueryHelper.getChildren(tree).size()); assertTrue(3 == QueryHelper.getChildren(tree).size());
theQuery = ResourceWebScriptHelper.getWhereClause("(NOT EXISTS(b))"); theQuery = getWhereClause("(NOT EXISTS(b))");
assertNotNull(theQuery); assertNotNull(theQuery);
tree = theQuery.getTree(); tree = theQuery.getTree();
assertNotNull(tree); assertNotNull(tree);
assertTrue(1 == QueryHelper.getChildren(tree).size()); assertTrue(1 == QueryHelper.getChildren(tree).size());
theQuery = ResourceWebScriptHelper.getWhereClause("(EXISTS(/target/folder) AND EXISTS(/target/site))"); theQuery = getWhereClause("(EXISTS(/target/folder) AND EXISTS(/target/site))");
assertNotNull(theQuery); assertNotNull(theQuery);
tree = theQuery.getTree(); tree = theQuery.getTree();
assertNotNull(tree); assertNotNull(tree);

View File

@@ -39,6 +39,7 @@ import static org.mockito.Mockito.when;
import org.alfresco.rest.framework.resource.content.ContentInfo; import org.alfresco.rest.framework.resource.content.ContentInfo;
import org.alfresco.rest.framework.resource.content.ContentInfoImpl; import org.alfresco.rest.framework.resource.content.ContentInfoImpl;
import org.alfresco.rest.framework.tools.ApiAssistant; import org.alfresco.rest.framework.tools.ApiAssistant;
import org.alfresco.rest.framework.tools.ResponseWriter;
import org.alfresco.rest.framework.webscripts.AbstractResourceWebScript; import org.alfresco.rest.framework.webscripts.AbstractResourceWebScript;
import org.alfresco.rest.framework.webscripts.ApiWebScript; import org.alfresco.rest.framework.webscripts.ApiWebScript;
import org.alfresco.rest.framework.webscripts.ResourceWebScriptDelete; import org.alfresco.rest.framework.webscripts.ResourceWebScriptDelete;
@@ -70,17 +71,17 @@ public class WithResponseTest
@Test @Test
public void testDefaults() throws Exception public void testDefaults() throws Exception
{ {
WithResponse callBack = new WithResponse(Status.STATUS_OK,ApiAssistant.DEFAULT_JSON_CONTENT, ApiAssistant.CACHE_NEVER); WithResponse callBack = new WithResponse(Status.STATUS_OK, ResponseWriter.DEFAULT_JSON_CONTENT, ResponseWriter.CACHE_NEVER);
assertEquals(Status.STATUS_OK, callBack.getStatus()); assertEquals(Status.STATUS_OK, callBack.getStatus());
assertEquals(ApiAssistant.DEFAULT_JSON_CONTENT, callBack.getContentInfo()); assertEquals(ResponseWriter.DEFAULT_JSON_CONTENT, callBack.getContentInfo());
assertEquals(ApiAssistant.CACHE_NEVER, callBack.getCache()); assertEquals(ResponseWriter.CACHE_NEVER, callBack.getCache());
assertTrue(callBack.getHeaders().isEmpty()); assertTrue(callBack.getHeaders().isEmpty());
} }
@Test @Test
public void testSetHeader() throws Exception public void testSetHeader() throws Exception
{ {
WithResponse callBack = new WithResponse(Status.STATUS_OK,ApiAssistant.DEFAULT_JSON_CONTENT, ApiAssistant.CACHE_NEVER); WithResponse callBack = new WithResponse(Status.STATUS_OK,ResponseWriter.DEFAULT_JSON_CONTENT, ResponseWriter.CACHE_NEVER);
callBack.setHeader("king", "can"); callBack.setHeader("king", "can");
callBack.setHeader("king", "kong"); callBack.setHeader("king", "kong");
assertTrue(callBack.getHeaders().size() == 1); assertTrue(callBack.getHeaders().size() == 1);
@@ -92,7 +93,7 @@ public class WithResponseTest
@Test @Test
public void testAddHeader() throws Exception public void testAddHeader() throws Exception
{ {
WithResponse callBack = new WithResponse(Status.STATUS_OK,ApiAssistant.DEFAULT_JSON_CONTENT, ApiAssistant.CACHE_NEVER); WithResponse callBack = new WithResponse(Status.STATUS_OK,ResponseWriter.DEFAULT_JSON_CONTENT, ResponseWriter.CACHE_NEVER);
callBack.addHeader("king", "can"); callBack.addHeader("king", "can");
callBack.addHeader("king", "kong"); callBack.addHeader("king", "kong");
assertTrue(callBack.getHeaders().size() == 1); assertTrue(callBack.getHeaders().size() == 1);
@@ -105,7 +106,7 @@ public class WithResponseTest
@Test @Test
public void testSetters() throws Exception public void testSetters() throws Exception
{ {
WithResponse callBack = new WithResponse(Status.STATUS_OK, ApiAssistant.DEFAULT_JSON_CONTENT, ApiAssistant.CACHE_NEVER); WithResponse callBack = new WithResponse(Status.STATUS_OK, ResponseWriter.DEFAULT_JSON_CONTENT, ResponseWriter.CACHE_NEVER);
callBack.setStatus(Status.STATUS_GONE); callBack.setStatus(Status.STATUS_GONE);
Cache myCache = new Cache(new Description.RequiredCache() Cache myCache = new Cache(new Description.RequiredCache()
{ {
@@ -142,7 +143,7 @@ public class WithResponseTest
{ {
AbstractResourceWebScript responseWriter = new ResourceWebScriptDelete(); AbstractResourceWebScript responseWriter = new ResourceWebScriptDelete();
responseWriter.setAssistant(new ApiAssistant()); responseWriter.setAssistant(new ApiAssistant());
WithResponse wr = new WithResponse(Status.STATUS_OK, ApiAssistant.DEFAULT_JSON_CONTENT, ApiAssistant.CACHE_NEVER); WithResponse wr = new WithResponse(Status.STATUS_OK, ResponseWriter.DEFAULT_JSON_CONTENT, ResponseWriter.CACHE_NEVER);
WebScriptResponse response = mock(WebScriptResponse.class); WebScriptResponse response = mock(WebScriptResponse.class);

View File

@@ -0,0 +1,539 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.framework.tools;
import static org.junit.Assert.*;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.jacksonextensions.BeanPropertiesFilter;
import org.alfresco.rest.framework.resource.parameters.InvalidSelectException;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.resource.parameters.SortColumn;
import org.alfresco.rest.framework.tests.core.ParamsExtender;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.extensions.webscripts.WebScriptRequest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Test the RecognizedParamsExtractor
*
* @author Gethin James
*/
public class RecognizedParamsExtractorTest implements RecognizedParamsExtractor
{
@Test
public void getFilterTest()
{
BeanPropertiesFilter theFilter = getFilter(null);
assertNotNull(theFilter);
assertTrue("Null passed in so must return the default BeanPropertiesFilter.ALLOW_ALL class", BeanPropertiesFilter.AllProperties.class.equals(theFilter.getClass()));
theFilter = getFilter("bob");
assertNotNull(theFilter);
assertTrue("Must return the BeanPropertiesFilter class", theFilter instanceof BeanPropertiesFilter);
theFilter = getFilter("50,fred,b.z");
assertNotNull(theFilter);
assertTrue("Must return the BeanPropertiesFilter class", theFilter instanceof BeanPropertiesFilter);
theFilter = getFilter("50,fred,");
assertNotNull(theFilter);
assertTrue("Must return the BeanPropertiesFilter class", theFilter instanceof BeanPropertiesFilter);
}
@Test
public void getSortingTest()
{
List<SortColumn> theSort = getSort(null);
assertNotNull(theSort);
assertTrue("Null passed in so empty sort list should be returned.", theSort.isEmpty());
theSort = getSort("name ASC");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc);
theSort = getSort("name ");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc);
theSort = getSort("name DESC");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(!theSort.get(0).asc); //desc
theSort = getSort("name desc");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(!theSort.get(0).asc); //desc
theSort = getSort("name,age desc");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 2);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc);
assertEquals("age", theSort.get(1).column);
assertTrue(!theSort.get(1).asc); //desc
theSort = getSort(" name, age desc");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 2);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc);
assertEquals("age", theSort.get(1).column);
assertTrue(!theSort.get(1).asc); //desc
theSort = getSort("name DESC, age desc");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 2);
assertEquals("name", theSort.get(0).column);
assertTrue(!theSort.get(0).asc); //desc
assertEquals("age", theSort.get(1).column);
assertTrue(!theSort.get(1).asc); //desc
theSort = getSort("age Desc, name Asc");
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 2);
assertEquals("age", theSort.get(0).column);
assertTrue(!theSort.get(0).asc); //desc
assertEquals("name", theSort.get(1).column);
assertTrue(theSort.get(1).asc);
theSort = getSort("name des"); //invalid, should be desc
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc); //Defaults to ascending because the sort order was invalid
theSort = getSort("name asc,"); //invalid, should be desc
assertNotNull(theSort);
assertTrue("Must have a value for column: NAME", !theSort.isEmpty());
assertTrue(theSort.size() == 1);
assertEquals("name", theSort.get(0).column);
assertTrue(theSort.get(0).asc);
}
@Test
public void getIncludeClauseTest()
{
getClauseTest("include");
}
@Test
public void getSelectClauseTest()
{
getClauseTest("select");
}
// at the moment select and include are parsed the same way, hence common/shared test
private void getClauseTest(String paramName)
{
List<String> theClause = getCorrectClause(paramName, null);
assertNotNull(theClause);
assertFalse("Null passed in so nothing in the "+paramName, theClause.size() > 0);
try
{
theClause = getCorrectClause(paramName, ",,,");
fail("Should throw an InvalidSelectException");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getCorrectClause(paramName, "(,,,");
fail("Should throw an InvalidSelectException");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getCorrectClause(paramName, "(,,,)");
fail("Should throw an InvalidSelectException");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getCorrectClause(paramName, "x/,z");
fail("Should throw an InvalidSelectException");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getCorrectClause(paramName, "/x'n,/z");
fail("Should throw an InvalidSelectException");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getCorrectClause(paramName, "/foo/0");
fail("Should throw an InvalidSelectException. Legal identifiers must start with a letter not zero");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getCorrectClause(paramName, "/");
fail("Should throw an InvalidSelectException. No identifier specified.");
}
catch (InvalidSelectException error)
{
//this is correct
}
try
{
theClause = getCorrectClause(paramName, "path, isLink");
fail("Should throw an InvalidSelectException. No identifier specified.");
}
catch (InvalidSelectException error)
{
//this is correct
}
theClause = getCorrectClause(paramName, "king/kong");
assertTrue("has a valid "+paramName, theClause.size() == 1);
assertEquals("king/kong",theClause.get(0));
theClause = getCorrectClause(paramName, "x,y");
assertTrue("has a valid "+paramName, theClause.size() == 2);
assertEquals("x",theClause.get(0));
assertEquals("y",theClause.get(1));
theClause = getCorrectClause(paramName, "x,/z");
assertTrue("has a valid "+paramName, theClause.size() == 2);
assertEquals("x",theClause.get(0));
assertEquals("/z",theClause.get(1));
theClause = getCorrectClause(paramName, "/b");
assertTrue("has a valid "+paramName, theClause.size() == 1);
assertEquals("/b",theClause.get(0));
theClause = getCorrectClause(paramName, "/be,/he");
assertTrue("has a valid "+paramName, theClause.size() == 2);
assertEquals("/be",theClause.get(0));
assertEquals("/he",theClause.get(1));
theClause = getCorrectClause(paramName, "/king/kong");
assertTrue("has a valid "+paramName, theClause.size() == 1);
assertEquals("/king/kong",theClause.get(0));
theClause = getCorrectClause(paramName, "/name,/person/age");
assertTrue("has a valid "+paramName, theClause.size() == 2);
assertEquals("/name",theClause.get(0));
assertEquals("/person/age",theClause.get(1));
theClause = getCorrectClause(paramName, "/foo");
assertTrue("has a valid select",theClause.size() == 1);
assertEquals("/foo",theClause.get(0));
theClause = getCorrectClause(paramName, "/foo/anArray/x");
assertTrue("has a valid "+paramName, theClause.size() == 1);
assertEquals("/foo/anArray/x",theClause.get(0));
theClause = getCorrectClause(paramName, "/foo/anArray/x,/person/age,/eggs/bacon/sausage,/p");
assertTrue("has a valid "+paramName, theClause.size() == 4);
assertEquals("/foo/anArray/x",theClause.get(0));
assertEquals("/person/age",theClause.get(1));
assertEquals("/eggs/bacon/sausage",theClause.get(2));
assertEquals("/p",theClause.get(3));
theClause = getCorrectClause(paramName, "/foo/_bar ");
assertTrue("has a valid "+paramName, theClause.size() == 1);
assertEquals("/foo/_bar",theClause.get(0));
}
private List<String> getCorrectClause(String paramName, String paramValue)
{
if (paramName.equalsIgnoreCase("include"))
{
return getIncludeClause(paramValue);
}
else if (paramName.equalsIgnoreCase("select"))
{
return getSelectClause(paramValue);
}
fail("Unexpected clause: "+paramName);
return null;
}
@Test
public void getRelationFilterTest()
{
Map<String, BeanPropertiesFilter> theFilter = getRelationFilter(null);
assertNotNull(theFilter);
assertTrue("Null passed in so nothing to filter.",theFilter.isEmpty());
theFilter = getRelationFilter("bob");
assertNotNull(theFilter);
assertTrue("Must be a single relationship", theFilter.size() == 1);
assertTrue("Must be a single relationship called bob", theFilter.containsKey("bob"));
BeanPropertiesFilter aFilter = theFilter.get("bob");
assertTrue("No bean properties specified so need a BeanPropertiesFilter.ALLOW_ALL class", BeanPropertiesFilter.AllProperties.class.equals(aFilter.getClass()));
theFilter = getRelationFilter("bob,hope");
assertNotNull(theFilter);
assertTrue("Must be a two relationships", theFilter.size() == 2);
assertTrue("Must have hope.", theFilter.containsKey("hope"));
aFilter = theFilter.get("hope");
assertTrue("No bean properties specified so need a BeanPropertiesFilter.ALLOW_ALL class", BeanPropertiesFilter.AllProperties.class.equals(aFilter.getClass()));
theFilter = getRelationFilter("bob(name),hope");
assertNotNull(theFilter);
assertTrue("Must be a two relationships", theFilter.size() == 2);
assertTrue("Must have bob.", theFilter.containsKey("bob"));
aFilter = theFilter.get("bob");
assertTrue("Bean properties specified so must be an BeanPropertiesFilter class", BeanPropertiesFilter.class.equals(aFilter.getClass()));
theFilter = getRelationFilter("bob,hope(age,name)");
assertNotNull(theFilter);
assertTrue("Must be a two relationships", theFilter.size() == 2);
aFilter = theFilter.get("bob");
assertTrue("No bean properties specified so need a BeanPropertiesFilter.ALLOW_ALL class", BeanPropertiesFilter.AllProperties.class.equals(aFilter.getClass()));
aFilter = theFilter.get("hope");
assertTrue("Bean properties specified so must be an BeanPropertiesFilter class", BeanPropertiesFilter.class.equals(aFilter.getClass()));
theFilter = getRelationFilter("bob(name,age),nohope,hope(height,width)");
assertNotNull(theFilter);
assertTrue("Must be a three relationships", theFilter.size() == 3);
aFilter = theFilter.get("bob");
assertTrue("Bean properties specified so must be an BeanPropertiesFilter class", BeanPropertiesFilter.class.equals(aFilter.getClass()));
aFilter = theFilter.get("nohope");
assertTrue("No bean properties specified so need a ReturnAllBeanProperties class", BeanPropertiesFilter.AllProperties.class.equals(aFilter.getClass()));
aFilter = theFilter.get("hope");
assertTrue("Bean properties specified so must be an BeanPropertiesFilter class", BeanPropertiesFilter.class.equals(aFilter.getClass()));
}
@Test
public void findPagingTest()
{
WebScriptRequest request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("34");
when(request.getParameter("maxItems")).thenReturn("50");
Paging pagin = findPaging(request);
assertNotNull(pagin);
assertTrue(pagin.getSkipCount() == 34);
assertTrue(pagin.getMaxItems() == 50);
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn(null);
when(request.getParameter("maxItems")).thenReturn(null);
pagin = findPaging(request);
assertNotNull(pagin);
assertTrue(pagin.getSkipCount() == Paging.DEFAULT_SKIP_COUNT);
assertTrue(pagin.getMaxItems() == Paging.DEFAULT_MAX_ITEMS);
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("55");
pagin = findPaging(request);
assertNotNull(pagin);
assertTrue(pagin.getSkipCount() == 55);
assertTrue(pagin.getMaxItems() == Paging.DEFAULT_MAX_ITEMS);
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn(null);
when(request.getParameter("maxItems")).thenReturn("45");
pagin = findPaging(request);
assertNotNull(pagin);
assertTrue(pagin.getMaxItems() == 45);
assertTrue(pagin.getSkipCount() == Paging.DEFAULT_SKIP_COUNT);
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("apple");
when(request.getParameter("maxItems")).thenReturn("pear");
try
{
pagin = findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("0");
when(request.getParameter("maxItems")).thenReturn("0");
try
{
pagin = findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
//Test Case cloud-2198
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("0");
when(request.getParameter("maxItems")).thenReturn("a");
try
{
pagin = findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("s");
when(request.getParameter("maxItems")).thenReturn("5");
try
{
pagin = findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("0");
when(request.getParameter("maxItems")).thenReturn("-2");
try
{
pagin = findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
request = mock(WebScriptRequest.class);
when(request.getParameter("skipCount")).thenReturn("-3");
when(request.getParameter("maxItems")).thenReturn("5");
try
{
pagin = findPaging(request);
fail("Should not get here.");
}
catch (InvalidArgumentException iae)
{
assertNotNull(iae); // Must throw this exceptions
}
request = mock(WebScriptRequest.class);
when(request.getParameter("maxItems")).thenReturn("5");
pagin = findPaging(request);
assertNotNull(pagin);
assertTrue("skip count defaults to 0", pagin.getSkipCount() == Paging.DEFAULT_SKIP_COUNT);
//End of Test Case cloud-2198
}
@Test
public void paramsTest()
{
Map<String,List<String>> mockParams = new HashMap<String,List<String>>();
mockParams.put("age", Arrays.asList("23","45"));
mockParams.put("name", Arrays.asList("fred"));
WebScriptRequest request = mockRequest(mockParams);
Map<String, String[]> params = getRequestParameters(request);
assertNotNull(params);
Params paramObj = ParamsExtender.valueOf(params);
assertNotNull(paramObj);
String aValue = paramObj.getParameter("age");
assertEquals("23", aValue);
aValue = paramObj.getParameter("name");
assertEquals("fred", aValue);
}
private WebScriptRequest mockRequest(final Map<String,List<String>> params)
{
final String[] paramNames = params.keySet().toArray(new String[]{});
WebScriptRequest request = mock(WebScriptRequest.class);
when(request.getParameterNames()).thenReturn(paramNames);
when(request.getParameterValues(anyString())).thenAnswer(new Answer<String[]>() {
@Override
public String[] answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return params.get((String) args[0]).toArray(new String[]{});
}
});
return request;
}
}

View File

@@ -43,7 +43,7 @@ import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.framework.resource.parameters.Params; import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.resource.parameters.Params.RecognizedParams; import org.alfresco.rest.framework.resource.parameters.Params.RecognizedParams;
import org.alfresco.rest.framework.resource.parameters.where.Query; import org.alfresco.rest.framework.resource.parameters.where.Query;
import org.alfresco.rest.framework.webscripts.ResourceWebScriptHelper; import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
import org.alfresco.rest.workflow.api.Processes; import org.alfresco.rest.workflow.api.Processes;
import org.alfresco.rest.workflow.api.impl.ProcessesImpl; import org.alfresco.rest.workflow.api.impl.ProcessesImpl;
import org.alfresco.rest.workflow.api.model.ProcessInfo; import org.alfresco.rest.workflow.api.model.ProcessInfo;
@@ -67,7 +67,7 @@ import junit.framework.TestCase;
* *
* @author Dmitry Velichkevich * @author Dmitry Velichkevich
*/ */
public class ProcessesImplTest extends TestCase public class ProcessesImplTest extends TestCase implements RecognizedParamsExtractor
{ {
private static final String[] CONFIG_LOCATIONS = new String[ApplicationContextHelper.CONFIG_LOCATIONS.length + 2]; private static final String[] CONFIG_LOCATIONS = new String[ApplicationContextHelper.CONFIG_LOCATIONS.length + 2];
static static
@@ -224,7 +224,7 @@ public class ProcessesImplTest extends TestCase
private CollectionWithPagingInfo<ProcessInfo> queryMatchesProcesses(String matchesString) private CollectionWithPagingInfo<ProcessInfo> queryMatchesProcesses(String matchesString)
{ {
Query query = ResourceWebScriptHelper.getWhereClause(String.format(QUERY_WORKFLOWDESCRIPTION_MATCHES, matchesString)); Query query = getWhereClause(String.format(QUERY_WORKFLOWDESCRIPTION_MATCHES, matchesString));
Parameters parameters = Params.valueOf(new RecognizedParams(null, Paging.valueOf(0, ACTIVE_WORKFLOWS_INITIAL_AMOUNT), null, null, null, null, query, null, false), null, null, null); Parameters parameters = Params.valueOf(new RecognizedParams(null, Paging.valueOf(0, ACTIVE_WORKFLOWS_INITIAL_AMOUNT), null, null, null, null, query, null, false), null, null, null);
return processes.getProcesses(parameters); return processes.getProcesses(parameters);
@@ -232,7 +232,7 @@ public class ProcessesImplTest extends TestCase
private CollectionWithPagingInfo<ProcessInfo> queryActiveProcessesAndAssertResult(int skipCount, int maxItems) private CollectionWithPagingInfo<ProcessInfo> queryActiveProcessesAndAssertResult(int skipCount, int maxItems)
{ {
Query query = ResourceWebScriptHelper.getWhereClause(QUERY_STATUS_ACTIVE); Query query = getWhereClause(QUERY_STATUS_ACTIVE);
Parameters parameters = Params.valueOf(new RecognizedParams(null, Paging.valueOf(skipCount, maxItems), null, null, null, null, query, null, false), null, null, null); Parameters parameters = Params.valueOf(new RecognizedParams(null, Paging.valueOf(skipCount, maxItems), null, null, null, null, query, null, false), null, null, null);
CollectionWithPagingInfo<ProcessInfo> result = processes.getProcesses(parameters); CollectionWithPagingInfo<ProcessInfo> result = processes.getProcesses(parameters);