diff --git a/source/java/org/alfresco/repo/webservice/AbstractQuery.java b/source/java/org/alfresco/repo/webservice/AbstractQuery.java new file mode 100644 index 0000000000..0dd23b54c0 --- /dev/null +++ b/source/java/org/alfresco/repo/webservice/AbstractQuery.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webservice; + +import java.util.Set; + +import org.alfresco.repo.webservice.types.ResultSetRowNode; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; + +/** + * Abstract implementation of a QuerySession providing support for automatic id generation + * and provides support for paging through query results. + *

+ * Before executing, all the services need to be set. + * + * @author gavinc + */ +public abstract class AbstractQuery implements ServerQuery +{ + public AbstractQuery() + { + } + + /** + * Override this method only if the query can limit the results without a post-query cut-off. + * + * {@inheritDoc} + */ + public RESULTSET execute(ServiceRegistry serviceRegistry, long maxResults) + { + return execute(serviceRegistry); + } + + /** + * Create a result set row node object for the provided node reference + * + * @param nodeRef + * the node reference + * @param nodeService + * the node service + * @return + * the result set row node + */ + protected ResultSetRowNode createResultSetRowNode(NodeRef nodeRef, NodeService nodeService) + { + // Get the type + String type = nodeService.getType(nodeRef).toString(); + + // Get the aspects applied to the node + Set aspects = nodeService.getAspects(nodeRef); + String[] aspectNames = new String[aspects.size()]; + int index = 0; + for (QName aspect : aspects) + { + aspectNames[index] = aspect.toString(); + index++; + } + + // Create and return the result set row node + return new ResultSetRowNode(nodeRef.getId(), type, aspectNames); + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/webservice/AbstractQuerySession.java b/source/java/org/alfresco/repo/webservice/AbstractQuerySession.java new file mode 100644 index 0000000000..8972f7576c --- /dev/null +++ b/source/java/org/alfresco/repo/webservice/AbstractQuerySession.java @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webservice; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.util.GUID; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * An abstract implementation of the query session that keeps track of the paging data. + * It provides support for paging of results of Serializable[] instances. + * + * @author Derek Hulley + * @since 2.1 + */ +public abstract class AbstractQuerySession implements QuerySession +{ + private static Log logger = LogFactory.getLog(AbstractQuerySession.class); + + private String id; + private long maxResults; + private long batchSize; + private ServerQuery query; + /** a transient cache of the query results */ + private transient RESULTSET cachedResults; + + /** + * A pointer to the first row to be returned. When the last result is returned, the + * position will be out of range of the current results by 1. + */ + private long position; + /** + * Keep track of whether the position has previously passed the end of a set of results. + */ + private boolean expectMoreResults; + + /** + * Common constructor that initialises the session's id and batch size + * + * @param maxResults + * the maximum number of results to retrieve for the query. This is not the page + * size, which is normally significantly smaller. + * @param batchSize + * the batch size this session will use + * @param query + * the query that generates the results + */ + public AbstractQuerySession(long maxResults, long batchSize, ServerQuery query) + { + this.id = GUID.generate(); + this.batchSize = batchSize; + this.maxResults = maxResults; + this.query = query; + this.position = 0; + this.expectMoreResults = true; + } + + /** + * {@inheritDoc} + */ + public String getId() + { + return this.id; + } + + /** + * {@inheritDoc} + */ + public ServerQuery getQuery() + { + return query; + } + + /** + * Helper method to get the results. This may be a cached value or may be + * freshly retrieved from the query object. + * + * @param serviceRegistry the + * @return the query results, new or cached + */ + protected RESULTSET getQueryResults(ServiceRegistry serviceRegistry) + { + if (cachedResults != null) + { + return cachedResults; + } + // Get the results and cache them + cachedResults = query.execute(serviceRegistry, maxResults); + // Done + return cachedResults; + } + + /** + * {@inheritDoc} + */ + public boolean haveMoreResults() + { + return expectMoreResults; + } + + protected abstract RESULTSETROW[] makeArray(int size); + + /** + * Helper method to page through the results. The task of retrieving, unwrapping and + * rewrapping the array of results (rows) is left up to the derived implementations. + */ + protected final RESULTSETROW[] getNextResults(RESULTSETROW[] allResults) + { + /* + * This class can't manipulate the query to get the results because each + * query implementation's results (the array of rows) is contained within + * a different type of object. This method helps + */ + + long allResultsSize = allResults.length; + + RESULTSETROW[] batchedResults = null; + if (position >= allResultsSize) + { + // We are already past the last result + batchedResults = makeArray(0); + // Position is after last + position = allResultsSize; + } + else if (position == 0 && batchSize >= allResultsSize) + { + // We can give back the original results + batchedResults = allResults; + // Position is after last + position = allResultsSize; + } + else if ((position + batchSize) >= allResultsSize) + { + // There isn't an excess of rows remaining, so copy to the last one + long lastResultIndex = allResultsSize - 1L; + long rowCopyCount = lastResultIndex - position; + batchedResults = makeArray((int)rowCopyCount); + System.arraycopy(allResults, (int)position, batchedResults, 0, (int)rowCopyCount); + // Position is after last + position = allResultsSize; + } + else + { + // There are an excess of rows remaining + batchedResults = makeArray((int)batchSize); + System.arraycopy(allResults, (int)position, batchedResults, 0, (int)batchSize); + // Position increases by the batch size + position += batchSize; + } + // Keep track of whether we expect more results + if (position >= allResultsSize) + { + expectMoreResults = false; + } + // Done + if (logger.isDebugEnabled()) + { + logger.debug("\n" + + "Fetched next set of results: \n" + + " Total results count: " + allResultsSize + "\n" + + " Batch size: " + batchedResults.length + "\n" + + " New Position: " + position); + } + return batchedResults; +// long allResultsSize = allResults.getTotalRowCount(); +// +// ResultSet batchedResults = null; +// if (position >= allResultsSize) +// { +// // We are already past the last result +// batchedResults = new ResultSet(); +// batchedResults.setRows(new ResultSetRow[] {}); +// batchedResults.setTotalRowCount(0); +// batchedResults.setMetaData(allResults.getMetaData()); +// // Position is after last +// position = allResultsSize; +// } +// else if (position == 0 && batchSize >= allResultsSize) +// { +// // We can give back the original results +// batchedResults = allResults; +// // Position is after last +// position = allResultsSize; +// } +// else if ((position + batchSize) >= allResultsSize) +// { +// // There isn't an excess of rows remaining, so copy to the last one +// long lastResultIndex = allResultsSize - 1L; +// long rowCopyCount = lastResultIndex - position; +// ResultSetRow[] batchedRows = new ResultSetRow[(int)rowCopyCount]; +// ResultSetRow[] allRows = allResults.getRows(); +// System.arraycopy(allRows, (int)position, batchedRows, 0, (int)rowCopyCount); +// // Build the results +// batchedResults = new ResultSet(); +// batchedResults.setRows(batchedRows); +// batchedResults.setTotalRowCount(rowCopyCount); +// batchedResults.setMetaData(allResults.getMetaData()); +// // Position is after last +// position = allResultsSize; +// } +// else +// { +// // There are an excess of rows remaining +// ResultSetRow[] batchedRows = new ResultSetRow[(int)batchSize]; +// ResultSetRow[] allRows = allResults.getRows(); +// System.arraycopy(allRows, (int)position, batchedRows, 0, (int)batchSize); +// // Build the results +// batchedResults = new ResultSet(); +// batchedResults.setRows(batchedRows); +// batchedResults.setTotalRowCount(batchSize); +// batchedResults.setMetaData(allResults.getMetaData()); +// // Position increases by the batch size +// position += batchSize; +// } +// // Keep track of whether we expect more results +// if (position >= allResultsSize) +// { +// expectMoreResults = false; +// } +// // Done +// if (logger.isDebugEnabled()) +// { +// logger.debug("\n" + +// "Fetched net set of results: \n" + +// " Total results count: " + allResultsSize + "\n" + +// " Batch size: " + batchedResults.getTotalRowCount() + "\n" + +// " New Position: " + position); +// } +// return batchedResults; + } +} diff --git a/source/java/org/alfresco/repo/webservice/AbstractWebService.java b/source/java/org/alfresco/repo/webservice/AbstractWebService.java index fe37be62c9..4cd169e21e 100644 --- a/source/java/org/alfresco/repo/webservice/AbstractWebService.java +++ b/source/java/org/alfresco/repo/webservice/AbstractWebService.java @@ -1,77 +1,117 @@ /* * Copyright (C) 2005-2007 Alfresco Software Limited. * - * Licensed under the GNU Lesser General Public License as - * published by the Free Software Foundation; either version - * 2.1 of the License, or (at your option) any later version. - * You may obtain a copy of the License at - * - * http://www.gnu.org/licenses/lgpl.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" */ package org.alfresco.repo.webservice; +import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.namespace.NamespaceService; /** - * Abstract base class for all web service implementations, provides support for common - * service injection + * Abstract base class for all web service implementations, provides support for common service injection * * @author gavinc */ public abstract class AbstractWebService { - protected NodeService nodeService; - protected ContentService contentService; - protected SearchService searchService; - protected NamespaceService namespaceService; - - /** - * Sets the instance of the NodeService to be used - * - * @param nodeService The NodeService - */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - /** - * Sets the ContentService instance to use - * - * @param contentSvc The ContentService - */ - public void setContentService(ContentService contentSvc) - { - this.contentService = contentSvc; - } - - /** - * Sets the instance of the SearchService to be used - * - * @param searchService The SearchService - */ - public void setSearchService(SearchService searchService) - { - this.searchService = searchService; - } - - /** - * Sets the instance of the NamespaceService to be used - * - * @param namespaceService The NamespaceService - */ - public void setNamespaceService(NamespaceService namespaceService) - { - this.namespaceService = namespaceService; - } + protected ServiceRegistry serviceRegistry; + protected DictionaryService dictionaryService; + protected NodeService nodeService; + protected ContentService contentService; + protected SearchService searchService; + protected NamespaceService namespaceService; + + protected SimpleCache querySessionCache; + + public void setServiceRegistry(ServiceRegistry serviceRegistry) + { + this.serviceRegistry = serviceRegistry; + } + + /** + * Sets the instance of the DictionaryService to be used + * + * @param dictionaryService + * The DictionaryService + */ + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + /** + * Sets the instance of the NodeService to be used + * + * @param nodeService The NodeService + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Sets the ContentService instance to use + * + * @param contentSvc The ContentService + */ + public void setContentService(ContentService contentSvc) + { + this.contentService = contentSvc; + } + + /** + * Sets the instance of the SearchService to be used + * + * @param searchService The SearchService + */ + public void setSearchService(SearchService searchService) + { + this.searchService = searchService; + } + + /** + * Sets the instance of the NamespaceService to be used + * + * @param namespaceService The NamespaceService + */ + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + /** + * Sets the cache to use for storing the the query session's paging information by query session ID. + * + * @param querySessionCache the cache. Cluster replication should be via serialization of + * the cache values. + */ + public void setQuerySessionCache(SimpleCache querySessionCache) + { + this.querySessionCache = querySessionCache; + } } diff --git a/source/java/org/alfresco/repo/webservice/QuerySession.java b/source/java/org/alfresco/repo/webservice/QuerySession.java new file mode 100644 index 0000000000..e913aea0e4 --- /dev/null +++ b/source/java/org/alfresco/repo/webservice/QuerySession.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webservice; + +import java.io.Serializable; + +import org.alfresco.service.ServiceRegistry; + +/** + * An interface for objects that track the query and its results. The only commonality between + * the different types of results used in the WebServices return values is that they are + * Serializable. + * + * @author Derek Hulley + */ +public interface QuerySession extends Serializable +{ + /** + * Retrieves the id this query session can be identified as + * + * @return Id of this query session + */ + public String getId(); + + /** + * Check if the session is expecting more results. This will be false if the + * cursor previously passed the end of a given set of results. + */ + public boolean haveMoreResults(); + + /** + * Get the next batch of results from the full set of available results. If there are no results + * available, then this session must go and fetch them. It is up to the implementation to provide + * a means for this to occur. + * + * @param serviceRegistry + * the services to perform a query + * @param allResults + * All available results. It may be necessary to requery to get the results. + * @return + * Returns the next batch of results based on the maximum fetch size. If there are no + * more results, the resultset will be empty. + */ + public RESULTSET getNextResults(ServiceRegistry serviceRegistry); +} diff --git a/source/java/org/alfresco/repo/webservice/repository/QuerySession.java b/source/java/org/alfresco/repo/webservice/ServerQuery.java similarity index 50% rename from source/java/org/alfresco/repo/webservice/repository/QuerySession.java rename to source/java/org/alfresco/repo/webservice/ServerQuery.java index dbb467a15c..00022e7624 100644 --- a/source/java/org/alfresco/repo/webservice/repository/QuerySession.java +++ b/source/java/org/alfresco/repo/webservice/ServerQuery.java @@ -22,53 +22,48 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.webservice.repository; +package org.alfresco.repo.webservice; import java.io.Serializable; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.ServiceRegistry; /** * Interface definition for a QuerySession. * * @author gavinc */ -public interface QuerySession extends Serializable +public interface ServerQuery extends Serializable { /** System column namess */ public static String SYS_COL_ASSOC_TYPE = "associationType"; public static String SYS_COL_ASSOC_NAME = "associationName"; public static String SYS_COL_IS_PRIMARY = "isPrimary"; public static String SYS_COL_NTH_SIBLING = "nthSibling"; - - /** - * Retrieves the id this query session can be identified as - * - * @return Id of this query session - */ - public String getId(); - - /** - * Returns a QueryResult object representing the next batch of results. - * QueryResult will contain a maximum of items as determined by the - * fetchSize element of the QueryConfiguration SOAP header. - * - * When the last batch of results is being returned the querySession of - * QueryResult will be null. - * - * @see org.alfresco.repo.webservice.repository.QuerySession#getId() - * @param searchService The SearchService to use for gathering the results - * @param nodeService The NodeService to use for gathering the results - * @param namespaceService The NamespaceService to use - * @return QueryResult containing the next batch of results or null if there - * are no more results - */ - public QueryResult getNextResultsBatch( - SearchService searchService, - NodeService nodeService, - NamespaceService namespaceService, - DictionaryService dictionaryService); -} + + /** + * Executes the query and returns the full query results. + * + * @param + * The services to help make the query + * @return + * The full set of query results. + * The results must be empty if there are no results. + */ + public RESULTSET execute(ServiceRegistry serviceRegistry); + + /** + * Executes the query and return all results up to given maximum number. + * Note that this is not the same as the page size, but rather is a total + * upper limit to the number of results that can viewed. + * + * @param + * The services to help make the query + * @param maxResults + * the total number of results to retrieve + * @return + * The full set of query results up to the maximum given. + * The results must be empty if there are no results. + */ + public RESULTSET execute(ServiceRegistry serviceRegistry, long maxResults); +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/webservice/Utils.java b/source/java/org/alfresco/repo/webservice/Utils.java index 01edb1eca8..b26b3abbfb 100644 --- a/source/java/org/alfresco/repo/webservice/Utils.java +++ b/source/java/org/alfresco/repo/webservice/Utils.java @@ -79,6 +79,8 @@ import org.springframework.web.context.support.WebApplicationContextUtils; */ public class Utils { + /** Default batch size for query results - 1000 */ + public static final int DEFAULT_BATCH_SIZE = 1000; public static final String REPOSITORY_SERVICE_NAMESPACE = "http://www.alfresco.org/ws/service/repository/1.0"; /** Get the logger for this class */ @@ -384,8 +386,7 @@ public class Utils } NodeRef rootNodeRef = nodeService.getRootNode(convertToStoreRef(store)); - List nodes = searchService.selectNodes(rootNodeRef, path, - null, namespaceService, false); + List nodes = searchService.selectNodes(rootNodeRef, path, null, namespaceService, false); // make sure we only have one result if (nodes.size() != 1) @@ -589,7 +590,7 @@ public class Utils */ public static int getBatchSize(MessageContext msgContext) { - int batchSize = -1; + int batchSize = DEFAULT_BATCH_SIZE; Integer batchConfigSize = (Integer) MessageContext.getCurrentContext() .getProperty(QueryConfigHandler.ALF_FETCH_SIZE); diff --git a/source/java/org/alfresco/repo/webservice/administration/AdministrationWebService.java b/source/java/org/alfresco/repo/webservice/administration/AdministrationWebService.java index 354b4d5949..f9285ac823 100644 --- a/source/java/org/alfresco/repo/webservice/administration/AdministrationWebService.java +++ b/source/java/org/alfresco/repo/webservice/administration/AdministrationWebService.java @@ -36,19 +36,19 @@ import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; -import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.webservice.AbstractWebService; import org.alfresco.repo.webservice.Utils; import org.alfresco.repo.webservice.action.ActionFault; +import org.alfresco.repo.webservice.repository.RepositoryFault; import org.alfresco.repo.webservice.types.NamedValue; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.GUID; import org.apache.axis.MessageContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -74,9 +74,6 @@ public class AdministrationWebService extends AbstractWebService implements /** A set of ignored properties */ private static Set ignoredProperties = new HashSet(3); - /** Simple cache used to store user query sessions */ - private SimpleCache querySessionCache; - /** * Constructor */ @@ -118,18 +115,6 @@ public class AdministrationWebService extends AbstractWebService implements this.authenticationService = authenticationService; } - /** - * Sets the instance of the SimpleCache to be used - * - * @param querySessionCache - * The SimpleCache - */ - public void setQuerySessionCache( - SimpleCache querySessionCache) - { - this.querySessionCache = querySessionCache; - } - /** * @see org.alfresco.repo.webservice.administration.AdministrationServiceSoapPort#queryUsers(org.alfresco.repo.webservice.administration.UserFilter) */ @@ -168,18 +153,33 @@ public class AdministrationWebService extends AbstractWebService implements { MessageContext msgContext = MessageContext.getCurrentContext(); + // Create the query + UserQuery query = new UserQuery(filter); + // Create a user query session - UserQuerySession userQuerySession = new UserQuerySession(Utils.getBatchSize(msgContext), filter); - UserQueryResults userQueryResults = userQuerySession.getNextBatch(); + UserQuerySession userQuerySession = new UserQuerySession(Long.MAX_VALUE, Utils.getBatchSize(msgContext), query); + + // Get the next batch of results + UserQueryResults userQueryResults = userQuerySession.getNextResults(serviceRegistry); + String querySessionId = userQuerySession.getId(); // add the session to the cache if there are more results to come - if (userQueryResults.getQuerySession() != null) + boolean haveMoreResults = userQuerySession.haveMoreResults(); + if (haveMoreResults) { - // this.querySessionCache.putQuerySession(querySession); - this.querySessionCache.put(userQueryResults.getQuerySession(), userQuerySession); + querySessionCache.put(querySessionId, userQuerySession); } - return userQueryResults; + // Construct the return value + // TODO: http://issues.alfresco.com/browse/AR-1689 + // This looks odd, but I've chosen to be specific about when the ID is set on the return + // results and when it isn't. + UserQueryResults result = new UserQueryResults( + haveMoreResults ? querySessionId : null, + userQueryResults.getUserDetails()); + + // Done + return result; } /** @@ -212,20 +212,34 @@ public class AdministrationWebService extends AbstractWebService implements /** * - * @param querySession + * @param querySessionId * @return */ - private UserQueryResults fetchMoreUsersImpl(String querySession) + private UserQueryResults fetchMoreUsersImpl(String querySessionId) throws RepositoryFault { - UserQueryResults queryResult = null; - UserQuerySession session = this.querySessionCache.get(querySession); + UserQuerySession session = null; + try + { + session = (UserQuerySession) querySessionCache.get(querySessionId); + } + catch (ClassCastException e) + { + if (logger.isDebugEnabled()) + { + logger.debug("Query session was not generated by the AdministrationWebService: " + querySessionId); + } + throw new RepositoryFault( + 4, + "querySession with id '" + querySessionId + "' is invalid"); + } + UserQueryResults queryResult = null; if (session != null) { - queryResult = session.getNextBatch(); - if (queryResult.getQuerySession() == null) + queryResult = session.getNextResults(serviceRegistry); + if (!session.haveMoreResults()) { - this.querySessionCache.remove(querySession); + this.querySessionCache.remove(querySessionId); } } @@ -269,12 +283,13 @@ public class AdministrationWebService extends AbstractWebService implements */ private UserDetails getUserImpl(String userName) { + NodeService nodeService = serviceRegistry.getNodeService(); UserDetails userDetails = null; if (this.personService.personExists(userName) == true) { NodeRef nodeRef = this.personService.getPerson(userName); - userDetails = createUserDetails(userName, nodeRef); + userDetails = createUserDetails(nodeService, userName, nodeRef); } else { @@ -291,7 +306,7 @@ public class AdministrationWebService extends AbstractWebService implements * @param nodeRef the node reference * @return the user details object populated with the appropriate property values */ - private UserDetails createUserDetails(String userName, NodeRef nodeRef) + /* package */ static UserDetails createUserDetails(NodeService nodeService, String userName, NodeRef nodeRef) { // Create the user details object UserDetails userDetails = new UserDetails(); @@ -300,7 +315,7 @@ public class AdministrationWebService extends AbstractWebService implements userDetails.setUserName(userName); // Set the various property values - Map properties = this.nodeService.getProperties(nodeRef); + Map properties = nodeService.getProperties(nodeRef); List namedValues = new ArrayList(properties.size()); for (Map.Entry entry : properties.entrySet()) { @@ -364,6 +379,7 @@ public class AdministrationWebService extends AbstractWebService implements */ private UserDetails[] createUsersImpl(NewUserDetails[] newUsers) { + NodeService nodeService = serviceRegistry.getNodeService(); UserDetails[] userDetails = new UserDetails[newUsers.length]; int index = 0; @@ -382,7 +398,7 @@ public class AdministrationWebService extends AbstractWebService implements NodeRef personNodeRef = this.personService.createPerson(properties); // Add the details to the result - userDetails[index] = createUserDetails(newUser.getUserName(), personNodeRef); + userDetails[index] = createUserDetails(nodeService, newUser.getUserName(), personNodeRef); index++; } @@ -424,6 +440,7 @@ public class AdministrationWebService extends AbstractWebService implements */ private UserDetails[] updateUsersImpl(UserDetails[] users) { + NodeService nodeService = serviceRegistry.getNodeService(); UserDetails[] userDetails = new UserDetails[users.length]; int index = 0; @@ -442,7 +459,7 @@ public class AdministrationWebService extends AbstractWebService implements // Add the details to the result NodeRef nodeRef = this.personService.getPerson(user.getUserName()); - userDetails[index] = createUserDetails(user.getUserName(), nodeRef); + userDetails[index] = createUserDetails(nodeService, user.getUserName(), nodeRef); index++; } @@ -539,163 +556,4 @@ public class AdministrationWebService extends AbstractWebService implements this.personService.deletePerson(userName); } } - - /** - * User query session used to support batched user query - * - * @author Roy Wetherall - */ - private class UserQuerySession implements Serializable - { - private static final long serialVersionUID = -2960711874297744356L; - - private int batchSize = -1; - private UserFilter filter; - protected int position = 0; - private String id; - - /** - * Constructor - * - * @param batchSize - * @param filter - */ - public UserQuerySession(int batchSize, UserFilter filter) - { - this.batchSize = batchSize; - this.filter = filter; - this.id = GUID.generate(); - } - - /** - * @see org.alfresco.repo.webservice.repository.QuerySession#getId() - */ - public String getId() - { - return this.id; - } - - /** - * Calculates the index of the last row to retrieve. - * - * @param totalRowCount The total number of rows in the results - * @return The index of the last row to return - */ - protected int calculateLastRowIndex(int totalRowCount) - { - int lastRowIndex = totalRowCount; - - // set the last row index if there are more results available - // than the batch size - if ((this.batchSize != -1) && ((this.position + this.batchSize) < totalRowCount)) - { - lastRowIndex = this.position + this.batchSize; - } - - return lastRowIndex; - } - - /** - * Calculates the value of the next position. - * If the end of the result set is reached the position is set to -1 - * - * @param totalRowCount The total number of rows in the results - * @param queryResult The QueryResult object being returned to the client, - * if there are no more results the id is removed from the QueryResult instance - */ - protected void updatePosition(int totalRowCount, UserQueryResults queryResult) - { - if (this.batchSize == -1) - { - this.position = -1; - queryResult.setQuerySession(null); - } - else - { - this.position += this.batchSize; - if (this.position >= totalRowCount) - { - // signify that there are no more results - this.position = -1; - queryResult.setQuerySession(null); - } - } - } - - /** - * Gets the next batch of user details - * - * @return user query results - */ - public UserQueryResults getNextBatch() - { - UserQueryResults queryResult = null; - - if (this.position != -1) - { - if (logger.isDebugEnabled()) - logger.debug("Before getNextBatch: " + toString()); - - Set nodeRefs = AdministrationWebService.this.personService.getAllPeople(); - - // Filter the results - List filteredNodeRefs = null; - if (filter != null && filter.getUserName() != null && filter.getUserName().length() != 0) - { - String userNameFilter = filter.getUserName(); - - if (logger.isDebugEnabled() == true) - { - logger.debug("Applying user query filter (" + userNameFilter + ")"); - } - - filteredNodeRefs = new ArrayList(nodeRefs.size()); - for (NodeRef nodeRef : nodeRefs) - { - String userName = (String)AdministrationWebService.this.nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME); - if (userName.matches(userNameFilter) == true) - { - filteredNodeRefs.add(nodeRef); - } - } - } - else - { - if (logger.isDebugEnabled() == true) - { - logger.debug("No user filter specified"); - } - - filteredNodeRefs = new ArrayList(nodeRefs); - } - - int totalRows = filteredNodeRefs.size(); - int lastRow = calculateLastRowIndex(totalRows); - int currentBatchSize = lastRow - this.position; - - if (logger.isDebugEnabled()) - logger.debug("Total rows = " + totalRows + ", current batch size = " + currentBatchSize); - - List userDetailsList = new ArrayList(currentBatchSize); - - for (int x = this.position; x < lastRow; x++) - { - NodeRef nodeRef = (NodeRef)filteredNodeRefs.get(x); - String userName = (String)AdministrationWebService.this.nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME); - UserDetails userDetails = AdministrationWebService.this.createUserDetails(userName, nodeRef); - userDetailsList.add(userDetails); - } - - queryResult = new UserQueryResults(getId(), (UserDetails[])userDetailsList.toArray(new UserDetails[userDetailsList.size()])); - - // move the position on - updatePosition(totalRows, queryResult); - - if (logger.isDebugEnabled()) - logger.debug("After getNextBatch: " + toString()); - } - - return queryResult; - } - } } diff --git a/source/java/org/alfresco/repo/webservice/administration/UserQuery.java b/source/java/org/alfresco/repo/webservice/administration/UserQuery.java new file mode 100644 index 0000000000..8793dd328b --- /dev/null +++ b/source/java/org/alfresco/repo/webservice/administration/UserQuery.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webservice.administration; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.webservice.AbstractQuery; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.PersonService; + +/** + * A query to retrieve normal node associations. + * + * @author Derek Hulley + * @since 2.1 + */ +public class UserQuery extends AbstractQuery +{ + private static final long serialVersionUID = -672399618512462040L; + + private UserFilter userFilter; + + /** + * @param userFilter + * The user filter + */ + public UserQuery(UserFilter userFilter) + { + this.userFilter = userFilter; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(128); + sb.append("AssociationQuery") + .append("[ userFilter=").append(userFilter.getUserName()) + .append("]"); + return sb.toString(); + } + + /** + * {@inheritDoc} + */ + public UserQueryResults execute(ServiceRegistry serviceRegistry) + { + PersonService personService = serviceRegistry.getPersonService(); + NodeService nodeService = serviceRegistry.getNodeService(); + + Set nodeRefs = personService.getAllPeople(); + + // Filter the results + List filteredNodeRefs = null; + if (userFilter != null && userFilter.getUserName() != null && userFilter.getUserName().length() != 0) + { + String userNameFilter = userFilter.getUserName(); + + filteredNodeRefs = new ArrayList(nodeRefs.size()); + for (NodeRef nodeRef : nodeRefs) + { + String userName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME); + if (userName.matches(userNameFilter) == true) + { + filteredNodeRefs.add(nodeRef); + } + } + } + else + { + filteredNodeRefs = new ArrayList(nodeRefs); + } + + UserDetails[] results = new UserDetails[filteredNodeRefs.size()]; + int index = 0; + for (NodeRef nodeRef : filteredNodeRefs) + { + String userName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME); + results[index] = AdministrationWebService.createUserDetails(nodeService, userName, nodeRef); + index++; + } + + UserQueryResults queryResults = new UserQueryResults(null, results); + + // Done + return queryResults; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/webservice/administration/UserQuerySession.java b/source/java/org/alfresco/repo/webservice/administration/UserQuerySession.java new file mode 100644 index 0000000000..f681f1afb1 --- /dev/null +++ b/source/java/org/alfresco/repo/webservice/administration/UserQuerySession.java @@ -0,0 +1,41 @@ +package org.alfresco.repo.webservice.administration; + +import org.alfresco.repo.webservice.AbstractQuerySession; +import org.alfresco.repo.webservice.ServerQuery; +import org.alfresco.service.ServiceRegistry; + +/** + * A session for managing user-related queries. + * + * @author Derek Hulley + * @since 2.1 + */ +public class UserQuerySession extends AbstractQuerySession +{ + private static final long serialVersionUID = 1823253197962982642L; + + public UserQuerySession(long maxResults, long batchSize, ServerQuery query) + { + super(maxResults, batchSize, query); + } + + @Override + protected UserDetails[] makeArray(int size) + { + return new UserDetails[size]; + } + + public UserQueryResults getNextResults(ServiceRegistry serviceRegistry) + { + UserQueryResults queryResults = getQueryResults(serviceRegistry); + UserDetails[] allRows = queryResults.getUserDetails(); + UserDetails[] batchedRows = getNextResults(allRows); + // Build the user query results + UserQueryResults batchedResults = new UserQueryResults(); +// batchedResults.setQuerySession(getId()); TODO: http://issues.alfresco.com/browse/AR-1689 + + batchedResults.setUserDetails(batchedRows); + // Done + return batchedResults; + } +} diff --git a/source/java/org/alfresco/repo/webservice/repository/AbstractQuerySession.java b/source/java/org/alfresco/repo/webservice/repository/AbstractQuerySession.java deleted file mode 100644 index 43b14eb379..0000000000 --- a/source/java/org/alfresco/repo/webservice/repository/AbstractQuerySession.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.webservice.repository; - -import java.util.Set; - -import org.alfresco.repo.webservice.types.ResultSetRowNode; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.GUID; - -/** - * Abstract implementation of a QuerySession providing support - * for automatic id generation and provides support for - * paging through query results. - * - * @author gavinc - */ -public abstract class AbstractQuerySession implements QuerySession -{ - protected int batchSize; - protected int position = 0; - - private String id; - - /** - * Common constructor that initialises the session's id and batch size - * - * @param batchSize The batch size this session will use - */ - public AbstractQuerySession(int batchSize) - { - this.id = GUID.generate(); - this.batchSize = batchSize; - } - - /** - * @see org.alfresco.repo.webservice.repository.QuerySession#getId() - */ - public String getId() - { - return this.id; - } - - /** - * Calculates the index of the last row to retrieve. - * - * @param totalRowCount The total number of rows in the results - * @return The index of the last row to return - */ - protected int calculateLastRowIndex(int totalRowCount) - { - int lastRowIndex = totalRowCount; - - // set the last row index if there are more results available - // than the batch size - if ((this.batchSize != -1) && ((this.position + this.batchSize) < totalRowCount)) - { - lastRowIndex = this.position + this.batchSize; - } - - return lastRowIndex; - } - - /** - * Calculates the value of the next position. - * If the end of the result set is reached the position is set to -1 - * - * @param totalRowCount The total number of rows in the results - * @param queryResult The QueryResult object being returned to the client, - * if there are no more results the id is removed from the QueryResult instance - */ - protected void updatePosition(int totalRowCount, QueryResult queryResult) - { - this.position += this.batchSize; - if (this.position >= totalRowCount) - { - // signify that there are no more results - this.position = -1; - queryResult.setQuerySession(null); - } - } - - /** - * Create a result set row node object for the provided node reference - * - * @param nodeRef the node reference - * @param nodeService the node service - * @return the result set row node - */ - protected ResultSetRowNode createResultSetRowNode(NodeRef nodeRef, NodeService nodeService) - { - // Get the type - String type = nodeService.getType(nodeRef).toString(); - - // Get the aspects applied to the node - Set aspects = nodeService.getAspects(nodeRef); - String[] aspectNames = new String[aspects.size()]; - int index = 0; - for (QName aspect : aspects) - { - aspectNames[index] = aspect.toString(); - index ++; - } - - // Create and return the result set row node - return new ResultSetRowNode(nodeRef.getId(), type, aspectNames); - } -} diff --git a/source/java/org/alfresco/repo/webservice/repository/AssociatedQuerySession.java b/source/java/org/alfresco/repo/webservice/repository/AssociatedQuerySession.java deleted file mode 100644 index 3f6034b9b6..0000000000 --- a/source/java/org/alfresco/repo/webservice/repository/AssociatedQuerySession.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.webservice.repository; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.webservice.Utils; -import org.alfresco.repo.webservice.types.NamedValue; -import org.alfresco.repo.webservice.types.Reference; -import org.alfresco.repo.webservice.types.ResultSetRow; -import org.alfresco.repo.webservice.types.ResultSetRowNode; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.repository.AssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.service.namespace.QNamePattern; -import org.alfresco.service.namespace.RegexQNamePattern; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Implementation of a QuerySession that stores the results from a query for - * associations - * - * @author Roy Wetherall - */ -public class AssociatedQuerySession extends AbstractQuerySession -{ - private static final long serialVersionUID = 6488008047324436124L; - - private transient static Log logger = LogFactory - .getLog(AssociatedQuerySession.class); - - private Reference node; - private Association association; - - /** - * Constructs a AssociatedQuerySession - * - * @param batchSize - * The batch size to use for this session - * @param node - * The node to retrieve the associations - */ - public AssociatedQuerySession(int batchSize, Reference node, Association association) - { - super(batchSize); - - this.node = node; - this.association = association; - } - - /** - * @see org.alfresco.repo.webservice.repository.QuerySession#getNextResultsBatch(org.alfresco.service.cmr.search.SearchService, - * org.alfresco.service.cmr.repository.NodeService, - * org.alfresco.service.namespace.NamespaceService) - */ - public QueryResult getNextResultsBatch(SearchService searchService, - NodeService nodeService, NamespaceService namespaceService, DictionaryService dictionaryService) - { - QueryResult queryResult = null; - - if (this.position != -1) - { - if (logger.isDebugEnabled()) - logger.debug("Before getNextResultsBatch: " + toString()); - - // create the node ref and get the children from the repository - NodeRef nodeRef = Utils.convertToNodeRef(this.node, nodeService, searchService, namespaceService); - List assocs = null; - if (association != null) - { - assocs = nodeService.getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL); - } - else - { - QNamePattern name = RegexQNamePattern.MATCH_ALL; - String assocType = association.getAssociationType(); - if (assocType != null) - { - name = QName.createQName(assocType); - } - if ("source".equals(association.getDirection()) == true) - { - assocs = nodeService.getSourceAssocs(nodeRef, name); - } - else - { - assocs = nodeService.getTargetAssocs(nodeRef, name); - } - } - - int totalRows = assocs.size(); - int lastRow = calculateLastRowIndex(totalRows); - int currentBatchSize = lastRow - this.position; - - if (logger.isDebugEnabled()) - logger.debug("Total rows = " + totalRows - + ", current batch size = " + currentBatchSize); - - org.alfresco.repo.webservice.types.ResultSet batchResults = new org.alfresco.repo.webservice.types.ResultSet(); - org.alfresco.repo.webservice.types.ResultSetRow[] rows = new org.alfresco.repo.webservice.types.ResultSetRow[currentBatchSize]; - - int arrPos = 0; - for (int x = this.position; x < lastRow; x++) - { - AssociationRef assoc = assocs.get(x); - NodeRef childNodeRef = assoc.getTargetRef(); - ResultSetRowNode rowNode = createResultSetRowNode(childNodeRef, nodeService); - - // create columns for all the properties of the node - // get the data for the row and build up the columns structure - Map props = nodeService - .getProperties(childNodeRef); - NamedValue[] columns = new NamedValue[props.size()+2]; - int col = 0; - for (QName propName : props.keySet()) - { - columns[col] = Utils.createNamedValue(dictionaryService, propName, props.get(propName)); - col++; - } - - // Now add the system columns containing the association details - columns[col] = new NamedValue(SYS_COL_ASSOC_TYPE, Boolean.FALSE, assoc.getTypeQName().toString(), null); - - // Add one more column for the node's path - col++; - columns[col] = Utils.createNamedValue(dictionaryService, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "path"), nodeService.getPath(childNodeRef).toString()); - - ResultSetRow row = new ResultSetRow(); - row.setRowIndex(x); - row.setNode(rowNode); - row.setColumns(columns); - - // add the row to the overall results - rows[arrPos] = row; - arrPos++; - } - - // add the rows to the result set and set the total row count - batchResults.setRows(rows); - batchResults.setTotalRowCount(totalRows); - - queryResult = new QueryResult(getId(), batchResults); - - // move the position on - updatePosition(totalRows, queryResult); - - if (logger.isDebugEnabled()) - logger.debug("After getNextResultsBatch: " + toString()); - } - - return queryResult; - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - StringBuilder builder = new StringBuilder(super.toString()); - builder.append(" (id=").append(getId()); - builder.append(" batchSize=").append(this.batchSize); - builder.append(" position=").append(this.position); - builder.append(" node-id=").append(this.node.getUuid()).append(")"); - return builder.toString(); - } -} diff --git a/source/java/org/alfresco/repo/webservice/repository/AssociationQuery.java b/source/java/org/alfresco/repo/webservice/repository/AssociationQuery.java new file mode 100644 index 0000000000..13211622ee --- /dev/null +++ b/source/java/org/alfresco/repo/webservice/repository/AssociationQuery.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webservice.repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.webservice.AbstractQuery; +import org.alfresco.repo.webservice.Utils; +import org.alfresco.repo.webservice.types.NamedValue; +import org.alfresco.repo.webservice.types.Reference; +import org.alfresco.repo.webservice.types.ResultSet; +import org.alfresco.repo.webservice.types.ResultSetRow; +import org.alfresco.repo.webservice.types.ResultSetRowNode; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.AssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.QNamePattern; +import org.alfresco.service.namespace.RegexQNamePattern; + +/** + * A query to retrieve normal node associations. + * + * @author Derek Hulley + * @since 2.1 + */ +public class AssociationQuery extends AbstractQuery +{ + private static final long serialVersionUID = -672399618512462040L; + + private Reference node; + private Association association; + + /** + * @param node + * The node to query against + * @param association + * The association type to query or null to query all + */ + public AssociationQuery(Reference node, Association association) + { + this.node = node; + this.association = association; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(128); + sb.append("AssociationQuery") + .append("[ node=").append(node.getUuid()) + .append(", association=").append(association) + .append("]"); + return sb.toString(); + } + + /** + * {@inheritDoc} + */ + public ResultSet execute(ServiceRegistry serviceRegistry) + { + SearchService searchService = serviceRegistry.getSearchService(); + NodeService nodeService = serviceRegistry.getNodeService(); + DictionaryService dictionaryService = serviceRegistry.getDictionaryService(); + NamespaceService namespaceService = serviceRegistry.getNamespaceService(); + + // create the node ref and get the children from the repository + NodeRef nodeRef = Utils.convertToNodeRef(node, nodeService, searchService, namespaceService); + List assocRefs = null; + if (association != null) + { + assocRefs = nodeService.getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL); + } + else + { + QNamePattern name = RegexQNamePattern.MATCH_ALL; + String assocType = association.getAssociationType(); + if (assocType != null) + { + name = QName.createQName(assocType); + } + if ("source".equals(association.getDirection()) == true) + { + assocRefs = nodeService.getSourceAssocs(nodeRef, name); + } + else + { + assocRefs = nodeService.getTargetAssocs(nodeRef, name); + } + } + + int totalRows = assocRefs.size(); + + ResultSet results = new ResultSet(); + ResultSetRow[] rows = new ResultSetRow[totalRows]; + + int index = 0; + for (AssociationRef assocRef : assocRefs) + { + NodeRef childNodeRef = assocRef.getTargetRef(); + ResultSetRowNode rowNode = createResultSetRowNode(childNodeRef, nodeService); + + // create columns for all the properties of the node + // get the data for the row and build up the columns structure + Map props = nodeService.getProperties(childNodeRef); + NamedValue[] columns = new NamedValue[props.size()+2]; + int col = 0; + for (QName propName : props.keySet()) + { + columns[col] = Utils.createNamedValue(dictionaryService, propName, props.get(propName)); + col++; + } + + // Now add the system columns containing the association details + columns[col] = new NamedValue(SYS_COL_ASSOC_TYPE, Boolean.FALSE, assocRef.getTypeQName().toString(), null); + + // Add one more column for the node's path + col++; + columns[col] = Utils.createNamedValue( + dictionaryService, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "path"), + nodeService.getPath(childNodeRef).toString()); + + ResultSetRow row = new ResultSetRow(); + row.setRowIndex(index); + row.setNode(rowNode); + row.setColumns(columns); + + // add the row to the overall results + rows[index] = row; + index++; + } + + // add the rows to the result set and set the total row count + results.setRows(rows); + results.setTotalRowCount(totalRows); + + return results; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/webservice/repository/ChildAssociationQuery.java b/source/java/org/alfresco/repo/webservice/repository/ChildAssociationQuery.java new file mode 100644 index 0000000000..b890dab74d --- /dev/null +++ b/source/java/org/alfresco/repo/webservice/repository/ChildAssociationQuery.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webservice.repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.webservice.AbstractQuery; +import org.alfresco.repo.webservice.Utils; +import org.alfresco.repo.webservice.types.NamedValue; +import org.alfresco.repo.webservice.types.Reference; +import org.alfresco.repo.webservice.types.ResultSet; +import org.alfresco.repo.webservice.types.ResultSetRow; +import org.alfresco.repo.webservice.types.ResultSetRowNode; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +/** + * A query to retrieve all child associations on a node. + * + * @author Derek Hulley + * @since 2.1 + */ +public class ChildAssociationQuery extends AbstractQuery +{ + private static final long serialVersionUID = -4965097420552826582L; + + private Reference node; + + /** + * @param node + * The node to query against + */ + public ChildAssociationQuery(Reference node) + { + this.node = node; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(128); + sb.append("ChildAssociationQuery") + .append("[ node=").append(node.getUuid()) + .append("]"); + return sb.toString(); + } + + /** + * {@inheritDoc} + */ + public ResultSet execute(ServiceRegistry serviceRegistry) + { + SearchService searchService = serviceRegistry.getSearchService(); + NodeService nodeService = serviceRegistry.getNodeService(); + DictionaryService dictionaryService = serviceRegistry.getDictionaryService(); + NamespaceService namespaceService = serviceRegistry.getNamespaceService(); + + // create the node ref and get the children from the repository + NodeRef nodeRef = Utils.convertToNodeRef(node, nodeService, searchService, namespaceService); + List assocRefs = nodeService.getChildAssocs(nodeRef); + + int totalRows = assocRefs.size(); + + ResultSet results = new ResultSet(); + ResultSetRow[] rows = new ResultSetRow[totalRows]; + + int index = 0; + for (ChildAssociationRef assocRef : assocRefs) + { + NodeRef childNodeRef = assocRef.getChildRef(); + ResultSetRowNode rowNode = createResultSetRowNode(childNodeRef, nodeService); + + // create columns for all the properties of the node + // get the data for the row and build up the columns structure + Map props = nodeService.getProperties(childNodeRef); + NamedValue[] columns = new NamedValue[props.size()+5]; + int col = 0; + for (QName propName : props.keySet()) + { + columns[col] = Utils.createNamedValue(dictionaryService, propName, props.get(propName)); + col++; + } + + // Now add the system columns containing the association details + columns[col] = new NamedValue(SYS_COL_ASSOC_TYPE, Boolean.FALSE, assocRef.getTypeQName().toString(), null); + col++; + columns[col] = new NamedValue(SYS_COL_ASSOC_NAME, Boolean.FALSE, assocRef.getQName().toString(), null); + col++; + columns[col] = new NamedValue(SYS_COL_IS_PRIMARY, Boolean.FALSE, Boolean.toString(assocRef.isPrimary()), null); + col++; + columns[col] = new NamedValue(SYS_COL_NTH_SIBLING, Boolean.FALSE, Integer.toString(assocRef.getNthSibling()), null); + + // Add one more column for the node's path + col++; + columns[col] = Utils.createNamedValue( + dictionaryService, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "path"), + nodeService.getPath(childNodeRef).toString()); + + ResultSetRow row = new ResultSetRow(); + row.setRowIndex(index); + row.setNode(rowNode); + row.setColumns(columns); + + // add the row to the overall results + rows[index] = row; + index++; + } + + // add the rows to the result set and set the total row count + results.setRows(rows); + results.setTotalRowCount(totalRows); + + return results; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/webservice/repository/ChildrenQuerySession.java b/source/java/org/alfresco/repo/webservice/repository/ChildrenQuerySession.java deleted file mode 100644 index bfbccbc497..0000000000 --- a/source/java/org/alfresco/repo/webservice/repository/ChildrenQuerySession.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.webservice.repository; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.webservice.Utils; -import org.alfresco.repo.webservice.types.NamedValue; -import org.alfresco.repo.webservice.types.Reference; -import org.alfresco.repo.webservice.types.ResultSetRow; -import org.alfresco.repo.webservice.types.ResultSetRowNode; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Implementation of a QuerySession that stores the results from a query for children - * - * @author gavinc - */ -public class ChildrenQuerySession extends AbstractQuerySession -{ - private static final long serialVersionUID = -5347036309571057074L; - - private transient static Log logger = LogFactory.getLog(ChildrenQuerySession.class); - - private Reference node; - - /** - * Constructs a ChildrenQuerySession - * - * @param batchSize The batch size to use for this session - * @param node The node to retrieve the parents - */ - public ChildrenQuerySession(int batchSize, Reference node) - { - super(batchSize); - - this.node = node; - } - - /** - * @see org.alfresco.repo.webservice.repository.QuerySession#getNextResultsBatch(org.alfresco.service.cmr.search.SearchService, org.alfresco.service.cmr.repository.NodeService, org.alfresco.service.namespace.NamespaceService) - */ - public QueryResult getNextResultsBatch(SearchService searchService, NodeService nodeService, NamespaceService namespaceService, DictionaryService dictionaryService) - { - QueryResult queryResult = null; - - if (this.position != -1) - { - if (logger.isDebugEnabled()) - logger.debug("Before getNextResultsBatch: " + toString()); - - // create the node ref and get the children from the repository - NodeRef nodeRef = Utils.convertToNodeRef(this.node, nodeService, searchService, namespaceService); - List kids = nodeService.getChildAssocs(nodeRef); - - int totalRows = kids.size(); - int lastRow = calculateLastRowIndex(totalRows); - int currentBatchSize = lastRow - this.position; - - if (logger.isDebugEnabled()) - logger.debug("Total rows = " + totalRows + ", current batch size = " + currentBatchSize); - - org.alfresco.repo.webservice.types.ResultSet batchResults = new org.alfresco.repo.webservice.types.ResultSet(); - org.alfresco.repo.webservice.types.ResultSetRow[] rows = new org.alfresco.repo.webservice.types.ResultSetRow[currentBatchSize]; - - int arrPos = 0; - for (int x = this.position; x < lastRow; x++) - { - ChildAssociationRef assoc = kids.get(x); - NodeRef childNodeRef = assoc.getChildRef(); - ResultSetRowNode rowNode = createResultSetRowNode(childNodeRef, nodeService); - - // create columns for all the properties of the node - // get the data for the row and build up the columns structure - Map props = nodeService.getProperties(childNodeRef); - NamedValue[] columns = new NamedValue[props.size()+5]; - int col = 0; - for (QName propName : props.keySet()) - { - columns[col] = Utils.createNamedValue(dictionaryService, propName, props.get(propName)); - col++; - } - - // Now add the system columns containing the association details - columns[col] = new NamedValue(SYS_COL_ASSOC_TYPE, Boolean.FALSE, assoc.getTypeQName().toString(), null); - col++; - columns[col] = new NamedValue(SYS_COL_ASSOC_NAME, Boolean.FALSE, assoc.getQName().toString(), null); - col++; - columns[col] = new NamedValue(SYS_COL_IS_PRIMARY, Boolean.FALSE, Boolean.toString(assoc.isPrimary()), null); - col++; - columns[col] = new NamedValue(SYS_COL_NTH_SIBLING, Boolean.FALSE, Integer.toString(assoc.getNthSibling()), null); - - // Add one more column for the node's path - col++; - columns[col] = Utils.createNamedValue(dictionaryService, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "path"), nodeService.getPath(childNodeRef).toString()); - - ResultSetRow row = new ResultSetRow(); - row.setRowIndex(x); - row.setNode(rowNode); - row.setColumns(columns); - - // add the row to the overall results - rows[arrPos] = row; - arrPos++; - } - - // add the rows to the result set and set the total row count - batchResults.setRows(rows); - batchResults.setTotalRowCount(totalRows); - - queryResult = new QueryResult(getId(), batchResults); - - // move the position on - updatePosition(totalRows, queryResult); - - if (logger.isDebugEnabled()) - logger.debug("After getNextResultsBatch: " + toString()); - } - - return queryResult; - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - StringBuilder builder = new StringBuilder(super.toString()); - builder.append(" (id=").append(getId()); - builder.append(" batchSize=").append(this.batchSize); - builder.append(" position=").append(this.position); - builder.append(" node-id=").append(this.node.getUuid()).append(")"); - return builder.toString(); - } -} diff --git a/source/java/org/alfresco/repo/webservice/repository/ParentAssociationQuery.java b/source/java/org/alfresco/repo/webservice/repository/ParentAssociationQuery.java new file mode 100644 index 0000000000..00d5c67193 --- /dev/null +++ b/source/java/org/alfresco/repo/webservice/repository/ParentAssociationQuery.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webservice.repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.webservice.AbstractQuery; +import org.alfresco.repo.webservice.Utils; +import org.alfresco.repo.webservice.types.NamedValue; +import org.alfresco.repo.webservice.types.Reference; +import org.alfresco.repo.webservice.types.ResultSet; +import org.alfresco.repo.webservice.types.ResultSetRow; +import org.alfresco.repo.webservice.types.ResultSetRowNode; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +/** + * A query to retrieve all parent associations on a node. + * + * @author Derek Hulley + * @since 2.1 + */ +public class ParentAssociationQuery extends AbstractQuery +{ + private static final long serialVersionUID = -4157476722256947274L; + + private Reference node; + + /** + * @param node + * The node to query against + */ + public ParentAssociationQuery(Reference node) + { + this.node = node; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(128); + sb.append("ParentAssociationQuery") + .append("[ node=").append(node.getUuid()) + .append("]"); + return sb.toString(); + } + + /** + * {@inheritDoc} + */ + public ResultSet execute(ServiceRegistry serviceRegistry) + { + SearchService searchService = serviceRegistry.getSearchService(); + NodeService nodeService = serviceRegistry.getNodeService(); + DictionaryService dictionaryService = serviceRegistry.getDictionaryService(); + NamespaceService namespaceService = serviceRegistry.getNamespaceService(); + + // create the node ref and get the parent from the repository + NodeRef nodeRef = Utils.convertToNodeRef(node, nodeService, searchService, namespaceService); + List assocRefs = nodeService.getParentAssocs(nodeRef); + + int totalRows = assocRefs.size(); + + ResultSet results = new ResultSet(); + ResultSetRow[] rows = new ResultSetRow[totalRows]; + + int index = 0; + for (ChildAssociationRef assocRef : assocRefs) + { + NodeRef parentNodeRef = assocRef.getParentRef(); + ResultSetRowNode rowNode = createResultSetRowNode(parentNodeRef, nodeService); + + // create columns for all the properties of the node + // get the data for the row and build up the columns structure + Map props = nodeService.getProperties(parentNodeRef); + NamedValue[] columns = new NamedValue[props.size()+5]; + int col = 0; + for (QName propName : props.keySet()) + { + columns[col] = Utils.createNamedValue(dictionaryService, propName, props.get(propName)); + col++; + } + + // Now add the system columns containing the association details + columns[col] = new NamedValue(SYS_COL_ASSOC_TYPE, Boolean.FALSE, assocRef.getTypeQName().toString(), null); + col++; + columns[col] = new NamedValue(SYS_COL_ASSOC_NAME, Boolean.FALSE, assocRef.getQName().toString(), null); + col++; + columns[col] = new NamedValue(SYS_COL_IS_PRIMARY, Boolean.FALSE, Boolean.toString(assocRef.isPrimary()), null); + col++; + columns[col] = new NamedValue(SYS_COL_NTH_SIBLING, Boolean.FALSE, Integer.toString(assocRef.getNthSibling()), null); + + // Add one more column for the node's path + col++; + columns[col] = Utils.createNamedValue( + dictionaryService, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "path"), + nodeService.getPath(parentNodeRef).toString()); + + ResultSetRow row = new ResultSetRow(); + row.setRowIndex(index); + row.setNode(rowNode); + row.setColumns(columns); + + // add the row to the overall results + rows[index] = row; + index++; + } + + // add the rows to the result set and set the total row count + results.setRows(rows); + results.setTotalRowCount(totalRows); + + return results; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/webservice/repository/ParentsQuerySession.java b/source/java/org/alfresco/repo/webservice/repository/ParentsQuerySession.java deleted file mode 100644 index 935171519f..0000000000 --- a/source/java/org/alfresco/repo/webservice/repository/ParentsQuerySession.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.webservice.repository; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.webservice.Utils; -import org.alfresco.repo.webservice.types.NamedValue; -import org.alfresco.repo.webservice.types.Reference; -import org.alfresco.repo.webservice.types.ResultSetRow; -import org.alfresco.repo.webservice.types.ResultSetRowNode; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Implementation of a QuerySession that stores the results from a query for parents - * - * @author gavinc - */ -public class ParentsQuerySession extends AbstractQuerySession -{ - private static final long serialVersionUID = 2539375863409175463L; - - private transient static Log logger = LogFactory.getLog(ParentsQuerySession.class); - - private Reference node; - - /** - * Constructs a ParentsQuerySession - * - * @param batchSize The batch size to use for this session - * @param node The node to retrieve the parents - */ - public ParentsQuerySession(int batchSize, Reference node) - { - super(batchSize); - - this.node = node; - } - - /** - * @see org.alfresco.repo.webservice.repository.QuerySession#getNextResultsBatch(org.alfresco.service.cmr.search.SearchService, org.alfresco.service.cmr.repository.NodeService, org.alfresco.service.namespace.NamespaceService) - */ - public QueryResult getNextResultsBatch(SearchService searchService, NodeService nodeService, NamespaceService namespaceService, DictionaryService dictionaryService) - { - QueryResult queryResult = null; - - if (this.position != -1) - { - if (logger.isDebugEnabled()) - logger.debug("Before getNextResultsBatch: " + toString()); - - // create the node ref and get the children from the repository - NodeRef nodeRef = Utils.convertToNodeRef(this.node, nodeService, searchService, namespaceService); - List parents = nodeService.getParentAssocs(nodeRef); - - int totalRows = parents.size(); - int lastRow = calculateLastRowIndex(totalRows); - int currentBatchSize = lastRow - this.position; - - if (logger.isDebugEnabled()) - logger.debug("Total rows = " + totalRows + ", current batch size = " + currentBatchSize); - - org.alfresco.repo.webservice.types.ResultSet batchResults = new org.alfresco.repo.webservice.types.ResultSet(); - org.alfresco.repo.webservice.types.ResultSetRow[] rows = new org.alfresco.repo.webservice.types.ResultSetRow[currentBatchSize]; - - int arrPos = 0; - for (int x = this.position; x < lastRow; x++) - { - ChildAssociationRef assoc = parents.get(x); - NodeRef parentNodeRef = assoc.getParentRef(); - ResultSetRowNode rowNode = createResultSetRowNode(parentNodeRef, nodeService); - - // create columns for all the properties of the node - // get the data for the row and build up the columns structure - Map props = nodeService.getProperties(parentNodeRef); - NamedValue[] columns = new NamedValue[props.size()+5]; - int col = 0; - for (QName propName : props.keySet()) - { - columns[col] = Utils.createNamedValue(dictionaryService, propName, props.get(propName)); - col++; - } - - // Now add the system columns containing the association details - columns[col] = new NamedValue(SYS_COL_ASSOC_TYPE, Boolean.FALSE, assoc.getTypeQName().toString(), null); - col++; - columns[col] = new NamedValue(SYS_COL_ASSOC_NAME, Boolean.FALSE, assoc.getQName().toString(), null); - col++; - columns[col] = new NamedValue(SYS_COL_IS_PRIMARY, Boolean.FALSE, Boolean.toString(assoc.isPrimary()), null); - col++; - columns[col] = new NamedValue(SYS_COL_NTH_SIBLING, Boolean.FALSE, Integer.toString(assoc.getNthSibling()), null); - // Add one more column for the node's path - col++; - columns[col] = Utils.createNamedValue(dictionaryService, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "path"), nodeService.getPath(parentNodeRef).toString()); - - ResultSetRow row = new ResultSetRow(); - row.setRowIndex(x); - row.setNode(rowNode); - row.setColumns(columns); - - // add the row to the overall results - rows[arrPos] = row; - arrPos++; - } - - // add the rows to the result set and set the total row count - batchResults.setRows(rows); - batchResults.setTotalRowCount(totalRows); - - queryResult = new QueryResult(getId(), batchResults); - - // move the position on - updatePosition(totalRows, queryResult); - - if (logger.isDebugEnabled()) - logger.debug("After getNextResultsBatch: " + toString()); - } - - return queryResult; - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - StringBuilder builder = new StringBuilder(super.toString()); - builder.append(" (id=").append(getId()); - builder.append(" batchSize=").append(this.batchSize); - builder.append(" position=").append(this.position); - builder.append(" node-id=").append(this.node.getUuid()).append(")"); - return builder.toString(); - } -} diff --git a/source/java/org/alfresco/repo/webservice/repository/RepositoryQuerySession.java b/source/java/org/alfresco/repo/webservice/repository/RepositoryQuerySession.java new file mode 100644 index 0000000000..67c99c6ce3 --- /dev/null +++ b/source/java/org/alfresco/repo/webservice/repository/RepositoryQuerySession.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webservice.repository; + +import org.alfresco.repo.webservice.AbstractQuerySession; +import org.alfresco.repo.webservice.ServerQuery; +import org.alfresco.repo.webservice.types.ResultSet; +import org.alfresco.repo.webservice.types.ResultSetRow; +import org.alfresco.service.ServiceRegistry; + +/** + * A query session for use with {@linkplain RepositoryWebService node-related queries} against the + * repository. + * + * @author Derek Hulley + * @since 2.1 + */ +public class RepositoryQuerySession extends AbstractQuerySession +{ + private static final long serialVersionUID = -3621997639261137000L; + + public RepositoryQuerySession(long maxResults, long batchSize, ServerQuery query) + { + super(maxResults, batchSize, query); + } + + @Override + protected ResultSetRow[] makeArray(int size) + { + return new ResultSetRow[size]; + } + + public ResultSet getNextResults(ServiceRegistry serviceRegistry) + { + ResultSet queryResults = getQueryResults(serviceRegistry); + ResultSetRow[] allRows = queryResults.getRows(); + ResultSetRow[] batchedRows = getNextResults(allRows); + // Build the resultset for the batched results + ResultSet batchedResults = new ResultSet(); + batchedResults.setMetaData(queryResults.getMetaData()); + batchedResults.setRows(batchedRows); + batchedResults.setTotalRowCount(batchedRows.length); + // Done + return batchedResults; + } +} diff --git a/source/java/org/alfresco/repo/webservice/repository/RepositoryWebService.java b/source/java/org/alfresco/repo/webservice/repository/RepositoryWebService.java index 1389a89402..0e5ba72e60 100644 --- a/source/java/org/alfresco/repo/webservice/repository/RepositoryWebService.java +++ b/source/java/org/alfresco/repo/webservice/repository/RepositoryWebService.java @@ -31,10 +31,10 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.webservice.AbstractWebService; import org.alfresco.repo.webservice.CMLUtil; +import org.alfresco.repo.webservice.ServerQuery; import org.alfresco.repo.webservice.Utils; import org.alfresco.repo.webservice.types.CML; import org.alfresco.repo.webservice.types.ClassDefinition; @@ -44,9 +44,9 @@ import org.alfresco.repo.webservice.types.NodeDefinition; import org.alfresco.repo.webservice.types.Predicate; import org.alfresco.repo.webservice.types.Query; import org.alfresco.repo.webservice.types.Reference; +import org.alfresco.repo.webservice.types.ResultSet; import org.alfresco.repo.webservice.types.Store; import org.alfresco.service.cmr.dictionary.AspectDefinition; -import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; @@ -67,23 +67,8 @@ public class RepositoryWebService extends AbstractWebService implements { private static Log logger = LogFactory.getLog(RepositoryWebService.class); - private DictionaryService dictionaryService; - private CMLUtil cmlUtil; - private SimpleCache querySessionCache; - - /** - * Sets the instance of the DictionaryService to be used - * - * @param dictionaryService - * The DictionaryService - */ - public void setDictionaryService(DictionaryService dictionaryService) - { - this.dictionaryService = dictionaryService; - } - /** * Sets the CML Util * @@ -94,18 +79,6 @@ public class RepositoryWebService extends AbstractWebService implements this.cmlUtil = cmlUtil; } - /** - * Sets the instance of the SimpleCache to be used - * - * @param querySessionCache - * The SimpleCache - */ - public void setQuerySessionCache( - SimpleCache querySessionCache) - { - this.querySessionCache = querySessionCache; - } - /** * {@inheritDoc} */ @@ -156,11 +129,58 @@ public class RepositoryWebService extends AbstractWebService implements } } + /** + * Executes the given query, caching the results as required. + */ + private QueryResult executeQuery(final MessageContext msgContext, final ServerQuery query) throws RepositoryFault + { + try + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public QueryResult execute() throws Throwable + { + // Construct a session to handle the iteration + long batchSize = Utils.getBatchSize(msgContext); + RepositoryQuerySession session = new RepositoryQuerySession(Long.MAX_VALUE, batchSize, query); + String sessionId = session.getId(); + + // Get the first batch of results + ResultSet batchedResults = session.getNextResults(serviceRegistry); + // Construct the result + // TODO: http://issues.alfresco.com/browse/AR-1689 + boolean haveMoreResults = session.haveMoreResults(); + QueryResult queryResult = new QueryResult( + haveMoreResults ? sessionId : null, + batchedResults); + + // Cache the session + if (session.haveMoreResults()) + { + querySessionCache.put(sessionId, session); + } + + // Done + return queryResult; + } + }; + return Utils.getRetryingTransactionHelper(MessageContext.getCurrentContext()).doInTransaction(callback, true); + } + catch (Throwable e) + { + if (logger.isDebugEnabled()) + { + logger.error("Unexpected error occurred", e); + } + e.printStackTrace(); + throw new RepositoryFault(0, e.toString()); + } + } + /** * {@inheritDoc} */ - public QueryResult query(final Store store, final Query query, final boolean includeMetaData) - throws RemoteException, RepositoryFault + public QueryResult query(final Store store, final Query query, final boolean includeMetaData) throws RemoteException, RepositoryFault { String language = query.getLanguage(); if (language.equals(Utils.QUERY_LANG_LUCENE) == false) @@ -171,131 +191,52 @@ public class RepositoryWebService extends AbstractWebService implements } final MessageContext msgContext = MessageContext.getCurrentContext(); - try - { - RetryingTransactionCallback callback = new RetryingTransactionCallback() - { - public QueryResult execute() throws Throwable - { - // setup a query session and get the first batch of results - QuerySession querySession = new ResultSetQuerySession(Utils - .getBatchSize(msgContext), store, query, includeMetaData); - QueryResult queryResult = querySession - .getNextResultsBatch(searchService, nodeService, namespaceService, dictionaryService); - - // add the session to the cache if there are more results to come - if (queryResult.getQuerySession() != null) - { - // this.querySessionCache.putQuerySession(querySession); - querySessionCache.put(queryResult.getQuerySession(), querySession); - } - - return queryResult; - } - }; - return Utils.getRetryingTransactionHelper(MessageContext.getCurrentContext()).doInTransaction(callback); - } - catch (Throwable e) - { - if (logger.isDebugEnabled()) - { - logger.error("Unexpected error occurred", e); - } - e.printStackTrace(); - throw new RepositoryFault(0, e.toString()); - } + SearchQuery serverQuery = new SearchQuery(store, query); + QueryResult queryResult = executeQuery(msgContext, serverQuery); + // Done + return queryResult; } /** * {@inheritDoc} */ - public QueryResult queryChildren(final Reference node) throws RemoteException, - RepositoryFault + public QueryResult queryChildren(final Reference node) throws RemoteException, RepositoryFault { - try - { - RetryingTransactionCallback callback = new RetryingTransactionCallback() - { - public QueryResult execute() throws Throwable - { - // setup a query session and get the first batch of results - QuerySession querySession = new ChildrenQuerySession(Utils - .getBatchSize(MessageContext.getCurrentContext()), node); - QueryResult queryResult = querySession - .getNextResultsBatch(searchService, nodeService, namespaceService, dictionaryService); - - // add the session to the cache if there are more results to come - if (queryResult.getQuerySession() != null) - { - querySessionCache.put(queryResult.getQuerySession(), querySession); - } - - if (logger.isDebugEnabled()) - { - logger.debug("Method end ... queryChildren"); - } - - return queryResult; - } - }; - return Utils.getRetryingTransactionHelper(MessageContext.getCurrentContext()).doInTransaction(callback); - } - catch (Throwable e) - { - if (logger.isDebugEnabled()) - { - logger.error("Unexpected error occurred", e); - } - e.printStackTrace(); - throw new RepositoryFault(0, e.toString()); - } + final MessageContext msgContext = MessageContext.getCurrentContext(); + ChildAssociationQuery query = new ChildAssociationQuery(node); + QueryResult queryResult = executeQuery(msgContext, query); + // Done + return queryResult; } - + /** * {@inheritDoc} */ public QueryResult queryParents(final Reference node) throws RemoteException, RepositoryFault { - try - { - RetryingTransactionCallback callback = new RetryingTransactionCallback() - { - public QueryResult execute() throws Throwable - { - // setup a query session and get the first batch of results - QuerySession querySession = new ParentsQuerySession(Utils - .getBatchSize(MessageContext.getCurrentContext()), node); - QueryResult queryResult = querySession.getNextResultsBatch( - searchService, nodeService, namespaceService, dictionaryService); - - // add the session to the cache if there are more results to come - if (queryResult.getQuerySession() != null) - { - // this.querySessionCache.putQuerySession(querySession); - querySessionCache.put(queryResult.getQuerySession(), querySession); - } - - return queryResult; - } - }; - return Utils.getRetryingTransactionHelper(MessageContext.getCurrentContext()).doInTransaction(callback); - - } - catch (Throwable e) - { - if (logger.isDebugEnabled()) - { - logger.error("Unexpected error occurred", e); - } - throw new RepositoryFault(0, e.toString()); - } + final MessageContext msgContext = MessageContext.getCurrentContext(); + ParentAssociationQuery query = new ParentAssociationQuery(node); + QueryResult queryResult = executeQuery(msgContext, query); + // Done + return queryResult; } /** * {@inheritDoc} */ - public QueryResult queryAssociated(final Reference node, final Association association) - throws RemoteException, RepositoryFault + public QueryResult queryAssociated(final Reference node, final Association association) throws RemoteException, RepositoryFault + { + final MessageContext msgContext = MessageContext.getCurrentContext(); + AssociationQuery query = new AssociationQuery(node, association); + QueryResult queryResult = executeQuery(msgContext, query); + // Done + return queryResult; + } + + /** + * {@inheritDoc} + */ + public QueryResult fetchMore(final String querySessionId) throws RemoteException, RepositoryFault { try { @@ -303,76 +244,54 @@ public class RepositoryWebService extends AbstractWebService implements { public QueryResult execute() throws Throwable { - // setup a query session and get the first batch of results - QuerySession querySession = new AssociatedQuerySession(Utils.getBatchSize(MessageContext.getCurrentContext()), node, association); - QueryResult queryResult = querySession.getNextResultsBatch(searchService, nodeService, namespaceService, dictionaryService); - - // add the session to the cache if there are more results to come - if (queryResult.getQuerySession() != null) + RepositoryQuerySession session = null; + try { - // this.querySessionCache.putQuerySession(querySession); - querySessionCache.put(queryResult.getQuerySession(), querySession); + // try and get the QuerySession with the given id from the cache + session = (RepositoryQuerySession) querySessionCache.get(querySessionId); + } + catch (ClassCastException e) + { + if (logger.isDebugEnabled()) + { + logger.debug("Query session was not generated by the RepositoryWebService: " + querySessionId); + } + throw new RepositoryFault( + 4, + "querySession with id '" + querySessionId + "' is invalid"); } - - return queryResult; - } - }; - return Utils.getRetryingTransactionHelper(MessageContext.getCurrentContext()).doInTransaction(callback); - } - catch (Throwable e) - { - if (logger.isDebugEnabled()) - { - logger.error("Unexpected error occurred", e); - } - throw new RepositoryFault(0, e.toString()); - } - } - - /** - * {@inheritDoc} - */ - public QueryResult fetchMore(final String querySession) throws RemoteException, RepositoryFault - { - try - { - RetryingTransactionCallback callback = new RetryingTransactionCallback() - { - public QueryResult execute() throws Throwable - { - // try and get the QuerySession with the given id from the cache - QuerySession session = querySessionCache.get(querySession); if (session == null) { if (logger.isDebugEnabled()) { - logger.debug("Invalid querySession id requested: " + querySession); + logger.debug("Invalid querySession id requested: " + querySessionId); } - throw new RepositoryFault( 4, - "querySession with id '" + querySession + "' is invalid"); + "querySession with id '" + querySessionId + "' is invalid"); + } + + ResultSet moreResults = session.getNextResults(serviceRegistry); + + // Drop the cache results if there are no more results expected + if (!session.haveMoreResults()) + { + querySessionCache.remove(querySessionId); } // get the next batch of results - QueryResult queryResult = session.getNextResultsBatch( - searchService, - nodeService, - namespaceService, - dictionaryService); - - // remove the QuerySession from the cache if there are no more - // results to come - if (queryResult.getQuerySession() == null) - { - querySessionCache.remove(querySession); - } + // TODO: http://issues.alfresco.com/browse/AR-1689 + boolean haveMoreResults = session.haveMoreResults(); + QueryResult queryResult = new QueryResult( + haveMoreResults ? querySessionId : null, + moreResults); + // Done return queryResult; } }; - return Utils.getRetryingTransactionHelper(MessageContext.getCurrentContext()).doInTransaction(callback); + return Utils.getRetryingTransactionHelper(MessageContext.getCurrentContext()).doInTransaction(callback, true); } catch (Throwable e) { diff --git a/source/java/org/alfresco/repo/webservice/repository/ResultSetQuerySession.java b/source/java/org/alfresco/repo/webservice/repository/ResultSetQuerySession.java deleted file mode 100644 index 3a455d3874..0000000000 --- a/source/java/org/alfresco/repo/webservice/repository/ResultSetQuerySession.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.webservice.repository; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.webservice.Utils; -import org.alfresco.repo.webservice.types.NamedValue; -import org.alfresco.repo.webservice.types.Query; -import org.alfresco.repo.webservice.types.ResultSetRowNode; -import org.alfresco.repo.webservice.types.Store; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.Path; -import org.alfresco.service.cmr.search.ResultSet; -import org.alfresco.service.cmr.search.ResultSetRow; -import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Implementation of a QuerySession that retrieves results from a repository ResultSet - * - * @author gavinc - */ -public class ResultSetQuerySession extends AbstractQuerySession -{ - private static final long serialVersionUID = -9154514445963635138L; - - private transient static Log logger = LogFactory.getLog(ResultSetQuerySession.class); - - private Store store; - private Query query; - @SuppressWarnings("unused") - private boolean includeMetaData; - - /** - * Constructs a ResultSetQuerySession - * - * @param batchSize The batch size to use for this session - * @param store The repository store to query against - * @param query The query to execute - * @param includeMetaData Whether to include metadata in the query results - */ - public ResultSetQuerySession(int batchSize, Store store, Query query, boolean includeMetaData) - { - super(batchSize); - - this.store = store; - this.query = query; - this.includeMetaData = includeMetaData; - } - - /** - * @see org.alfresco.repo.webservice.repository.QuerySession#getNextResultsBatch(org.alfresco.service.cmr.search.SearchService, org.alfresco.service.cmr.repository.NodeService, org.alfresco.service.namespace.NamespaceService) - */ - public QueryResult getNextResultsBatch(SearchService searchService, NodeService nodeService, NamespaceService namespaceService, DictionaryService dictionaryService) - { - QueryResult queryResult = null; - - if (this.position != -1) - { - if (logger.isDebugEnabled()) - logger.debug("Before getNextResultsBatch: " + toString()); - - // handle the special search string of * meaning, get everything - String statement = query.getStatement(); - if (statement.equals("*")) - { - statement = "ISNODE:*"; - } - ResultSet searchResults = null; - try - { - searchResults = searchService.query(Utils.convertToStoreRef(this.store), - this.query.getLanguage(), statement); - - int totalRows = searchResults.length(); - int lastRow = calculateLastRowIndex(totalRows); - int currentBatchSize = lastRow - this.position; - - if (logger.isDebugEnabled()) - logger.debug("Total rows = " + totalRows + ", current batch size = " + currentBatchSize); - - org.alfresco.repo.webservice.types.ResultSet batchResults = new org.alfresco.repo.webservice.types.ResultSet(); - List rowList = - new ArrayList(); - - for (int x = this.position; x < lastRow; x++) - { - ResultSetRow origRow = searchResults.getRow(x); - NodeRef nodeRef = origRow.getNodeRef(); - - // search can return nodes that no longer exist, so we need to ignore these - if(nodeService.exists(nodeRef) == false) - { - if(logger.isDebugEnabled()) - { - logger.warn("Search returned node that doesn't exist: " + nodeRef); - } - continue; - } - - ResultSetRowNode rowNode = createResultSetRowNode(nodeRef, nodeService); - - // get the data for the row and build up the columns structure - Map values = origRow.getValues(); - NamedValue[] columns = new NamedValue[values.size() + 1]; - int col = 0; - for (Path path : values.keySet()) - { - // Get the attribute QName from the result path - String attributeName = path.last().toString(); - if (attributeName.startsWith("@") == true) - { - attributeName = attributeName.substring(1); - } - - columns[col] = Utils.createNamedValue(dictionaryService, QName.createQName(attributeName), values.get(path)); - col++; - } - - // add one extra column for the node's path - columns[col] = Utils.createNamedValue(dictionaryService, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "path"), nodeService.getPath(nodeRef).toString()); - - org.alfresco.repo.webservice.types.ResultSetRow row = new org.alfresco.repo.webservice.types.ResultSetRow(); - row.setColumns(columns); - row.setScore(origRow.getScore()); - row.setRowIndex(x); - row.setNode(rowNode); - - // add the row to the overall results list - rowList.add(row); - } - - // TODO: build up the meta data data structure if we've been asked to - - // add the rows to the result set and set the total row count - org.alfresco.repo.webservice.types.ResultSetRow[] rows = - rowList.toArray(new org.alfresco.repo.webservice.types.ResultSetRow[rowList.size()]);; - batchResults.setRows(rows); - batchResults.setTotalRowCount(totalRows); - - queryResult = new QueryResult(getId(), batchResults); - - // move the position on - updatePosition(totalRows, queryResult); - - if (logger.isDebugEnabled()) - logger.debug("After getNextResultsBatch: " + toString()); - } - finally - { - if (searchResults != null) - { - searchResults.close(); - } - } - } - - return queryResult; - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - StringBuilder builder = new StringBuilder(super.toString()); - builder.append(" (id=").append(getId()); - builder.append(" batchSize=").append(this.batchSize); - builder.append(" position=").append(this.position); - builder.append(" store=").append(this.store.getScheme()).append(":").append(this.store.getAddress()); - builder.append(" language=").append(this.query.getLanguage()); - builder.append(" statement=").append(this.query.getStatement()); - builder.append(")"); - return builder.toString(); - } -} diff --git a/source/java/org/alfresco/repo/webservice/repository/SearchQuery.java b/source/java/org/alfresco/repo/webservice/repository/SearchQuery.java new file mode 100644 index 0000000000..d5bc6c18d8 --- /dev/null +++ b/source/java/org/alfresco/repo/webservice/repository/SearchQuery.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webservice.repository; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.webservice.AbstractQuery; +import org.alfresco.repo.webservice.Utils; +import org.alfresco.repo.webservice.types.NamedValue; +import org.alfresco.repo.webservice.types.Query; +import org.alfresco.repo.webservice.types.ResultSet; +import org.alfresco.repo.webservice.types.ResultSetRow; +import org.alfresco.repo.webservice.types.ResultSetRowNode; +import org.alfresco.repo.webservice.types.Store; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.Path; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +/** + * A query to using full search. + * + * @author Derek Hulley + * @since 2.1 + */ +public class SearchQuery extends AbstractQuery +{ + private static final long serialVersionUID = 5429510102265380433L; + + private Store store; + private Query query; + + /** + * @param node The node to query against + * @param association The association type to query or null to query all + */ + public SearchQuery(Store store, Query query) + { + this.store = store; + this.query = query; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(128); + sb.append("SearchQuery") + .append("[ store=").append(this.store.getScheme()).append(":").append(this.store.getAddress()) + .append(" language=").append(this.query.getLanguage()) + .append(" statement=").append(this.query.getStatement()) + .append("]"); + return sb.toString(); + } + + /** + * {@inheritDoc} + */ + public ResultSet execute(ServiceRegistry serviceRegistry) + { + SearchService searchService = serviceRegistry.getSearchService(); + NodeService nodeService = serviceRegistry.getNodeService(); + DictionaryService dictionaryService = serviceRegistry.getDictionaryService(); + + // handle the special search string of * meaning, get everything + String statement = query.getStatement(); + if (statement.equals("*")) + { + statement = "ISNODE:*"; + } + org.alfresco.service.cmr.search.ResultSet searchResults = null; + try + { + StoreRef storeRef = Utils.convertToStoreRef(store); + searchResults = searchService.query(storeRef, query.getLanguage(), statement); + return convert( + nodeService, + dictionaryService, + searchResults); + } + finally + { + if (searchResults != null) + { + try + { + searchResults.close(); + } + catch (Throwable e) + { + } + } + } + } + + private ResultSet convert( + NodeService nodeService, + DictionaryService dictionaryService, + org.alfresco.service.cmr.search.ResultSet searchResults) + { + ResultSet results = new ResultSet(); + List rowsList = new ArrayList(); + + int index = 0; + for (org.alfresco.service.cmr.search.ResultSetRow searchRow : searchResults) + { + NodeRef nodeRef = searchRow.getNodeRef(); + // Search can return nodes that no longer exist, so we need to ignore these + if (!nodeService.exists(nodeRef)) + { + continue; + } + ResultSetRowNode rowNode = createResultSetRowNode(nodeRef, nodeService); + + // get the data for the row and build up the columns structure + Map values = searchRow.getValues(); + NamedValue[] columns = new NamedValue[values.size() + 1]; + int col = 0; + for (Path path : values.keySet()) + { + // Get the attribute QName from the result path + String attributeName = path.last().toString(); + if (attributeName.startsWith("@") == true) + { + attributeName = attributeName.substring(1); + } + columns[col] = Utils.createNamedValue(dictionaryService, QName.createQName(attributeName), values.get(path)); + col++; + } + + // add one extra column for the node's path + columns[col] = Utils.createNamedValue(dictionaryService, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "path"), nodeService.getPath(nodeRef).toString()); + + ResultSetRow row = new org.alfresco.repo.webservice.types.ResultSetRow(); + row.setColumns(columns); + row.setScore(searchRow.getScore()); + row.setRowIndex(index); + row.setNode(rowNode); + + // add the row to the overall results list + rowsList.add(row); + index++; + } + + // Convert list to array + int totalRows = rowsList.size(); + ResultSetRow[] rows = rowsList.toArray(new org.alfresco.repo.webservice.types.ResultSetRow[totalRows]); + + // add the rows to the result set and set the total row count + results.setRows(rows); + results.setTotalRowCount(totalRows); + + return results; + } +} \ No newline at end of file diff --git a/source/java/web-services-application-context.xml b/source/java/web-services-application-context.xml index 392a2a95b5..b27e8d565c 100644 --- a/source/java/web-services-application-context.xml +++ b/source/java/web-services-application-context.xml @@ -10,28 +10,6 @@ - - - - - - webservice.QuerySessionCache - - - - - - - - - - - webservice.UserQuerySessionCache - - - - - @@ -63,6 +41,9 @@ + + + @@ -79,7 +60,7 @@ - + @@ -210,6 +191,9 @@ + + + @@ -229,7 +213,7 @@ - +