+ * This uses the bootstrap importer to get the paths to look for. If not present, + * the required structures are created. + *
+ * This class should be replaced with a more generic ImporterPatch
+ * that can do conditional importing into given locations.
+ *
+ * JIRA: {@link http://www.alfresco.org/jira/browse/AR-342 AR-342}
+ *
+ * @author Kevin Roast
+ */
+public class ScriptsFolderPatch extends AbstractPatch
+{
+ private static final String MSG_EXISTS = "patch.scriptsFolder.result.exists";
+ private static final String MSG_CREATED = "patch.scriptsFolder.result.created";
+
+ public static final String PROPERTY_COMPANY_HOME_CHILDNAME = "spaces.company_home.childname";
+ public static final String PROPERTY_DICTIONARY_CHILDNAME = "spaces.dictionary.childname";
+ public static final String PROPERTY_SCRIPTS_FOLDER_CHILDNAME = "spaces.scripts.childname";
+ private static final String PROPERTY_SCRIPTS_FOLDER_NAME = "spaces.scripts.name";
+ private static final String PROPERTY_SCRIPTS_FOLDER_DESCRIPTION = "spaces.scripts.description";
+ private static final String PROPERTY_ICON = "space-icon-default";
+
+ private ImporterBootstrap importerBootstrap;
+ private MessageSource messageSource;
+
+ protected NodeRef dictionaryNodeRef;
+ protected Properties configuration;
+ protected NodeRef scriptsFolderNodeRef;
+
+ public void setImporterBootstrap(ImporterBootstrap importerBootstrap)
+ {
+ this.importerBootstrap = importerBootstrap;
+ }
+
+ public void setMessageSource(MessageSource messageSource)
+ {
+ this.messageSource = messageSource;
+ }
+
+ /**
+ * Ensure that required common properties have been set
+ */
+ protected void checkCommonProperties() throws Exception
+ {
+ if (importerBootstrap == null)
+ {
+ throw new PatchException("'importerBootstrap' property has not been set");
+ }
+ else if (namespaceService == null)
+ {
+ throw new PatchException("'namespaceService' property has not been set");
+ }
+ else if (searchService == null)
+ {
+ throw new PatchException("'searchService' property has not been set");
+ }
+ else if (nodeService == null)
+ {
+ throw new PatchException("'nodeService' property has not been set");
+ }
+ }
+
+ /**
+ * Extracts pertinent references and properties that are common to execution
+ * of this and derived patches.
+ */
+ protected void setUp() throws Exception
+ {
+ // get the node store that we must work against
+ StoreRef storeRef = importerBootstrap.getStoreRef();
+ if (storeRef == null)
+ {
+ throw new PatchException("Bootstrap store has not been set");
+ }
+ NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
+
+ this.configuration = importerBootstrap.getConfiguration();
+ // get the association names that form the path
+ String companyHomeChildName = configuration.getProperty(PROPERTY_COMPANY_HOME_CHILDNAME);
+ if (companyHomeChildName == null || companyHomeChildName.length() == 0)
+ {
+ throw new PatchException("Bootstrap property '" + PROPERTY_COMPANY_HOME_CHILDNAME + "' is not present");
+ }
+ String dictionaryChildName = configuration.getProperty(PROPERTY_DICTIONARY_CHILDNAME);
+ if (dictionaryChildName == null || dictionaryChildName.length() == 0)
+ {
+ throw new PatchException("Bootstrap property '" + PROPERTY_DICTIONARY_CHILDNAME + "' is not present");
+ }
+ String scriptsChildName = configuration.getProperty(PROPERTY_SCRIPTS_FOLDER_CHILDNAME);
+ if (scriptsChildName == null || scriptsChildName.length() == 0)
+ {
+ throw new PatchException("Bootstrap property '" + PROPERTY_SCRIPTS_FOLDER_CHILDNAME + "' is not present");
+ }
+
+ // build the search string to get the dictionary node
+ StringBuilder sb = new StringBuilder(256);
+ sb.append("/").append(companyHomeChildName)
+ .append("/").append(dictionaryChildName);
+ String xpath = sb.toString();
+
+ // get the dictionary node
+ List
+ * Node class implementation, specific for use by ScriptService as part of the object model.
*
* The class exposes Node properties, children and assocs as dynamically populated maps and lists.
* The various collection classes are mirrored as JavaScript properties. So can be accessed using
- * standard JavaScript syntax, such as
* Various helper methods are provided to access common and useful node variables such
* as the content url and type information.
@@ -270,24 +268,6 @@ public final class Node implements Serializable
// return childrenByXPath(xpath);
//}
- /**
- * @return A map capable of returning a List of Node objects from an NodeRef to a Saved Search
- * object. The Saved Search is executed and the resulting nodes supplied as a sequence.
- */
- //public Map getChildrenBySavedSearch()
- //{
- // return new SavedSearchResultsMap(this, this.services);
- //}
-
- /**
- * @return A map capable of returning a List of Node objects from an NodeRef to a Lucene search
- * string. The Saved Search is executed and the resulting nodes supplied as a sequence.
- */
- //public Map getChildrenByLuceneSearch()
- //{
- // return new LuceneSearchResultsMap(this, this.services);
- //}
-
/**
* Return the associations for this Node. As a Map of assoc name to an Array of Nodes.
*
diff --git a/source/java/org/alfresco/repo/jscript/RhinoScriptService.java b/source/java/org/alfresco/repo/jscript/RhinoScriptService.java
index 788dc42275..8945d66111 100644
--- a/source/java/org/alfresco/repo/jscript/RhinoScriptService.java
+++ b/source/java/org/alfresco/repo/jscript/RhinoScriptService.java
@@ -21,10 +21,12 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
+import java.util.HashMap;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
+import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -221,4 +223,46 @@ public class RhinoScriptService implements ScriptService
cx.exit();
}
}
+
+ /**
+ * Create the default data-model available to scripts as global scope level objects:
+ *
+ * 'companyhome' - the Company Home node
+ * Provides access to Lucene search facilities including saved search objects. The results
+ * from a search are returned as an array (collection) of scriptable Node wrapper objects.
+ *
+ * The object is added to the root of the model to provide syntax such as:
+ * node.children[0].properties.name
.
+ * standard JavaScript property syntax, such as node.children[0].properties.name
.
*
+ * 'userhome' - the current user home space node
+ * 'person' - the node representing the current user Person
+ * 'document' - document context node (may not be available)
+ * 'space' - space context node (may not be available)
+ *
+ * @param services ServiceRegistry
+ * @param person The current user Person Node
+ * @param companyHome The CompanyHome ref
+ * @param userHome The User home space ref
+ * @param document Optional ref to a document Node
+ * @param space Optional ref to a space Node
+ *
+ * @return A Map of global scope scriptable Node objects
+ */
+ public static Mapvar results = search.luceneSearch(statement);
+ * and
+ * var results = search.savedSearch(node);
+ *
+ * @author Kevin Roast
+ */
+public final class Search
+{
+ private static Log logger = LogFactory.getLog(Search.class);
+
+ private ServiceRegistry services;
+ private StoreRef storeRef;
+ private TemplateImageResolver imageResolver;
+
+
+ /**
+ * Constructor
+ *
+ * @param services The ServiceRegistry to use
+ */
+ public Search(ServiceRegistry services, StoreRef storeRef, TemplateImageResolver imageResolver)
+ {
+ this.services = services;
+ this.storeRef = storeRef;
+ this.imageResolver = imageResolver;
+ }
+
+ /**
+ * Execute a Lucene search
+ *
+ * @param search Lucene search string to execute
+ *
+ * @return Node[] of results from the search - can be empty but not null
+ */
+ public Node[] luceneSearch(String search)
+ {
+ return query(search);
+ }
+
+ /**
+ * Execute a saved Lucene search
+ *
+ * @param savedSearch Node that contains the saved lucene search content
+ *
+ * @return Node[] of results from the search - can be empty but not null
+ */
+ public Node[] savedSearch(Node savedSearch)
+ {
+ String search = null;
+
+ // read the Saved Search XML on the specified node - and get the Lucene search from it
+ try
+ {
+ ContentReader content = this.services.getContentService().getReader(
+ savedSearch.getNodeRef(), ContentModel.PROP_CONTENT);
+ if (content != null && content.exists())
+ {
+ // get the root element
+ SAXReader reader = new SAXReader();
+ Document document = reader.read(new StringReader(content.getContentString()));
+ Element rootElement = document.getRootElement();
+
+ Element queryElement = rootElement.element("query");
+ if (queryElement != null)
+ {
+ search = queryElement.getText();
+ }
+ }
+ }
+ catch (Throwable err)
+ {
+ throw new AlfrescoRuntimeException("Failed to find or load saved Search: " + savedSearch.getNodeRef(), err);
+ }
+
+ return search != null ? query(search) : new Node[0];
+ }
+
+ private Node[] query(String search)
+ {
+ Node[] nodes = null;
+
+ // perform the search against the repo
+ ResultSet results = null;
+ try
+ {
+ results = this.services.getSearchService().query(
+ this.storeRef,
+ SearchService.LANGUAGE_LUCENE,
+ search);
+
+ if (results.length() != 0)
+ {
+ nodes = new Node[results.length()];
+ int count = 0;
+ for (ResultSetRow row: results)
+ {
+ NodeRef nodeRef = row.getNodeRef();
+ nodes[count++] = new Node(nodeRef, services, this.imageResolver);
+ }
+ }
+ }
+ catch (Throwable err)
+ {
+ throw new AlfrescoRuntimeException("Failed to execute search: " + search, err);
+ }
+ finally
+ {
+ if (results != null)
+ {
+ results.close();
+ }
+ }
+
+ return nodes != null ? nodes : new Node[0];
+ }
+}
diff --git a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java
index a4cbfee87f..d7e846d429 100644
--- a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java
+++ b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java
@@ -33,6 +33,7 @@ import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.CopyService;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.ScriptService;
import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.search.CategoryService;
@@ -302,6 +303,14 @@ public class ServiceDescriptorRegistry
*/
public FileFolderService getFileFolderService()
{
- return (FileFolderService) getService(FILE_FOLDER_SERVICE);
+ return (FileFolderService)getService(FILE_FOLDER_SERVICE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.ServiceRegistry#getScriptService()
+ */
+ public ScriptService getScriptService()
+ {
+ return (ScriptService)getService(SCRIPT_SERVICE);
}
}
diff --git a/source/java/org/alfresco/service/ServiceRegistry.java b/source/java/org/alfresco/service/ServiceRegistry.java
index 5cd8917780..1e8683848f 100644
--- a/source/java/org/alfresco/service/ServiceRegistry.java
+++ b/source/java/org/alfresco/service/ServiceRegistry.java
@@ -27,6 +27,7 @@ import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.CopyService;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.ScriptService;
import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.search.CategoryService;
@@ -79,6 +80,7 @@ public interface ServiceRegistry
static final QName AUTHORITY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AuthorityService");
static final QName TEMPLATE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "TemplateService");
static final QName FILE_FOLDER_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "FileFolderService");
+ static final QName SCRIPT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ScriptService");
/**
* Get the list of services provided by the Repository
@@ -220,4 +222,9 @@ public interface ServiceRegistry
* @return the file-folder manipulation service (or null if one is not provided)
*/
FileFolderService getFileFolderService();
+
+ /**
+ * @return the script execution service (or null if one is not provided)
+ */
+ ScriptService getScriptService();
}