. Rhino JavaScript integration checkpoint:

- Added a new action to the repository for executing JavaScript files
  - Added script action UI to rule framework, means we can execute a JavaScript file as part of a rule
  - Lucene search and Saved Search functionality added to default data-model for scripts
  - Added Scripts folder to Data Dictionary (created during bootstrap)
  - Created patch to add the Scripts folder to existing schemas
  - Added ScriptService to ServiceRegistry bean

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2740 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2006-05-03 12:01:21 +00:00
parent 86134ca56f
commit 0d67f51ed9
10 changed files with 309 additions and 39 deletions

View File

@@ -689,6 +689,8 @@ action_check_in=Check in content as ''{0}'' with comment ''{1}''
action_check_out=Check out content to
action_set_property_value=Sets property
action_import=Imports to
action_script=Executes script
action_script_select=Select a script to execute
not_condition_result=Check the item does not match the criteria above
space=Space
import_to=Import To
@@ -720,6 +722,7 @@ creating_from=Creating From
save_as_template=Save As Template
template_name=Template Name
select_a_template=Select a template...
select_a_script=Select a script...
starting_space=Starting Space
space_options=Space Options
space_details=Space Details
@@ -857,6 +860,7 @@ title_action_checkin=Check In Action
title_action_checkout=Check Out Action
title_action_copy=Copy Action
title_action_move=Move Action
title_action_script=Script Action
title_action_import=Import Action
title_action_email=Email Action
title_action_link_category=Link Category Action

View File

@@ -372,6 +372,16 @@
</params>
</action>
<!-- Manage Deleted Items -->
<action id="manage_deleted_items">
<permissions>
<permission allow="true">Write</permission>
</permissions>
<label-id>manage_deleted_items</label-id>
<image>/images/icons/trashcan.gif</image>
<action>dialog:manageDeletedItems</action>
</action>
<!-- Take Ownership of document -->
<action id="take_ownership_doc">
<permissions>
@@ -525,6 +535,7 @@
<action idref="paste_all" />
<action idref="manage_space_users" />
<action idref="manage_space_rules" />
<action idref="manage_deleted_items" />
</action-group>
<!-- Actions Menu for Document Details screen -->

View File

@@ -71,6 +71,7 @@ public class Application
private static String contentTemplatesFolderName;
private static String emailTemplatesFolderName;
private static String savedSearchesFolderName;
private static String scriptsFolderName;
/**
* Private constructor to prevent instantiation of this class
@@ -379,6 +380,23 @@ public class Application
return getSavedSearchesFolderName(FacesContextUtils.getRequiredWebApplicationContext(context));
}
/**
* @return Return the JavaScript scripts folder name
*/
public static String getScriptsFolderName(ServletContext context)
{
return getScriptsFolderName(WebApplicationContextUtils.getRequiredWebApplicationContext(context));
}
/**
* @return Return the JavaScript scripts folder name
*/
public static String getScriptsFolderName(FacesContext context)
{
return getScriptsFolderName(FacesContextUtils.getRequiredWebApplicationContext(context));
}
/**
* Set the language locale for the current user context
*
@@ -728,6 +746,24 @@ public class Application
return savedSearchesFolderName;
}
/**
* Returns the JavaScript scripts folder name
*
* @param context The spring context
* @return The scripts folder name
*/
private static String getScriptsFolderName(WebApplicationContext context)
{
if (scriptsFolderName == null)
{
ImporterBootstrap bootstrap = (ImporterBootstrap)context.getBean(BEAN_IMPORTER_BOOTSTRAP);
Properties configuration = bootstrap.getConfiguration();
scriptsFolderName = configuration.getProperty("spaces.scripts.childname");
}
return scriptsFolderName;
}
/**
* Retrieves the configured error page for the application
*

View File

@@ -549,7 +549,8 @@ public class CheckinCheckoutBean
// calculate which editor screen to display
if (MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(mimetype) ||
MimetypeMap.MIMETYPE_XML.equals(mimetype) ||
MimetypeMap.MIMETYPE_TEXT_CSS.equals(mimetype))
MimetypeMap.MIMETYPE_TEXT_CSS.equals(mimetype) ||
MimetypeMap.MIMETYPE_JAVASCRIPT.equals(mimetype))
{
// make content available to the editing screen
if (reader != null)

View File

@@ -839,11 +839,12 @@ public class DocumentDetailsBean extends BaseDetailsBean
}
if (contentType != null)
{
// set the property to true by default if the filetype is text/HTML content
// set the property to true by default if the filetype is a known content type
if (MimetypeMap.MIMETYPE_HTML.equals(contentType) ||
MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(contentType) ||
MimetypeMap.MIMETYPE_XML.equals(contentType) ||
MimetypeMap.MIMETYPE_TEXT_CSS.equals(contentType))
MimetypeMap.MIMETYPE_TEXT_CSS.equals(contentType) ||
MimetypeMap.MIMETYPE_JAVASCRIPT.equals(contentType))
{
props.put(ContentModel.PROP_EDITINLINE, true);
}

View File

@@ -37,7 +37,7 @@ import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
/**
* Provide access to commonly used lists of templates.
* Provide access to commonly used lists of templates and script files.
* <p>
* The lists are cached for a small period of time to help performance in the client,
* as generally the contents of the template folders are not changed frequently.
@@ -46,6 +46,9 @@ import org.alfresco.web.data.QuickSort;
*/
public class TemplateSupportBean
{
private static final String MSG_SELECT_TEMPLATE = "select_a_template";
private static final String MSG_SELECT_SCRIPT = "select_a_script";
/** "no selection" marker for SelectItem lists */
public static final String NO_SELECTION = "none";
@@ -55,12 +58,15 @@ public class TemplateSupportBean
/** The SearchService instance */
private SearchService searchService;
/** cache of content templates that last 10 seconds - enough for a couple of page refreshes */
private ExpiringValueCache<List<SelectItem>> contentTemplates = new ExpiringValueCache<List<SelectItem>>(1000*10);
/** cache of content templates that lasts 30 seconds - enough for a couple of page refreshes */
private ExpiringValueCache<List<SelectItem>> contentTemplates = new ExpiringValueCache<List<SelectItem>>(1000*30);
/** cache of email templates that last 30 seconds - enough for a few page refreshes */
/** cache of email templates that lasts 30 seconds - enough for a few page refreshes */
private ExpiringValueCache<List<SelectItem>> emailTemplates = new ExpiringValueCache<List<SelectItem>>(1000*30);
/** cache of JavaScript files that lasts 30 seconds - enough for a few page refreshes */
private ExpiringValueCache<List<SelectItem>> scriptFiles = new ExpiringValueCache<List<SelectItem>>(1000*30);
/**
* @param nodeService The NodeService to set.
@@ -92,7 +98,7 @@ public class TemplateSupportBean
Application.getGlossaryFolderName(fc) + "/" +
Application.getContentTemplatesFolderName(fc) + "//*";
templates = selectTemplateNodes(fc, xpath);
templates = selectDictionaryNodes(fc, xpath, MSG_SELECT_TEMPLATE);
contentTemplates.put(templates);
}
@@ -114,7 +120,7 @@ public class TemplateSupportBean
Application.getGlossaryFolderName(fc) + "/" +
Application.getEmailTemplatesFolderName(fc) + "//*";
templates = selectTemplateNodes(fc, xpath);
templates = selectDictionaryNodes(fc, xpath, MSG_SELECT_TEMPLATE);
emailTemplates.put(templates);
}
@@ -123,14 +129,36 @@ public class TemplateSupportBean
}
/**
* @param context FacesContext
* @param xpath XPath to the template nodes to select
*
* @return List of SelectItem object from the template nodes found at the XPath
* @return the list of available JavaScript files that can be applied to the current document.
*/
private List<SelectItem> selectTemplateNodes(FacesContext fc, String xpath)
public List<SelectItem> getScriptFiles()
{
List<SelectItem> templates = null;
List<SelectItem> scripts = this.scriptFiles.get();
if (scripts == null)
{
// get the scripts from the special Scripts folder
FacesContext fc = FacesContext.getCurrentInstance();
String xpath = Application.getRootPath(fc) + "/" +
Application.getGlossaryFolderName(fc) + "/" +
Application.getScriptsFolderName(fc) + "//*";
scripts = selectDictionaryNodes(fc, xpath, MSG_SELECT_SCRIPT);
scriptFiles.put(scripts);
}
return scripts;
}
/**
* @param context FacesContext
* @param xpath XPath to the nodes to select
*
* @return List of SelectItem wrapper objects for the nodes found at the XPath
*/
private List<SelectItem> selectDictionaryNodes(FacesContext fc, String xpath, String noSelectionLabel)
{
List<SelectItem> wrappers = null;
try
{
@@ -138,7 +166,7 @@ public class TemplateSupportBean
NamespaceService resolver = Repository.getServiceRegistry(fc).getNamespaceService();
List<NodeRef> results = this.searchService.selectNodes(rootNodeRef, xpath, null, resolver, false);
templates = new ArrayList<SelectItem>(results.size() + 1);
wrappers = new ArrayList<SelectItem>(results.size() + 1);
if (results.size() != 0)
{
DictionaryService dd = Repository.getServiceRegistry(fc).getDictionaryService();
@@ -149,13 +177,13 @@ public class TemplateSupportBean
Node childNode = new Node(ref);
if (dd.isSubClass(childNode.getType(), ContentModel.TYPE_CONTENT))
{
templates.add(new SelectItem(childNode.getId(), childNode.getName()));
wrappers.add(new SelectItem(childNode.getId(), childNode.getName()));
}
}
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(templates, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
QuickSort sorter = new QuickSort(wrappers, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
}
@@ -164,13 +192,13 @@ public class TemplateSupportBean
// ignore the result if we cannot access the root
}
// add an entry (at the start) to instruct the user to select a template
if (templates == null)
// add an entry (at the start) to instruct the user to select an item
if (wrappers == null)
{
templates = new ArrayList<SelectItem>(1);
wrappers = new ArrayList<SelectItem>(1);
}
templates.add(0, new SelectItem(NO_SELECTION, Application.getMessage(FacesContext.getCurrentInstance(), "select_a_template")));
wrappers.add(0, new SelectItem(NO_SELECTION, Application.getMessage(FacesContext.getCurrentInstance(), noSelectionLabel)));
return templates;
return wrappers;
}
}

View File

@@ -29,6 +29,7 @@ import org.alfresco.repo.action.executer.LinkCategoryActionExecuter;
import org.alfresco.repo.action.executer.MailActionExecuter;
import org.alfresco.repo.action.executer.MoveActionExecuter;
import org.alfresco.repo.action.executer.RemoveFeaturesActionExecuter;
import org.alfresco.repo.action.executer.ScriptActionExecutor;
import org.alfresco.repo.action.executer.SimpleWorkflowActionExecuter;
import org.alfresco.repo.action.executer.SpecialiseTypeActionExecuter;
import org.alfresco.repo.action.executer.TransformActionExecuter;
@@ -94,6 +95,7 @@ public abstract class BaseActionWizard extends BaseWizardBean
public static final String PROP_MIMETYPE = "mimetype";
public static final String PROP_MODEL_ASPECT = "modelaspect";
public static final String PROP_TYPE_OR_ASPECT = "typeoraspect";
public static final String PROP_SCRIPT = "script";
protected ActionService actionService;
protected DictionaryService dictionaryService;
@@ -154,6 +156,7 @@ public abstract class BaseActionWizard extends BaseWizardBean
this.currentActionProperties.put(PROP_CHECKIN_MINOR, new Boolean(true));
}
// ------------------------------------------------------------------------------
// Bean Getters and Setters
@@ -520,6 +523,7 @@ public abstract class BaseActionWizard extends BaseWizardBean
return this.imageTransformers;
}
// ------------------------------------------------------------------------------
// Action event handlers
@@ -750,6 +754,7 @@ public abstract class BaseActionWizard extends BaseWizardBean
usingTemplate = null;
}
// ------------------------------------------------------------------------------
// Service Injection
@@ -799,6 +804,7 @@ public abstract class BaseActionWizard extends BaseWizardBean
this.authorityService = authorityService;
}
// ------------------------------------------------------------------------------
// Helper methods
@@ -1045,12 +1051,19 @@ public abstract class BaseActionWizard extends BaseWizardBean
NodeRef destNodeRef = (NodeRef)this.currentActionProperties.get(PROP_DESTINATION);
actionParams.put(ImporterActionExecuter.PARAM_DESTINATION_FOLDER, destNodeRef);
}
else if (this.action.equals(SpecialiseTypeActionExecuter.NAME) == true)
else if (this.action.equals(SpecialiseTypeActionExecuter.NAME))
{
// add the specialisation type
String objectType = (String)this.currentActionProperties.get(PROP_OBJECT_TYPE);
actionParams.put(SpecialiseTypeActionExecuter.PARAM_TYPE_NAME, QName.createQName(objectType));
}
else if (this.action.equals(ScriptActionExecutor.NAME))
{
// add the selected script noderef to the action properties
String id = (String)this.currentActionProperties.get(PROP_SCRIPT);
NodeRef scriptRef = new NodeRef(Repository.getStoreRef(), id);
actionParams.put(ScriptActionExecutor.PARAM_SCRIPTREF, scriptRef);
}
return actionParams;
}
@@ -1221,7 +1234,7 @@ public abstract class BaseActionWizard extends BaseWizardBean
String spaceName = Repository.getNameForNode(this.nodeService, space);
summary.append("'").append(spaceName).append("'");
}
else if (SpecialiseTypeActionExecuter.NAME.equals(actionName) == true)
else if (SpecialiseTypeActionExecuter.NAME.equals(actionName))
{
String label = null;
String objectType = (String)this.currentActionProperties.get(PROP_OBJECT_TYPE);
@@ -1236,6 +1249,13 @@ public abstract class BaseActionWizard extends BaseWizardBean
summary.append("'").append(label).append("'");
}
else if (ScriptActionExecutor.NAME.equals(actionName))
{
String id = (String)this.currentActionProperties.get(PROP_SCRIPT);
NodeRef scriptRef = new NodeRef(Repository.getStoreRef(), id);
String scriptName = Repository.getNameForNode(this.nodeService, scriptRef);
summary.append("'").append(scriptName).append("'");
}
summaryResult = summary.toString();
}
@@ -1270,6 +1290,7 @@ public abstract class BaseActionWizard extends BaseWizardBean
return ACTION_PAGES_LOCATION + actionId + ".jsp";
}
// ------------------------------------------------------------------------------
// Inner classes

View File

@@ -76,6 +76,7 @@ public class CreateRuleWizard extends BaseActionWizard
private static final Log logger = LogFactory.getLog(CreateRuleWizard.class);
// ------------------------------------------------------------------------------
// Wizard implementation
@@ -260,6 +261,7 @@ public class CreateRuleWizard extends BaseActionWizard
return outcome;
}
// ------------------------------------------------------------------------------
// Bean Getters and Setters
@@ -515,6 +517,7 @@ public class CreateRuleWizard extends BaseActionWizard
this.condition = condition;
}
// ------------------------------------------------------------------------------
// Action event handlers
@@ -646,6 +649,7 @@ public class CreateRuleWizard extends BaseActionWizard
goToPage(FacesContext.getCurrentInstance(), this.returnViewId);
}
// ------------------------------------------------------------------------------
// Service Injection
@@ -667,6 +671,7 @@ public class CreateRuleWizard extends BaseActionWizard
this.rulesBean = rulesBean;
}
// ------------------------------------------------------------------------------
// Helper methods

View File

@@ -23,6 +23,7 @@ import org.alfresco.repo.action.executer.LinkCategoryActionExecuter;
import org.alfresco.repo.action.executer.MailActionExecuter;
import org.alfresco.repo.action.executer.MoveActionExecuter;
import org.alfresco.repo.action.executer.RemoveFeaturesActionExecuter;
import org.alfresco.repo.action.executer.ScriptActionExecutor;
import org.alfresco.repo.action.executer.SimpleWorkflowActionExecuter;
import org.alfresco.repo.action.executer.SpecialiseTypeActionExecuter;
import org.alfresco.repo.action.executer.TransformActionExecuter;
@@ -306,5 +307,10 @@ public class EditRuleWizard extends CreateRuleWizard
QName specialiseType = (QName)actionProps.get(SpecialiseTypeActionExecuter.PARAM_TYPE_NAME);
this.currentActionProperties.put(PROP_OBJECT_TYPE, specialiseType.toString());
}
else if (this.action.equals(ScriptActionExecutor.NAME))
{
NodeRef scriptRef = (NodeRef)actionProps.get(ScriptActionExecutor.PARAM_SCRIPTREF);
this.currentActionProperties.put(PROP_SCRIPT, scriptRef.getId());
}
}
}

View File

@@ -0,0 +1,157 @@
<%--
Copyright (C) 2005 Alfresco, Inc.
Licensed under the Mozilla Public License version 1.1
with a permitted attribution clause. You may obtain a
copy of the License at
http://www.alfresco.org/legal/license.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.
--%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="/WEB-INF/alfresco.tld" prefix="a" %>
<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %>
<%@ page buffer="32kb" contentType="text/html;charset=UTF-8" %>
<%@ page isELIgnored="false" %>
<%@ page import="org.alfresco.web.ui.common.PanelGenerator" %>
<r:page titleId="title_action_script">
<f:view>
<%-- load a bundle of properties with I18N strings --%>
<f:loadBundle basename="alfresco.messages.webclient" var="msg"/>
<h:form acceptCharset="UTF-8" id="script-action">
<%-- Main outer table --%>
<table cellspacing="0" cellpadding="2">
<%-- Title bar --%>
<tr>
<td colspan="2">
<%@ include file="../parts/titlebar.jsp" %>
</td>
</tr>
<%-- Main area --%>
<tr valign="top">
<%-- Shelf --%>
<td>
<%@ include file="../parts/shelf.jsp" %>
</td>
<%-- Work Area --%>
<td width="100%">
<table cellspacing="0" cellpadding="0" width="100%">
<%-- Breadcrumb --%>
<%@ include file="../parts/breadcrumb.jsp" %>
<%-- Status and Actions --%>
<tr>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/statuspanel_4.gif)" width="4"></td>
<td bgcolor="#EEEEEE">
<%-- Status and Actions inner contents table --%>
<%-- Generally this consists of an icon, textual summary and actions for the current object --%>
<table cellspacing="4" cellpadding="0" width="100%">
<tr>
<td width="32">
<h:graphicImage id="wizard-logo" url="/images/icons/new_rule_large.gif" />
</td>
<td>
<div class="mainTitle"><h:outputText value="#{WizardManager.title}" /></div>
<div class="mainSubText"><h:outputText value="#{WizardManager.description}" /></div>
</td>
</tr>
</table>
</td>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/statuspanel_6.gif)" width="4"></td>
</tr>
<%-- separator row with gradient shadow --%>
<tr>
<td><img src="<%=request.getContextPath()%>/images/parts/statuspanel_7.gif" width="4" height="9"></td>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/statuspanel_8.gif)"></td>
<td><img src="<%=request.getContextPath()%>/images/parts/statuspanel_9.gif" width="4" height="9"></td>
</tr>
<%-- Details --%>
<tr valign=top>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/whitepanel_4.gif)" width="4"></td>
<td>
<table cellspacing="0" cellpadding="3" border="0" width="100%">
<tr>
<td width="100%" valign="top">
<a:errors message="#{msg.error_wizard}" styleClass="errorMessage" />
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "white", "white"); %>
<table cellpadding="2" cellspacing="2" border="0" width="100%">
<tr>
<td colspan="2" class="mainSubTitle"><h:outputText value="#{msg.set_action_values}" /></td>
</tr>
<tr><td class="paddingRow"></td></tr>
<tr>
<td><h:outputText value="#{msg.action_script_select}"/>:</td>
<td>
<%-- Scripts drop-down selector --%>
<h:selectOneMenu value="#{WizardManager.bean.actionProperties.script}">
<f:selectItems value="#{TemplateSupportBean.scriptFiles}" />
</h:selectOneMenu>
</td>
</tr>
<tr><td class="paddingRow"></td></tr>
</table>
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "white"); %>
</td>
<td valign="top">
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "blue", "#D3E6FE"); %>
<table cellpadding="1" cellspacing="1" border="0">
<tr>
<td align="center">
<h:commandButton value="#{msg.ok}" action="#{WizardManager.bean.addAction}" styleClass="wizardButton" />
</td>
</tr>
<tr>
<td align="center">
<h:commandButton value="#{msg.cancel_button}" action="#{WizardManager.bean.cancelAddAction}" styleClass="wizardButton" />
</td>
</tr>
</table>
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "blue"); %>
</td>
</tr>
</table>
</td>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/whitepanel_6.gif)" width="4"></td>
</tr>
<%-- separator row with bottom panel graphics --%>
<tr>
<td><img src="<%=request.getContextPath()%>/images/parts/whitepanel_7.gif" width="4" height="4"></td>
<td width="100%" align="center" style="background-image: url(<%=request.getContextPath()%>/images/parts/whitepanel_8.gif)"></td>
<td><img src="<%=request.getContextPath()%>/images/parts/whitepanel_9.gif" width="4" height="4"></td>
</tr>
</table>
</td>
</tr>
</table>
</h:form>
</f:view>
</r:page>