From 1ef35756f85277cea635dde884689b0cdcc00857 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Tue, 11 Sep 2007 03:03:50 +0000 Subject: [PATCH] Merged V2.1 to HEAD 6580: AVM bulk import performance tweaks. 6582: WCM-767, WCM-768 6583: Fix for AWC-1528 (potential NPE in ErrorsRenderer) 6584: Fix for AWC-1256 (Links produced by inline HTML editor are incorrect) 6585: AR-1635: event listeners added in a beforeCommit event are now executed successfully 6586: AR-1561 Update Web Scripts readme.html to be consistent with "Category Search Sample" (or vice-versa) 6587: Fix for AWC-1390 (Paste all doesn't work for forum items) 6588: AR-1701 Script getDocument call doesn't check for non-existent content 6589: Fix for AWC-1530 - Saved search does not work for custom properties of type d:text with list constraint 6591: Improvement for submit speed. 6592: Removed obsolete tests. 6594: Index tracking sample to include AVM index tracking 6595: Added the AVM helpers methods from the FreeMarker AVM API that were missing from the JavaScript API 6597: Rationalize post commit execution hooks for deployment receiver 6598: Properly escape path names for ProgramRunnable. 6599: AVM store name lookup cache is (theoretically) clusterable. 6600: Some or other gramatically incorrect stuff about Chiba. 6601: Fix for AR-1121 and AR-1673 6602: AR-1655: Versioning is not MLText aware 6603: Updated messages from lang packs 6604: Fixed AR-1476: JCR import end element escaping 6605: Updated Japanese lang messages git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6746 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../web-client-config-forum-actions.xml | 1 - .../clipboard/WorkspaceClipboardItem.java | 11 +- .../org/alfresco/web/bean/wcm/AVMUtil.java | 30 ++++- .../web/bean/wcm/CreateWebappDialog.java | 22 +++- .../web/bean/wcm/DeleteSandboxDialog.java | 2 +- .../web/bean/wcm/DeleteWebsiteDialog.java | 2 +- .../web/bean/wcm/ImportWebsiteDialog.java | 28 ++-- .../web/forms/xforms/Schema2XForms.java | 27 ++-- .../web/forms/xforms/Schema2XFormsTest.java | 123 +++++++++++++++++- .../org/alfresco/web/scripts/RepoStore.java | 4 + .../ui/common/renderer/ErrorsRenderer.java | 8 +- .../unit-tests/automated/constraint-test.xsd | 34 +++++ .../create-content-wizard/create-html.jsp | 32 +++-- source/web/jsp/dialog/edit-html-inline.jsp | 32 +++-- 14 files changed, 286 insertions(+), 70 deletions(-) create mode 100644 source/test-resources/xforms/unit-tests/automated/constraint-test.xsd diff --git a/config/alfresco/web-client-config-forum-actions.xml b/config/alfresco/web-client-config-forum-actions.xml index af2aa3e377..2752edf976 100644 --- a/config/alfresco/web-client-config-forum-actions.xml +++ b/config/alfresco/web-client-config-forum-actions.xml @@ -332,7 +332,6 @@ - diff --git a/source/java/org/alfresco/web/bean/clipboard/WorkspaceClipboardItem.java b/source/java/org/alfresco/web/bean/clipboard/WorkspaceClipboardItem.java index e95ca1a25c..96c510b21d 100644 --- a/source/java/org/alfresco/web/bean/clipboard/WorkspaceClipboardItem.java +++ b/source/java/org/alfresco/web/bean/clipboard/WorkspaceClipboardItem.java @@ -60,6 +60,8 @@ public class WorkspaceClipboardItem extends AbstractClipboardItem { private static final String WORKSPACE_PASTE_VIEW_ID = "/jsp/browse/browse.jsp"; private static final String AVM_PASTE_VIEW_ID = "/jsp/wcm/browse-sandbox.jsp"; + private static final String FORUMS_PASTE_VIEW_ID = "/jsp/forums/forums.jsp"; + private static final String FORUM_PASTE_VIEW_ID = "/jsp/forums/forum.jsp"; private static final String MSG_LINK_TO = "link_to"; @@ -89,7 +91,8 @@ public class WorkspaceClipboardItem extends AbstractClipboardItem */ public boolean canCopyToViewId(String viewId) { - return (WORKSPACE_PASTE_VIEW_ID.equals(viewId) || AVM_PASTE_VIEW_ID.equals(viewId)); + return (WORKSPACE_PASTE_VIEW_ID.equals(viewId) || AVM_PASTE_VIEW_ID.equals(viewId) || + FORUMS_PASTE_VIEW_ID.equals(viewId) || FORUM_PASTE_VIEW_ID.equals(viewId)); } /** @@ -97,7 +100,8 @@ public class WorkspaceClipboardItem extends AbstractClipboardItem */ public boolean canMoveToViewId(String viewId) { - return (WORKSPACE_PASTE_VIEW_ID.equals(viewId)); + return (WORKSPACE_PASTE_VIEW_ID.equals(viewId) || FORUMS_PASTE_VIEW_ID.equals(viewId) || + FORUM_PASTE_VIEW_ID.equals(viewId)); } /** @@ -106,7 +110,8 @@ public class WorkspaceClipboardItem extends AbstractClipboardItem public boolean paste(FacesContext fc, String viewId, int action) throws Throwable { - if (WORKSPACE_PASTE_VIEW_ID.equals(viewId)) + if (WORKSPACE_PASTE_VIEW_ID.equals(viewId) || FORUMS_PASTE_VIEW_ID.equals(viewId) || + FORUM_PASTE_VIEW_ID.equals(viewId)) { NavigationBean navigator = (NavigationBean)FacesHelper.getManagedBean(fc, NavigationBean.BEAN_NAME); NodeRef destRef = new NodeRef(Repository.getStoreRef(), navigator.getCurrentNodeId()); diff --git a/source/java/org/alfresco/web/bean/wcm/AVMUtil.java b/source/java/org/alfresco/web/bean/wcm/AVMUtil.java index d76e11f937..3665255fff 100644 --- a/source/java/org/alfresco/web/bean/wcm/AVMUtil.java +++ b/source/java/org/alfresco/web/bean/wcm/AVMUtil.java @@ -1012,10 +1012,36 @@ public final class AVMUtil path = path.substring(0, webappIndex); } final VirtServerRegistry vServerRegistry = AVMUtil.getVirtServerRegistry(); - vServerRegistry.updateAllWebapps(-1, path, true); + vServerRegistry.updateWebapp(-1, path, true); } } + + /** + * Removal notification on all the virtualisation server webapp as required by the specified path + * + * @param path Path to match against + * @param force True to force update of server even if path does not match + */ + public static void removeAllVServerWebapps(String path, boolean force) + { + if (force || VirtServerUtils.requiresUpdateNotification(path)) + { + final int webappIndex = path.indexOf('/', + path.indexOf(JNDIConstants.DIR_DEFAULT_APPBASE) + + JNDIConstants.DIR_DEFAULT_APPBASE.length() + 1); + + if (webappIndex != -1) + { + path = path.substring(0, webappIndex); + } + final VirtServerRegistry vServerRegistry = AVMUtil.getVirtServerRegistry(); + vServerRegistry.removeAllWebapps(-1, path, true); + } + } + + + /** * Removal notification on the virtualisation server webapp as required for the specified path * @@ -1035,7 +1061,7 @@ public final class AVMUtil path = path.substring(0, webappIndex); } final VirtServerRegistry vServerRegistry = AVMUtil.getVirtServerRegistry(); - vServerRegistry.removeAllWebapps(-1, path, true); + vServerRegistry.removeWebapp(-1, path, true); } } diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebappDialog.java b/source/java/org/alfresco/web/bean/wcm/CreateWebappDialog.java index 433af8c7d8..aae8640a8c 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateWebappDialog.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateWebappDialog.java @@ -43,6 +43,8 @@ public class CreateWebappDialog extends CreateFolderDialog // ------------------------------------------------------------------------------ // Dialog implementation + protected String path; + /** * @see org.alfresco.web.bean.dialog.BaseDialogBean#finishImpl(javax.faces.context.FacesContext, java.lang.String) */ @@ -53,9 +55,9 @@ public class CreateWebappDialog extends CreateFolderDialog final String parent = AVMUtil.buildSandboxRootPath( stagingStore ); this.avmService.createDirectory(parent, this.name); - final String path = AVMNodeConverter.ExtendAVMPath(parent, this.name); - this.avmService.addAspect(path, ApplicationModel.ASPECT_UIFACETS); - this.avmService.addAspect(path, WCMAppModel.ASPECT_WEBAPP); + this.path = AVMNodeConverter.ExtendAVMPath(parent, this.name); + this.avmService.addAspect(this.path, ApplicationModel.ASPECT_UIFACETS); + this.avmService.addAspect(this.path, WCMAppModel.ASPECT_WEBAPP); if (this.description != null && this.description.length() != 0) { this.avmService.setNodeProperty(path, @@ -65,8 +67,18 @@ public class CreateWebappDialog extends CreateFolderDialog } // Snapshot the store with the empty webapp - this.avmService.createSnapshot( stagingStore, null, null); - + this.avmService.createSnapshot(stagingStore, null, null); + + return outcome; + } + + @Override + protected String doPostCommitProcessing(FacesContext context, String outcome) + { + // Tell the virtualization server about the new webapp. + // e.g.: this.path = "mysite:/www/avm_webapps/mywebapp" + AVMUtil.updateVServerWebapp(this.path, true); + return outcome; } } diff --git a/source/java/org/alfresco/web/bean/wcm/DeleteSandboxDialog.java b/source/java/org/alfresco/web/bean/wcm/DeleteSandboxDialog.java index 735e5a24e0..70c67112ea 100644 --- a/source/java/org/alfresco/web/bean/wcm/DeleteSandboxDialog.java +++ b/source/java/org/alfresco/web/bean/wcm/DeleteSandboxDialog.java @@ -130,7 +130,7 @@ public class DeleteSandboxDialog extends BaseDialogBean // dependent order, so clients don't have to worry about // accessing a preview layer whose main layer has been torn // out from under it. - AVMUtil.removeVServerWebapp(path, true); + AVMUtil.removeAllVServerWebapps(path, true); // TODO: Use the .sandbox-id. property to delete all sandboxes, // rather than assume a sandbox always had a single preview diff --git a/source/java/org/alfresco/web/bean/wcm/DeleteWebsiteDialog.java b/source/java/org/alfresco/web/bean/wcm/DeleteWebsiteDialog.java index 4d4498cc30..5c9af4b187 100644 --- a/source/java/org/alfresco/web/bean/wcm/DeleteWebsiteDialog.java +++ b/source/java/org/alfresco/web/bean/wcm/DeleteWebsiteDialog.java @@ -97,7 +97,7 @@ public class DeleteWebsiteDialog extends DeleteSpaceDialog String sandbox = AVMUtil.buildStagingStoreName(storeRoot); String path = AVMUtil.buildStoreWebappPath(sandbox, "/ROOT"); - AVMUtil.removeVServerWebapp(path, true); + AVMUtil.removeAllVServerWebapps(path, true); // get the list of users who have a sandbox in the website List userInfoRefs = nodeService.getChildAssocs( diff --git a/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java b/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java index ad26142361..8e22af1ec2 100644 --- a/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java +++ b/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java @@ -30,6 +30,10 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; @@ -50,6 +54,7 @@ import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; import org.alfresco.util.TempFileProvider; import org.alfresco.web.app.AlfrescoNavigationHandler; import org.alfresco.web.app.Application; @@ -334,8 +339,14 @@ public class ImportWebsiteDialog // Create a file in the AVM store String avmPath = AVMNodeConverter.ToAVMVersionPath(root).getSecond(); String fileName = file.getName(); + List aspects = new ArrayList(); + aspects.add(ContentModel.ASPECT_TITLED); + Map properties = new HashMap(); + properties.put(ContentModel.PROP_TITLE, + new PropertyValue(DataTypeDefinition.TEXT, fileName)); this.avmService.createFile( - avmPath, fileName,new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE)); + avmPath, fileName,new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE), + aspects, properties); // TODO: restore this code once performance is acceptable // NodeRef fileRef = AVMNodeConverter.ToNodeRef(-1, filePath); @@ -346,10 +357,10 @@ public class ImportWebsiteDialog // this.nodeService.addAspect(fileRef, ContentModel.ASPECT_TITLED, titledProps); // for now use the avm service directly - String filePath = avmPath + '/' + fileName; - this.avmService.addAspect(filePath, ContentModel.ASPECT_TITLED); - this.avmService.setNodeProperty(filePath, ContentModel.PROP_TITLE, - new PropertyValue(DataTypeDefinition.TEXT, fileName)); + // String filePath = avmPath + '/' + fileName; + // this.avmService.addAspect(filePath, ContentModel.ASPECT_TITLED); + // this.avmService.setNodeProperty(filePath, ContentModel.PROP_TITLE, + // new PropertyValue(DataTypeDefinition.TEXT, fileName)); // create content node based on the filename /*FileInfo contentFile = fileFolderService.create(root, fileName, ContentModel.TYPE_AVM_PLAIN_CONTENT); @@ -369,7 +380,9 @@ public class ImportWebsiteDialog // Create a directory in the AVM store String avmPath = AVMNodeConverter.ToAVMVersionPath(root).getSecond(); - this.avmService.createDirectory(avmPath, file.getName()); + List aspects = new ArrayList(); + aspects.add(ApplicationModel.ASPECT_UIFACETS); + this.avmService.createDirectory(avmPath, file.getName(), aspects, null); String folderPath = avmPath + '/' + file.getName(); NodeRef folderRef = AVMNodeConverter.ToNodeRef(-1, folderPath); @@ -379,9 +392,6 @@ public class ImportWebsiteDialog // see AVMBrowseBean.setAVMNodeDescriptor // add the uifacets aspect for the read/edit properties screens // this.nodeService.addAspect(folderRef, ContentModel.ASPECT_UIFACETS, null); - - // for now use the AVM service directly - this.avmService.addAspect(folderPath, ApplicationModel.ASPECT_UIFACETS); } } catch (FileNotFoundException e) diff --git a/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java b/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java index 248d0c118f..a091f0f36f 100644 --- a/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java +++ b/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java @@ -34,6 +34,7 @@ import org.alfresco.service.namespace.NamespaceService; import org.alfresco.web.forms.XMLUtil; import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.jxpath.Pointer; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xerces.xs.*; @@ -2121,6 +2122,9 @@ public class Schema2XForms final Element modelElement = xformsDocument.createElementNS(NamespaceConstants.XFORMS_NS, NamespaceConstants.XFORMS_PREFIX + ":model"); + modelElement.setAttributeNS(NamespaceConstants.XFORMS_NS, + NamespaceConstants.XFORMS_PREFIX + ":functions", + NamespaceConstants.CHIBA_PREFIX + ":match"); this.setXFormsId(modelElement); final Element modelWrapper = xformsDocument.createElementNS(NamespaceConstants.XHTML_NS, @@ -2777,7 +2781,7 @@ public class Schema2XForms // // type.getName() may be 'null' for anonymous types, so compare against // static string (see bug #1172541 on sf.net) - + final List constraints = new LinkedList(); if (controlType instanceof XSSimpleTypeDefinition && ((XSSimpleTypeDefinition)controlType).getBuiltInKind() != XSConstants.ANYSIMPLETYPE_DT) { @@ -2798,6 +2802,11 @@ public class Schema2XForms NamespaceService.ALFRESCO_PREFIX + ":builtInType", typeName); } + final StringList lexicalPatterns = ((XSSimpleTypeDefinition)controlType).getLexicalPattern(); + for (int i = 0; lexicalPatterns != null && i < lexicalPatterns.getLength(); i++) + { + constraints.add("chiba:match(., '" + lexicalPatterns.item(i) + "',null)"); + } } final short constraintType = @@ -2833,13 +2842,10 @@ public class Schema2XForms //count(.) <= maxOccurs && count(.) >= minOccurs final String nodeset = bindElement.getAttributeNS(NamespaceConstants.XFORMS_NS, "nodeset"); - String minConstraint = null; - String maxConstraint = null; - if (o.minimum > 1) { //if 0 or 1 -> no constraint (managed by "required") - minConstraint = "count(../" + nodeset + ") >= " + o.minimum; + constraints.add("count(../" + nodeset + ") >= " + o.minimum); } bindElement.setAttributeNS(NamespaceConstants.XFORMS_NS, NamespaceConstants.XFORMS_PREFIX + ":minOccurs", @@ -2847,23 +2853,18 @@ public class Schema2XForms if (o.maximum > 1) { //if 1 or unbounded -> no constraint - maxConstraint = "count(../" + nodeset + ") <= " + o.maximum; + constraints.add("count(../" + nodeset + ") <= " + o.maximum); } bindElement.setAttributeNS(NamespaceConstants.XFORMS_NS, NamespaceConstants.XFORMS_PREFIX + ":maxOccurs", o.isUnbounded() ? "unbounded" : String.valueOf(o.maximum)); - final String constraint = (minConstraint != null && maxConstraint != null - ? minConstraint + " and " + maxConstraint - : (minConstraint != null - ? minConstraint - : maxConstraint)); - if (constraint != null) + if (constraints.size() != 0) { bindElement.setAttributeNS(NamespaceConstants.XFORMS_NS, NamespaceConstants.XFORMS_PREFIX + ":constraint", - constraint); + StringUtils.join((String[])constraints.toArray(new String[constraints.size()]), " and ")); } return bindElement; } diff --git a/source/java/org/alfresco/web/forms/xforms/Schema2XFormsTest.java b/source/java/org/alfresco/web/forms/xforms/Schema2XFormsTest.java index ef268b37d2..646883b52f 100644 --- a/source/java/org/alfresco/web/forms/xforms/Schema2XFormsTest.java +++ b/source/java/org/alfresco/web/forms/xforms/Schema2XFormsTest.java @@ -25,18 +25,27 @@ package org.alfresco.web.forms.xforms; import java.io.*; -import java.util.*; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.Vector; +import java.util.ResourceBundle; import junit.framework.AssertionFailedError; import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.web.forms.XMLUtil; import org.alfresco.util.BaseTest; +import org.alfresco.web.forms.XMLUtil; import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.jxpath.Pointer; -import org.chiba.xml.ns.NamespaceConstants; -import org.w3c.dom.*; -import org.xml.sax.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.chiba.xml.ns.NamespaceConstants; +import org.chiba.xml.events.XFormsEventNames; +import org.chiba.xml.events.XMLEvent; +import org.chiba.xml.xforms.ChibaBean; +import org.chiba.xml.xforms.XFormsElement; +import org.chiba.xml.events.DOMEventNames; +import org.w3c.dom.*; +import org.w3c.dom.events.*; +import org.xml.sax.*; /** * JUnit tests to exercise the the schema to xforms converter @@ -54,6 +63,7 @@ public class Schema2XFormsTest { final Document schemaDocument = this.loadTestResourceDocument("xforms/unit-tests/automated/one-string-test.xsd"); final Document xformsDocument = Schema2XFormsTest.buildXForm(null, schemaDocument, "one-string-test"); + this.runXForm(xformsDocument); final JXPathContext xpathContext = JXPathContext.newContext(xformsDocument); Pointer pointer = xpathContext.getPointer("//*[@id='input_0']"); assertNotNull(pointer); @@ -73,6 +83,7 @@ public class Schema2XFormsTest final Document instanceDocument = XMLUtil.parse("test"); final Document schemaDocument = this.loadTestResourceDocument("xforms/unit-tests/automated/one-string-test.xsd"); final Document xformsDocument = Schema2XFormsTest.buildXForm(instanceDocument, schemaDocument, "one-string-test"); + this.runXForm(xformsDocument); final JXPathContext xpathContext = JXPathContext.newContext(xformsDocument); Pointer pointer = xpathContext.getPointer("//*[@id='input_0']"); assertNotNull(pointer); @@ -144,6 +155,7 @@ public class Schema2XFormsTest Schema2XFormsTest.assertRepeatProperties(xformsDocument, "/repeat-constraints-test/nested-outer-outer-three-to-inf/nested-outer-inner-five-to-inf/nested-inner-inner-seven-to-inf", new SchemaUtil.Occurrence(7, SchemaUtil.Occurrence.UNBOUNDED)); + this.runXForm(xformsDocument); } public void testRootElementWithExtension() @@ -151,6 +163,7 @@ public class Schema2XFormsTest { final Document schemaDocument = this.loadTestResourceDocument("xforms/unit-tests/automated/root-element-with-extension-test.xsd"); Document xformsDocument = Schema2XFormsTest.buildXForm(null, schemaDocument, "without-extension-test"); + this.runXForm(xformsDocument); assertEquals(3, xformsDocument.getElementsByTagNameNS(NamespaceConstants.XFORMS_NS, "input").getLength()); try @@ -169,7 +182,7 @@ public class Schema2XFormsTest { final Document schemaDocument = this.loadTestResourceDocument("xforms/unit-tests/automated/switch-test.xsd"); final Document xformsDocument = Schema2XFormsTest.buildXForm(null, schemaDocument, "switch-test"); - LOGGER.debug("generated xforms " + XMLUtil.toString(xformsDocument)); + this.runXForm(xformsDocument); // assertEquals(3, xformsDocument.getElementsByTagNameNS(NamespaceConstants.XFORMS_NS, "input").getLength()); // // try @@ -187,6 +200,7 @@ public class Schema2XFormsTest { final Document schemaDocument = this.loadTestResourceDocument("xforms/unit-tests/automated/derived-type-test.xsd"); final Document xformsDocument = Schema2XFormsTest.buildXForm(null, schemaDocument, "derived-type-test"); + this.runXForm(xformsDocument); LOGGER.debug("generated xforms " + XMLUtil.toString(xformsDocument)); assertBindProperties(xformsDocument, "/derived-type-test/raw-normalized-string", @@ -306,6 +320,7 @@ public class Schema2XFormsTest { final Document schemaDocument = this.loadTestResourceDocument("xforms/unit-tests/automated/recursive-test.xsd"); Document xformsDocument = Schema2XFormsTest.buildXForm(null, schemaDocument, "non-recursive-test"); + this.runXForm(xformsDocument); try { xformsDocument = Schema2XFormsTest.buildXForm(null, schemaDocument, "recursive-test"); @@ -326,6 +341,87 @@ public class Schema2XFormsTest } } + public void testConstraint() + throws Exception + { + final Document schemaDocument = this.loadTestResourceDocument("xforms/unit-tests/automated/constraint-test.xsd"); + Document xformsDocument = Schema2XFormsTest.buildXForm(null, schemaDocument, "constraint-test"); + final ChibaBean chibaBean = this.runXForm(xformsDocument); + final LinkedList events = new LinkedList(); + final EventListener el = new EventListener() + { + public void handleEvent(final Event e) + { + events.add((XMLEvent)e); + } + }; + ((EventTarget)chibaBean.getXMLContainer().getDocumentElement()).addEventListener(XFormsEventNames.VALID, el, true); + ((EventTarget)chibaBean.getXMLContainer().getDocumentElement()).addEventListener(XFormsEventNames.INVALID, el, true); + ((EventTarget)chibaBean.getXMLContainer().getDocumentElement()).addEventListener(XFormsEventNames.SUBMIT_DONE, el, true); + ((EventTarget)chibaBean.getXMLContainer().getDocumentElement()).addEventListener(XFormsEventNames.SUBMIT_ERROR, el, true); + + Element e = Schema2XFormsTest.resolveXFormsControl(xformsDocument, "/constraint-test/zip-pattern")[0]; + chibaBean.updateControlValue(e.getAttribute("id"), "not a zip"); + assertEquals(1, events.size()); + assertEquals(XFormsEventNames.INVALID, events.get(0).getType()); + events.clear(); + + chibaBean.updateControlValue(e.getAttribute("id"), "94110"); + assertEquals(1, events.size()); + assertEquals(XFormsEventNames.VALID, events.get(0).getType()); + events.clear(); + + e = Schema2XFormsTest.resolveXFormsControl(xformsDocument, "/constraint-test/email-pattern")[0]; + chibaBean.updateControlValue(e.getAttribute("id"), "iamnotanemailaddress"); + assertEquals(1, events.size()); + assertEquals(XFormsEventNames.INVALID, events.get(0).getType()); + events.clear(); + + chibaBean.updateControlValue(e.getAttribute("id"), "ariel.backenroth@alfresco.org"); + assertEquals(1, events.size()); + assertEquals(XFormsEventNames.VALID, events.get(0).getType()); + events.clear(); + + Element[] controls = Schema2XFormsTest.resolveXFormsControl(xformsDocument, "/constraint-test/repeated-zip-pattern/."); + assertEquals(3 /* 2 actual + prototype */, controls.length); + Element[] repeat = Schema2XFormsTest.resolveXFormsControl(xformsDocument, "/constraint-test/repeated-zip-pattern"); + assertEquals(4 /* 1 repeat + 3 triggers */, repeat.length); + + final Element[] bindForRepeat = Schema2XFormsTest.resolveBind(xformsDocument, "/constraint-test/repeated-zip-pattern"); + assertEquals(bindForRepeat[bindForRepeat.length - 1].getAttribute("id"), repeat[0].getAttributeNS(NamespaceConstants.XFORMS_NS, "bind")); + for (int i = 1; i <= Integer.parseInt(bindForRepeat[bindForRepeat.length - 1].getAttributeNS(NamespaceConstants.XFORMS_NS, "minOccurs")); i++) + { + chibaBean.updateRepeatIndex(repeat[0].getAttribute("id"), i); + chibaBean.updateControlValue(controls[controls.length - 1].getAttribute("id"), "notavalidzip"); + } + // assertEquals("unexpected events " + events, controls.length, events.size()); + for (final Event event : events) + { + assertEquals(XFormsEventNames.INVALID, event.getType()); + } + events.clear(); + + chibaBean.dispatch("submit", DOMEventNames.ACTIVATE); + assertEquals(1, events.size()); + assertEquals(XFormsEventNames.SUBMIT_ERROR, events.get(0).getType()); + events.clear(); + + for (final Element c : controls) + { + chibaBean.updateControlValue(c.getAttribute("id"), "07666"); + } +// assertEquals("unexpected events " + events, controls.length, events.size()); + for (final Event event : events) + { + assertEquals(XFormsEventNames.VALID, event.getType()); + } + events.clear(); + + chibaBean.dispatch("submit", DOMEventNames.ACTIVATE); + assertEquals(1, events.size()); + assertEquals(XFormsEventNames.SUBMIT_DONE, events.get(0).getType()); + } + private static void assertRepeatProperties(final Document xformsDocument, final String nodeset, final SchemaUtil.Occurrence o) @@ -478,6 +574,19 @@ public class Schema2XFormsTest return XMLUtil.parse(f); } + private ChibaBean runXForm(final Document xformsDocument) + throws Exception + { + final ChibaBean chibaBean = new ChibaBean(); + chibaBean.setConfig(this.getResourcesDir() + File.separator + + ".." + File.separator + + "web" + File.separator + + "WEB-INF" + File.separator + "chiba.xml"); + chibaBean.setXMLContainer(xformsDocument); + chibaBean.init(); + return chibaBean; + } + private static Document buildXForm(final Document instanceDocument, final Document schemaDocument, final String rootElementName) @@ -485,7 +594,7 @@ public class Schema2XFormsTest { final Schema2XForms s2xf = new Schema2XForms("/test_action", Schema2XForms.SubmitMethod.POST, - "http://fake.base.url"); + "echo://fake.base.url"); return s2xf.buildXForm(instanceDocument, schemaDocument, rootElementName, diff --git a/source/java/org/alfresco/web/scripts/RepoStore.java b/source/java/org/alfresco/web/scripts/RepoStore.java index c34efc6141..4dec38e133 100644 --- a/source/java/org/alfresco/web/scripts/RepoStore.java +++ b/source/java/org/alfresco/web/scripts/RepoStore.java @@ -394,6 +394,10 @@ public class RepoStore implements WebScriptStore, ApplicationContextAware, Appli throw new IOException("Document " + documentPath + " does not exist."); } ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT); + if (reader == null || !reader.exists()) + { + throw new IOException("Failed to read content at " + documentPath + " (content reader does not exist)"); + } return reader.getContentInputStream(); } }); diff --git a/source/java/org/alfresco/web/ui/common/renderer/ErrorsRenderer.java b/source/java/org/alfresco/web/ui/common/renderer/ErrorsRenderer.java index 4abd07273e..4efc7728f9 100644 --- a/source/java/org/alfresco/web/ui/common/renderer/ErrorsRenderer.java +++ b/source/java/org/alfresco/web/ui/common/renderer/ErrorsRenderer.java @@ -160,8 +160,8 @@ public class ErrorsRenderer extends BaseRenderer { // use the error class if the message is error level if (errorClass != null && - fm.getSeverity() == FacesMessage.SEVERITY_ERROR || - fm.getSeverity() == FacesMessage.SEVERITY_FATAL) + (fm.getSeverity() == FacesMessage.SEVERITY_ERROR || + fm.getSeverity() == FacesMessage.SEVERITY_FATAL)) { out.write(" class='"); out.write(errorClass); @@ -170,8 +170,8 @@ public class ErrorsRenderer extends BaseRenderer // use the info class if the message is info level if (infoClass != null && - fm.getSeverity() == FacesMessage.SEVERITY_INFO || - fm.getSeverity() == FacesMessage.SEVERITY_WARN) + (fm.getSeverity() == FacesMessage.SEVERITY_INFO || + fm.getSeverity() == FacesMessage.SEVERITY_WARN)) { out.write(" class='"); out.write(infoClass); diff --git a/source/test-resources/xforms/unit-tests/automated/constraint-test.xsd b/source/test-resources/xforms/unit-tests/automated/constraint-test.xsd new file mode 100644 index 0000000000..4fc4cc66bd --- /dev/null +++ b/source/test-resources/xforms/unit-tests/automated/constraint-test.xsd @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/web/jsp/content/create-content-wizard/create-html.jsp b/source/web/jsp/content/create-content-wizard/create-html.jsp index 393494337d..533c4b08a3 100644 --- a/source/web/jsp/content/create-content-wizard/create-html.jsp +++ b/source/web/jsp/content/create-content-wizard/create-html.jsp @@ -33,18 +33,19 @@ <%-- Init the Tiny MCE in-line HTML editor --%> tinyMCE.init({ - theme : "advanced", - mode : "exact", - elements : "editor", - save_callback : "saveContent", - plugins : "table", - theme_advanced_toolbar_location : "top", - theme_advanced_toolbar_align : "left", - theme_advanced_buttons1_add : "fontselect,fontsizeselect", - theme_advanced_buttons2_add : "separator,forecolor,backcolor", - theme_advanced_buttons3_add_before : "tablecontrols,separator", - theme_advanced_disable: "styleselect", - extended_valid_elements : "a[href|target|name],font[face|size|color|style],span[class|align|style]" + theme : "advanced", + mode : "exact", + elements : "editor", + save_callback : "saveContent", + urlconverter_callback: "convertUrl", + plugins : "table", + theme_advanced_toolbar_location : "top", + theme_advanced_toolbar_align : "left", + theme_advanced_buttons1_add : "fontselect,fontsizeselect", + theme_advanced_buttons2_add : "separator,forecolor,backcolor", + theme_advanced_buttons3_add_before : "tablecontrols,separator", + theme_advanced_disable: "styleselect", + extended_valid_elements : "a[href|target|name],font[face|size|color|style],span[class|align|style]" }); function saveContent(id, content) @@ -52,6 +53,13 @@ document.getElementById("wizard:wizard-body:editor-output").value = content; } + function convertUrl(href, element, onsave) + { + // just return the passed href, this is enough to stop TinyMCE + // from converting the URL to it's relative form + return href; + } + var isIE = (document.all); diff --git a/source/web/jsp/dialog/edit-html-inline.jsp b/source/web/jsp/dialog/edit-html-inline.jsp index f9d444446e..7a9769d655 100644 --- a/source/web/jsp/dialog/edit-html-inline.jsp +++ b/source/web/jsp/dialog/edit-html-inline.jsp @@ -39,18 +39,19 @@ <%-- Init the Tiny MCE in-line HTML editor --%> tinyMCE.init({ - theme : "advanced", - mode : "exact", - elements : "editor", - save_callback : "saveContent", - plugins : "table", - theme_advanced_toolbar_location : "top", - theme_advanced_toolbar_align : "left", - theme_advanced_buttons1_add : "fontselect,fontsizeselect", - theme_advanced_buttons2_add : "separator,forecolor,backcolor", - theme_advanced_buttons3_add_before : "tablecontrols,separator", - theme_advanced_disable: "styleselect", - extended_valid_elements : "a[href|target|name],font[face|size|color|style],span[class|align|style]" + theme : "advanced", + mode : "exact", + elements : "editor", + save_callback : "saveContent", + urlconverter_callback: "convertUrl", + plugins : "table", + theme_advanced_toolbar_location : "top", + theme_advanced_toolbar_align : "left", + theme_advanced_buttons1_add : "fontselect,fontsizeselect", + theme_advanced_buttons2_add : "separator,forecolor,backcolor", + theme_advanced_buttons3_add_before : "tablecontrols,separator", + theme_advanced_disable: "styleselect", + extended_valid_elements : "a[href|target|name],font[face|size|color|style],span[class|align|style]" }); function saveContent(id, content) @@ -58,6 +59,13 @@ document.forms['edit-file']['edit-file:editorOutput'].value = content; } + function convertUrl(href, element, onsave) + { + // just return the passed href, this is enough to stop TinyMCE + // from converting the URL to it's relative form + return href; + } +