diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties index 3d028c61bf..ce603b6862 100644 --- a/config/alfresco/messages/webclient.properties +++ b/config/alfresco/messages/webclient.properties @@ -664,6 +664,7 @@ create_form_select_default_workflow_desc=Select the workflow you want to be used create_web_content_summary_desc=The wizard has successfully created the content and all renditions. create_web_content_summary_content_details=Content Details create_web_content_summary_rendition_details=Rendition Details +create_web_content_summary_uploaded_files_details=Uploaded File Details create_web_content_summary_submit_message=Submit {0} when wizard finishes. rendering_engine_type=Rendering Engine apply_default_workflow=Apply default workflow diff --git a/source/java/org/alfresco/web/app/Application.java b/source/java/org/alfresco/web/app/Application.java index e006353250..d9915a09cf 100644 --- a/source/java/org/alfresco/web/app/Application.java +++ b/source/java/org/alfresco/web/app/Application.java @@ -517,7 +517,7 @@ public class Application { Locale locale = parseLocale(code); - session.putValue(LOCALE, locale); + session.setAttribute(LOCALE, locale); session.removeAttribute(MESSAGE_BUNDLE); } diff --git a/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java b/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java index ea3f979a2b..79d19cbdbc 100644 --- a/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java +++ b/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java @@ -139,7 +139,8 @@ public class InvokeCommand extends BaseAjaxCommand } } - logger.error(err); + logger.error("Failed to execute method " + expression + ": " + err.getMessage(), + err); throw new AlfrescoRuntimeException("Failed to execute method " + expression + ": " + err.getMessage(), err); } diff --git a/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java b/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java index b4bed422a0..719a27eaa4 100644 --- a/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java +++ b/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java @@ -18,6 +18,8 @@ package org.alfresco.web.bean.wcm; import java.io.File; import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; @@ -28,6 +30,8 @@ import org.alfresco.model.WCMAppModel; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avmsync.AVMDifference; +import org.alfresco.service.cmr.avmsync.AVMSyncService; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; @@ -63,13 +67,18 @@ public class AVMEditBean private static final String MSG_UPLOAD_SUCCESS = "file_upload_success"; private String documentContent = null; + private Document instanceDataDocument = null; private String editorOutput = null; - private File file; - private String fileName; + private File file = null; + private String fileName = null; + protected FormProcessor.Session formProcessorSession = null; /** AVM service bean reference */ protected AVMService avmService; + + /** AVM sync service bean reference */ + protected AVMSyncService avmSyncService; /** AVM Browse Bean reference */ protected AVMBrowseBean avmBrowseBean; @@ -91,6 +100,14 @@ public class AVMEditBean { this.avmService = avmService; } + + /** + * @param avmSyncService The AVMSyncService to set. + */ + public void setAvmSyncService(AVMSyncService avmSyncService) + { + this.avmSyncService = avmSyncService; + } /** * @param avmBrowseBean The AVMBrowseBean to set. @@ -225,34 +242,41 @@ public class AVMEditBean * @return Returns the wrapper instance data for feeding the xml * content to the form processor. */ - public FormProcessor.InstanceData getInstanceData() + public Document getInstanceDataDocument() { - final Form tt = this.getForm(); - final FormProcessor tim = tt.getFormProcessors().get(0); - return new FormProcessor.InstanceData() + if (this.instanceDataDocument == null) { - private final FormsService ts = FormsService.getInstance(); - - public Document load() - { - try - { - final String content = AVMEditBean.this.getEditorOutput(); - return content != null ? this.ts.parseXML(content) : null; - } - catch (Exception e) - { - e.printStackTrace(); - return null; - } - } - - public void save(final Document d, - final String[] uploadedFilePaths) + final FormsService fs = FormsService.getInstance(); + final String content = this.getEditorOutput(); + try { - AVMEditBean.this.setEditorOutput(this.ts.writeXMLToString(d)); + this.instanceDataDocument = (content != null + ? fs.parseXML(content) + : fs.newDocument()); } - }; + catch (Exception e) + { + Utils.addErrorMessage("error parsing document", e); + return fs.newDocument(); + } + } + return this.instanceDataDocument; + } + + /** + * Returns the form processor session. + */ + public FormProcessor.Session getFormProcessorSession() + { + return this.formProcessorSession; + } + + /** + * Sets the form processor session. + */ + public void setFormProcessorSession(final FormProcessor.Session formProcessorSession) + { + this.formProcessorSession = formProcessorSession; } // ------------------------------------------------------------------------------ @@ -280,6 +304,18 @@ public class AVMEditBean final AVMNode avmNode = new AVMNode(this.avmService.lookup(p.getFirst(), p.getSecond())); this.avmBrowseBean.setAvmActionNode(avmNode); } + + if (this.nodeService.hasAspect(avmRef, WCMAppModel.ASPECT_FORM_INSTANCE_DATA)) + { + // reset the preview layer + String path = this.avmBrowseBean.getCurrentPath(); + path = path.replaceFirst(AVMConstants.STORE_MAIN, AVMConstants.STORE_PREVIEW); + path = path.split(":")[0] + ":/" + AVMConstants.DIR_APPBASE; + if (LOGGER.isDebugEnabled()) + LOGGER.debug("reseting layer " + path); + this.avmSyncService.resetLayer(path); + } + if (LOGGER.isDebugEnabled()) LOGGER.debug("Editing AVM node: " + avmRef.toString()); ContentReader reader = contentService.getReader(avmRef, ContentModel.PROP_CONTENT); @@ -345,47 +381,62 @@ public class AVMEditBean */ public String editInlineOK() { - String outcome = null; - UserTransaction tx = null; - - AVMNode avmNode = getAvmNode(); - if (avmNode != null) + final AVMNode avmNode = getAvmNode(); + if (avmNode == null) { - NodeRef avmRef = AVMNodeConverter.ToNodeRef(-1, getAvmNode().getPath()); - try - { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - // get an updating writer that we can use to modify the content on the current node - ContentWriter writer = this.contentService.getWriter(avmRef, ContentModel.PROP_CONTENT, true); - writer.putContent(this.editorOutput); - - // commit the transaction - tx.commit(); - - // regenerate form content - if (nodeService.hasAspect(avmRef, WCMAppModel.ASPECT_FORM_INSTANCE_DATA)) - { - final FormsService fs = FormsService.getInstance(); - fs.regenerateRenditions(avmRef); - } - - resetState(); - - outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; - } - catch (Throwable err) - { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} - Utils.addErrorMessage(Application.getMessage( - FacesContext.getCurrentInstance(), CheckinCheckoutBean.MSG_ERROR_UPDATE) + err.getMessage()); - } + return null; + } + + final FormsService formsService = FormsService.getInstance(); + final NodeRef avmRef = AVMNodeConverter.ToNodeRef(-1, avmNode.getPath()); + try + { + tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); + tx.begin(); + + // get an updating writer that we can use to modify the content on the current node + ContentWriter writer = this.contentService.getWriter(avmRef, ContentModel.PROP_CONTENT, true); + + if (nodeService.hasAspect(avmRef, WCMAppModel.ASPECT_FORM_INSTANCE_DATA)) + { + this.editorOutput = formsService.writeXMLToString(this.instanceDataDocument); + } + writer.putContent(this.editorOutput); + + // commit the transaction + tx.commit(); + + // regenerate form content + if (nodeService.hasAspect(avmRef, WCMAppModel.ASPECT_FORM_INSTANCE_DATA)) + { + + formsService.regenerateRenditions(avmRef); + NodeRef[] uploadedFiles = this.formProcessorSession.getUploadedFiles(); + final List diffList = new ArrayList(uploadedFiles.length); + for (NodeRef uploadedFile : uploadedFiles) + { + final String path = AVMNodeConverter.ToAVMVersionPath(uploadedFile).getSecond(); + diffList.add(new AVMDifference(-1, path, + -1, path.replaceFirst(AVMConstants.STORE_PREVIEW, + AVMConstants.STORE_MAIN), + AVMDifference.NEWER)); + } + this.avmSyncService.update(diffList, null, true, true, true, true, null, null); + } + + resetState(); + + return AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; + } + catch (Throwable err) + { + // rollback the transaction + try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} + Utils.addErrorMessage(Application.getMessage( + FacesContext.getCurrentInstance(), CheckinCheckoutBean.MSG_ERROR_UPDATE) + err.getMessage()); + return null; } - - return outcome; } /** @@ -452,6 +503,8 @@ public class AVMEditBean clearUpload(); setDocumentContent(null); setEditorOutput(null); + this.instanceDataDocument = null; + this.formProcessorSession = null; } /** diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java index 190f46962e..7b5a3950f1 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java @@ -64,6 +64,7 @@ import org.alfresco.web.forms.FormProcessor; import org.alfresco.web.forms.FormsService; import org.alfresco.web.forms.Rendition; import org.alfresco.web.ui.common.Utils; +import org.alfresco.web.ui.common.component.UIListItem; import org.alfresco.web.ui.wcm.component.UIUserSandboxes; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -82,9 +83,10 @@ public class CreateWebContentWizard extends BaseContentWizard protected String createdPath = null; protected List renditions = null; protected FormInstanceData formInstanceData = null; + protected FormProcessor.Session formProcessorSession = null; + private Document instanceDataDocument = null; protected boolean formSelectDisabled = false; protected boolean startWorkflow = false; - protected String[] uploadedFilePaths = null; /** AVM service bean reference */ protected AVMService avmService; @@ -145,9 +147,15 @@ public class CreateWebContentWizard extends BaseContentWizard this.formName = null; this.mimeType = MimetypeMap.MIMETYPE_XML; this.formInstanceData = null; - this.uploadedFilePaths = null; + if (this.formProcessorSession != null) + { + this.formProcessorSession.destroy(); + } + this.formProcessorSession = null; + this.instanceDataDocument = null; this.renditions = null; this.startWorkflow = false; + this.formSelectDisabled = false; // check for a form ID being passed in as a parameter if (this.parameters.get(UIUserSandboxes.PARAM_FORM_ID) != null) @@ -199,8 +207,22 @@ public class CreateWebContentWizard extends BaseContentWizard if (step == 2) { LOGGER.debug("clearing form instance data"); + if (this.formInstanceData != null) + { + final NodeRef nr = this.formInstanceData.getNodeRef(); + final String path = AVMNodeConverter.ToAVMVersionPath(nr).getSecond(); + this.avmService.removeNode(path); + } + if (this.renditions != null) + { + for (Rendition r : this.renditions) + { + final NodeRef nr = r.getNodeRef(); + final String path = AVMNodeConverter.ToAVMVersionPath(nr).getSecond(); + this.avmService.removeNode(path); + } + } this.formInstanceData = null; - this.uploadedFilePaths = null; this.renditions = null; } return super.back(); @@ -228,8 +250,11 @@ public class CreateWebContentWizard extends BaseContentWizard protected String finishImpl(final FacesContext context, final String outcome) throws Exception { + final NodeRef[] uploadedFiles = (this.formProcessorSession != null + ? this.formProcessorSession.getUploadedFiles() + : new NodeRef[0]); final List diffList = - new ArrayList(1 + this.renditions.size()); + new ArrayList(1 + this.renditions.size() + uploadedFiles.length); diffList.add(new AVMDifference(-1, this.createdPath, -1, this.createdPath.replaceFirst(AVMConstants.STORE_PREVIEW, AVMConstants.STORE_MAIN), @@ -243,8 +268,9 @@ public class CreateWebContentWizard extends BaseContentWizard AVMDifference.NEWER)); } - for (String path : this.uploadedFilePaths) + for (NodeRef uploadedFile : uploadedFiles) { + final String path = AVMNodeConverter.ToAVMVersionPath(uploadedFile).getSecond(); diffList.add(new AVMDifference(-1, path, -1, path.replaceFirst(AVMConstants.STORE_PREVIEW, AVMConstants.STORE_MAIN), @@ -255,8 +281,7 @@ public class CreateWebContentWizard extends BaseContentWizard { for (AVMDifference diff : diffList) { - LOGGER.debug("updating " + AVMConstants.STORE_MAIN + - " with " + diff.getSourcePath()); + LOGGER.debug("updating " + AVMConstants.STORE_MAIN + " with " + diff.getSourcePath()); } } this.avmSyncService.update(diffList, null, true, true, true, true, null, null); @@ -393,6 +418,11 @@ public class CreateWebContentWizard extends BaseContentWizard } } } + + if (this.formProcessorSession != null) + { + this.formProcessorSession.destroy(); + } // return the default outcome return outcome; @@ -431,9 +461,8 @@ public class CreateWebContentWizard extends BaseContentWizard path = path.replaceFirst(AVMConstants.STORE_MAIN, AVMConstants.STORE_PREVIEW); if (MimetypeMap.MIMETYPE_XML.equals(this.mimeType) && this.formName != null) { - final Document formInstanceData = fs.parseXML(this.content); - - path = this.getForm().getOutputPathForFormInstanceData(path, fileName, formInstanceData); + path = this.getForm().getOutputPathForFormInstanceData(path, fileName, this.instanceDataDocument); + this.content = FormsService.getInstance().writeXMLToString(this.instanceDataDocument); final String[] sb = AVMNodeConverter.SplitBase(path); path = sb[0]; fileName = sb[1]; @@ -594,45 +623,87 @@ public class CreateWebContentWizard extends BaseContentWizard * @return Returns the wrapper instance data for feeding the xml * content to the form processor. */ - public FormProcessor.InstanceData getInstanceData() + public Document getInstanceDataDocument() { - return new FormProcessor.InstanceData() + if (this.instanceDataDocument == null) { - private final FormsService ts = FormsService.getInstance(); - - public Document load() - { - try - { - final String content = CreateWebContentWizard.this.getContent(); - return content != null ? this.ts.parseXML(content) : null; - } - catch (Exception e) - { - e.printStackTrace(); - return null; - } - } - - public void save(final Document d, - final String[] uploadedFilePaths) + final FormsService fs = FormsService.getInstance(); + final String content = this.getContent(); + try { - CreateWebContentWizard.this.setContent(ts.writeXMLToString(d)); - CreateWebContentWizard.this.uploadedFilePaths = uploadedFilePaths; + this.instanceDataDocument = (content != null + ? fs.parseXML(content) + : fs.newDocument()); } - }; + catch (Exception e) + { + Utils.addErrorMessage("error parsing document", e); + this.instanceDataDocument = fs.newDocument(); + } + } + return this.instanceDataDocument; } + /** + * Returns the form processor session. + */ + public FormProcessor.Session getFormProcessorSession() + { + return this.formProcessorSession; + } + + /** + * Sets the form processor session. + */ + public void setFormProcessorSession(final FormProcessor.Session formProcessorSession) + { + this.formProcessorSession = formProcessorSession; + } + + /** + * Returns the generated form instance data. + */ public FormInstanceData getFormInstanceData() { return this.formInstanceData; } + /** + * Returns the generated renditions + */ public List getRenditions() { return this.renditions; } + /** + * Returns the files uploaded using the form + */ + public List getUploadedFiles() + { + if (this.formProcessorSession == null) + { + return Collections.emptyList(); + } + + NodeRef[] uploadedFiles = this.formProcessorSession.getUploadedFiles(); + final List result = + new ArrayList(uploadedFiles.length); + + for (NodeRef nodeRef : uploadedFiles) + { + final UIListItem item = new UIListItem(); + final String name = (String) + this.nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); + item.setValue(name); + item.setLabel((String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE)); + item.setDescription((String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION)); + item.setImage(Utils.getFileTypeImage(name, false)); + result.add(item); + } + return result; + } + public boolean getFormSelectDisabled() { return this.formSelectDisabled; diff --git a/source/java/org/alfresco/web/forms/FormProcessor.java b/source/java/org/alfresco/web/forms/FormProcessor.java index aa92b49a07..44cdb31702 100644 --- a/source/java/org/alfresco/web/forms/FormProcessor.java +++ b/source/java/org/alfresco/web/forms/FormProcessor.java @@ -16,12 +16,14 @@ */ package org.alfresco.web.forms; -import org.w3c.dom.Document; import java.io.Serializable; import java.io.Writer; +import org.alfresco.service.cmr.repository.NodeRef; +import org.w3c.dom.Document; /** * Generates a user interface for inputing data into a template. + * @author Ariel Backenroth */ public interface FormProcessor extends Serializable @@ -33,13 +35,38 @@ public interface FormProcessor * An abstraction layer around the xml content which allows * for reseting the xml content being collected by the input method. */ - public interface InstanceData + public interface Session { - - public Document load(); - - public void save(final Document d, - final String[] uploadedFilePaths); + + public NodeRef[] getUploadedFiles(); + + public void destroy(); + + public Form getForm(); + + public Document getFormInstanceData(); + } + + ///////////////////////////////////////////////////////////////////////////// + + public static class ProcessingException + extends Exception + { + + public ProcessingException(final String msg) + { + super(msg); + } + + public ProcessingException(final Exception cause) + { + super(cause); + } + + public ProcessingException(final String msg, final Exception cause) + { + super(msg, cause); + } } ///////////////////////////////////////////////////////////////////////////// @@ -47,11 +74,16 @@ public interface FormProcessor /** * Processes a user interface for inputing data into a form. * - * @param instanceData provides the xml instance data if available. + * @param formInstanceData provides the xml instance data if available. * @param form the form to generate for * @param out the writer to write the output to. */ - public void process(final FormProcessor.InstanceData instanceData, - final Form form, - final Writer out); + public Session process(final Document formInstanceData, + final Form form, + final Writer out) + throws ProcessingException; + + public void process(final Session session, + final Writer out) + throws ProcessingException; } diff --git a/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java b/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java index da0b8820ed..25af5c37df 100644 --- a/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java +++ b/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java @@ -357,7 +357,7 @@ public class SchemaFormBuilder SchemaFormBuilder.XMLSCHEMA_INSTANCE_NS); Element importedInstanceDocumentElement = null; - if (instanceDocument == null) + if (instanceDocument == null || instanceDocument.getDocumentElement() == null) instanceElement.appendChild(defaultInstanceDocumentElement); else { diff --git a/source/java/org/alfresco/web/forms/xforms/XFormsBean.java b/source/java/org/alfresco/web/forms/xforms/XFormsBean.java index a56a62c04e..d17d5aa421 100644 --- a/source/java/org/alfresco/web/forms/xforms/XFormsBean.java +++ b/source/java/org/alfresco/web/forms/xforms/XFormsBean.java @@ -23,11 +23,15 @@ import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; +import org.alfresco.model.ContentModel; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMService; +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.Application; import org.alfresco.web.app.servlet.FacesHelper; @@ -69,80 +73,104 @@ import org.xml.sax.SAXException; */ public class XFormsBean { + + ///////////////////////////////////////////////////////////////////////////// + + /** + */ + static class XFormsSession implements FormProcessor.Session + { + + private final Document formInstanceData; + private final Form form; + + private ChibaBean chibaBean; + private final SchemaFormBuilder schemaFormBuilder; + private final HashMap uploads = new HashMap(); + private final List eventLog = new LinkedList(); + + public XFormsSession(final Document formInstanceData, + final Form form, + final String baseUrl) + { + this.formInstanceData = formInstanceData; + this.form = form; + this.schemaFormBuilder = + new SchemaFormBuilder("/ajax/invoke/XFormsBean.handleAction", + SchemaFormBuilder.SUBMIT_METHOD_POST, + new XHTMLWrapperElementsBuilder(), + baseUrl); + } + + public NodeRef[] getUploadedFiles() + { + return (NodeRef[])this.uploads.values().toArray(new NodeRef[0]); + } + + public void destroy() + { + this.uploads.clear(); + try + { + this.chibaBean.shutdown(); + } + catch (XFormsException xfe) + { + LOGGER.debug(xfe); + } + } + + public Form getForm() + { + return this.form; + } + + public Document getFormInstanceData() + { + return this.formInstanceData; + } + } + + ///////////////////////////////////////////////////////////////////////////// + private static final Log LOGGER = LogFactory.getLog(XFormsBean.class); - private Form form; - private FormProcessor.InstanceData instanceData = null; - private final ChibaBean chibaBean = new ChibaBean(); - private SchemaFormBuilder schemaFormBuilder = null; - private final HashMap uploads = new HashMap(); - private final List eventLog = new LinkedList(); + private XFormsSession xformsSession; - /** @return the form */ - public Form getForm() - { - return this.form; - } - - /** @param tt the template type */ - public void setForm(final Form form) - { - this.form = form; - } - - /** @param instanceData the instance data being modified. */ - public void setInstanceData(final FormProcessor.InstanceData instanceData) - { - this.instanceData = instanceData; - } - - /** - * Initializes the chiba process with the xform and registers any necessary - * event listeners. - */ - public void init() + /** @param xformsSession the current session */ + public void setXFormsSession(final XFormsSession xformsSession) throws XFormsException { - if (LOGGER.isDebugEnabled()) - { - LOGGER.debug("initializing " + this + " with form " + this.form.getName()); - } + this.xformsSession = xformsSession; + final FacesContext facesContext = FacesContext.getCurrentInstance(); final ExternalContext externalContext = facesContext.getExternalContext(); final HttpServletRequest request = (HttpServletRequest) externalContext.getRequest(); - XFormsBean.storeCookies(request.getCookies(), this.chibaBean); + + final ChibaBean chibaBean = new ChibaBean(); + XFormsBean.storeCookies(request.getCookies(), chibaBean); final HttpSession session = (HttpSession)externalContext.getSession(true); final AVMBrowseBean browseBean = (AVMBrowseBean) session.getAttribute("AVMBrowseBean"); final String cwdAVMPath = browseBean.getCurrentPath(); - final String baseUrl = (request.getScheme() + "://" + - request.getServerName() + ':' + - request.getServerPort() + - request.getContextPath()); if (LOGGER.isDebugEnabled()) { - LOGGER.debug("building xform for schema " + form.getName() + - " with baseUrl " + baseUrl + - " root element " + form.getSchemaRootElementName() + + LOGGER.debug("building xform for schema " + this.xformsSession.form.getName() + + " root element " + this.xformsSession.form.getSchemaRootElementName() + " avm cwd " + cwdAVMPath); } - this.schemaFormBuilder = - new SchemaFormBuilder("/ajax/invoke/XFormsBean.handleAction", - SchemaFormBuilder.SUBMIT_METHOD_POST, - new XHTMLWrapperElementsBuilder(), - baseUrl); try { - final Document schemaDocument = this.form.getSchema(); - this.rewriteInlineURIs(schemaDocument, cwdAVMPath); + final Document schemaDocument = this.xformsSession.form.getSchema(); + XFormsBean.rewriteInlineURIs(schemaDocument, cwdAVMPath); final Document xformsDocument = - this.schemaFormBuilder.buildXForm(instanceData.load(), - schemaDocument, - this.form.getSchemaRootElementName()); + this.xformsSession.schemaFormBuilder.buildXForm(this.xformsSession.formInstanceData, + schemaDocument, + this.xformsSession.form.getSchemaRootElementName()); if (LOGGER.isDebugEnabled()) { @@ -150,16 +178,16 @@ public class XFormsBean FormsService.getInstance().writeXMLToString(xformsDocument)); } - this.chibaBean.setXMLContainer(xformsDocument); + chibaBean.setXMLContainer(xformsDocument); final EventTarget et = (EventTarget) - this.chibaBean.getXMLContainer().getDocumentElement(); + chibaBean.getXMLContainer().getDocumentElement(); final EventListener el = new EventListener() { - public void handleEvent(Event e) + public void handleEvent(final Event e) { XFormsBean.LOGGER.debug("received event " + e); - XFormsBean.this.eventLog.add((XFormsEvent)e); + XFormsBean.this.xformsSession.eventLog.add((XFormsEvent)e); } }; // interaction events my occur during init so we have to register before @@ -167,7 +195,7 @@ public class XFormsBean et.addEventListener(XFormsEventFactory.CHIBA_RENDER_MESSAGE, el, true); et.addEventListener(XFormsEventFactory.CHIBA_REPLACE_ALL, el, true); - this.chibaBean.init(); + chibaBean.init(); // register for notification events et.addEventListener(XFormsEventFactory.SUBMIT_DONE, el, true); @@ -197,6 +225,33 @@ public class XFormsBean { LOGGER.error(saxe); } + this.xformsSession.chibaBean = chibaBean; + } + + /** + * Initializes the chiba process with the xform and registers any necessary + * event listeners. + */ + public static XFormsSession createSession(final Document formInstanceData, + final Form form) + throws XFormsException + { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("initializing xforms session with form " + form.getName() + + " and instance data " + formInstanceData); + } + + final FacesContext facesContext = FacesContext.getCurrentInstance(); + final ExternalContext externalContext = facesContext.getExternalContext(); + final HttpServletRequest request = (HttpServletRequest) + externalContext.getRequest(); + + final String baseUrl = (request.getScheme() + "://" + + request.getServerName() + ':' + + request.getServerPort() + + request.getContextPath()); + return new XFormsSession(formInstanceData, form, baseUrl); } /** @@ -210,7 +265,8 @@ public class XFormsBean LOGGER.debug(this + ".getXForm()"); final FacesContext context = FacesContext.getCurrentInstance(); final ResponseWriter out = context.getResponseWriter(); - final Node xformsDocument = this.chibaBean.getXMLContainer(); + final ChibaBean chibaBean = this.xformsSession.chibaBean; + final Node xformsDocument = chibaBean.getXMLContainer(); FormsService.getInstance().writeXML(xformsDocument, out); } @@ -230,13 +286,14 @@ public class XFormsBean final String value = (String)requestParameters.get("value"); LOGGER.debug(this + ".setXFormsValue(" + id + ", " + value + ")"); - if (this.chibaBean.lookup(id) instanceof Upload) + final ChibaBean chibaBean = this.xformsSession.chibaBean; + if (chibaBean.lookup(id) instanceof Upload) { - this.chibaBean.updateControlValue(id, null, value, value.getBytes()); + chibaBean.updateControlValue(id, null, value, value.getBytes()); } else { - this.chibaBean.updateControlValue(id, value); + chibaBean.updateControlValue(id, value); } final ResponseWriter out = context.getResponseWriter(); @@ -260,7 +317,8 @@ public class XFormsBean final int index = Integer.parseInt((String)requestParameters.get("index")); LOGGER.debug(this + ".setRepeatIndex(" + id + ", " + index + ")"); - this.chibaBean.updateRepeatIndex(id, index); + final ChibaBean chibaBean = this.xformsSession.chibaBean; + chibaBean.updateRepeatIndex(id, index); final ResponseWriter out = context.getResponseWriter(); FormsService.getInstance().writeXML(this.getEventLog(), out); @@ -280,7 +338,8 @@ public class XFormsBean final String id = (String)requestParameters.get("id"); LOGGER.debug(this + ".fireAction(" + id + ")"); - this.chibaBean.dispatch(id, XFormsEventFactory.DOM_ACTIVATE); + final ChibaBean chibaBean = this.xformsSession.chibaBean; + chibaBean.dispatch(id, XFormsEventFactory.DOM_ACTIVATE); final ResponseWriter out = context.getResponseWriter(); FormsService.getInstance().writeXML(this.getEventLog(), out); @@ -300,19 +359,25 @@ public class XFormsBean context.getExternalContext().getRequest(); final FormsService formsService = FormsService.getInstance(); final Document result = formsService.parseXML(request.getInputStream()); - this.schemaFormBuilder.removePrototypeNodes(result.getDocumentElement()); + final Document instanceData = this.xformsSession.getFormInstanceData(); + Element documentElement = instanceData.getDocumentElement(); + if (documentElement != null) + { + instanceData.removeChild(documentElement); + } - final String[] uploadedFilePaths = (String[]) - this.uploads.values().toArray(new String[0]); - this.instanceData.save(result, uploadedFilePaths); + documentElement = result.getDocumentElement(); + this.xformsSession.schemaFormBuilder.removePrototypeNodes(documentElement); + documentElement = (Element)instanceData.importNode(documentElement, true); + instanceData.appendChild(documentElement); final ResponseWriter out = context.getResponseWriter(); - formsService.writeXML(result, out); + formsService.writeXML(instanceData, out); out.close(); } catch (Throwable t) { - LOGGER.error(t); + LOGGER.error(t.getMessage(), t); } } @@ -328,8 +393,9 @@ public class XFormsBean final String fromItemId = (String)requestParameters.get("fromItemId"); final String toItemId = (String)requestParameters.get("toItemId"); LOGGER.debug(this + ".swapRepeatItems(" + fromItemId + ", " + toItemId + ")"); - this.swapRepeatItems(this.chibaBean.lookup(fromItemId), - this.chibaBean.lookup(toItemId)); + final ChibaBean chibaBean = this.xformsSession.chibaBean; + this.swapRepeatItems(chibaBean.lookup(fromItemId), + chibaBean.lookup(toItemId)); final ResponseWriter out = context.getResponseWriter(); FormsService.getInstance().writeXML(this.getEventLog(), out); @@ -483,7 +549,16 @@ public class XFormsBean FileCopyUtils.copy(fileInputStream, avmService.createFile(currentPath, filename)); - this.uploads.put(uploadId, currentPath + "/" + filename); + final NodeRef uploadNodeRef = + AVMNodeConverter.ToNodeRef(-1, currentPath + "/" + filename); + final Map props = new HashMap(2, 1.0f); + props.put(ContentModel.PROP_TITLE, filename); + props.put(ContentModel.PROP_DESCRIPTION, + "Uploaded for form " + this.xformsSession.getForm().getName()); + final NodeService nodeService = serviceRegistry.getNodeService(); + nodeService.addAspect(uploadNodeRef, ContentModel.ASPECT_TITLED, props); + + this.xformsSession.uploads.put(uploadId, uploadNodeRef); LOGGER.debug("upload complete. sending response"); final FormsService formsService = FormsService.getInstance(); @@ -542,8 +617,8 @@ public class XFormsBean } } - private void rewriteInlineURIs(final Document schemaDocument, - final String cwdAvmPath) + private static void rewriteInlineURIs(final Document schemaDocument, + final String cwdAvmPath) { final NodeList includes = schemaDocument.getElementsByTagNameNS(SchemaFormBuilder.XMLSCHEMA_NS, "include"); @@ -570,7 +645,7 @@ public class XFormsBean final Document result = formsService.newDocument(); final Element eventsElement = result.createElement("events"); result.appendChild(eventsElement); - for (XFormsEvent xfe : this.eventLog) + for (XFormsEvent xfe : this.xformsSession.eventLog) { final String type = xfe.getType(); if (LOGGER.isDebugEnabled()) @@ -604,7 +679,7 @@ public class XFormsBean } } } - this.eventLog.clear(); + this.xformsSession.eventLog.clear(); if (LOGGER.isDebugEnabled()) { diff --git a/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java b/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java index 9c8b9a9490..4a8a262e07 100644 --- a/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java +++ b/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java @@ -33,75 +33,92 @@ import org.alfresco.web.app.servlet.FacesHelper; import org.chiba.xml.xforms.exception.XFormsException; public class XFormsProcessor - implements FormProcessor + implements FormProcessor { - private static final Log LOGGER = LogFactory.getLog(XFormsProcessor.class); - public XFormsProcessor() - { - } + private static final Log LOGGER = LogFactory.getLog(XFormsProcessor.class); - /** - * Generates html text which bootstraps the JavaScript code that will - * call back into the XFormsBean and get the xform and build the ui. - */ - public void process(final InstanceData instanceData, - final Form tt, - final Writer out) - { - final FormsService ts = FormsService.getInstance(); - final FacesContext fc = FacesContext.getCurrentInstance(); - //make the XFormsBean available for this session - final XFormsBean xforms = (XFormsBean) - FacesHelper.getManagedBean(fc, "XFormsBean"); - xforms.setInstanceData(instanceData); - xforms.setForm(tt); - try - { - xforms.init(); - } - catch (XFormsException xfe) - { - LOGGER.error(xfe); - } + public XFormsProcessor() + { + } + + public Session process(final Document instanceDataDocument, + final Form form, + final Writer out) + throws FormProcessor.ProcessingException + { + try + { + final Session result = + XFormsBean.createSession(instanceDataDocument, form); + this.process(result, out); + return result; + } + catch (XFormsException xfe) + { + LOGGER.error(xfe); + throw new FormProcessor.ProcessingException(xfe); + } + } + + /** + * Generates html text which bootstraps the JavaScript code that will + * call back into the XFormsBean and get the xform and build the ui. + */ + public void process(final Session session, final Writer out) + throws FormProcessor.ProcessingException + { + final FormsService ts = FormsService.getInstance(); + final FacesContext fc = FacesContext.getCurrentInstance(); + //make the XFormsBean available for this session + final XFormsBean xforms = (XFormsBean) + FacesHelper.getManagedBean(fc, "XFormsBean"); + try + { + xforms.setXFormsSession((XFormsBean.XFormsSession)session); + } + catch (XFormsException xfe) + { + LOGGER.error(xfe); + throw new ProcessingException(xfe); + } - final String cp = fc.getExternalContext().getRequestContextPath(); + final String cp = fc.getExternalContext().getRequestContextPath(); + final Document result = ts.newDocument(); - final Document result = ts.newDocument(); + // this div is where the ui will write to + final Element div = result.createElement("div"); + div.setAttribute("id", "alfresco-xforms-ui"); + result.appendChild(div); - // this div is where the ui will write to - final Element div = result.createElement("div"); - div.setAttribute("id", "alfresco-xforms-ui"); - result.appendChild(div); - - // a script with config information and globals. - Element e = result.createElement("script"); - e.setAttribute("type", "text/javascript"); - e.appendChild(result.createTextNode("\ndjConfig = { isDebug: " + LOGGER.isDebugEnabled() + - " };\n" + - "var WEBAPP_CONTEXT = \"" + cp + "\";\n")); - div.appendChild(e); - final String[] scripts = - { - "/scripts/tiny_mce/" + (LOGGER.isDebugEnabled() - ? "tiny_mce_src.js" - : "tiny_mce.js"), + // a script with config information and globals. + Element e = result.createElement("script"); + e.setAttribute("type", "text/javascript"); + e.appendChild(result.createTextNode("\ndjConfig = { isDebug: " + LOGGER.isDebugEnabled() + + " };\n" + + "var WEBAPP_CONTEXT = \"" + cp + "\";\n")); + div.appendChild(e); + final String[] scripts = + { + "/scripts/tiny_mce/" + (LOGGER.isDebugEnabled() + ? "tiny_mce_src.js" + : "tiny_mce.js"), "/scripts/ajax/dojo/" + (LOGGER.isDebugEnabled() ? "dojo.js.uncompressed.js" : "dojo.js"), "/scripts/ajax/xforms.js" - }; + }; - // include all our scripts, order is significant - for (int i = 0; i < scripts.length; i++) - { - e = result.createElement("script"); - e.setAttribute("type", "text/javascript"); - e.setAttribute("src", cp + scripts[i]); - e.appendChild(result.createTextNode("\n")); - div.appendChild(e); - } + // include all our scripts, order is significant + for (int i = 0; i < scripts.length; i++) + { + e = result.createElement("script"); + e.setAttribute("type", "text/javascript"); + e.setAttribute("src", cp + scripts[i]); + e.appendChild(result.createTextNode("\n")); + div.appendChild(e); + } - ts.writeXML(result, out); - } + ts.writeXML(result, out); + } } diff --git a/source/java/org/alfresco/web/ui/wcm/component/UIFormProcessor.java b/source/java/org/alfresco/web/ui/wcm/component/UIFormProcessor.java index bb462e7b2c..a8d001fff0 100644 --- a/source/java/org/alfresco/web/ui/wcm/component/UIFormProcessor.java +++ b/source/java/org/alfresco/web/ui/wcm/component/UIFormProcessor.java @@ -23,9 +23,11 @@ import javax.faces.context.ResponseWriter; import javax.faces.el.ValueBinding; import org.alfresco.web.forms.*; +import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.component.SelfRenderingComponent; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; /** * @author Ariel Backenroth @@ -34,12 +36,11 @@ public class UIFormProcessor extends SelfRenderingComponent { private static final Log LOGGER = LogFactory.getLog(UIFormProcessor.class); - - private FormProcessor.InstanceData formInstanceData = null; + private Document formInstanceData = null; private Form form = null; - - + private FormProcessor.Session formProcessorSession; + // ------------------------------------------------------------------------------ // Component implementation @@ -52,13 +53,14 @@ public class UIFormProcessor extends SelfRenderingComponent return "org.alfresco.faces.FormProcessor"; } - public void restoreState(FacesContext context, Object state) + public void restoreState(final FacesContext context, final Object state) { final Object values[] = (Object[])state; // standard component attributes are restored by the super class super.restoreState(context, values[0]); - this.formInstanceData = (FormProcessor.InstanceData)values[1]; + this.formInstanceData = (Document)values[1]; this.form = (Form)values[2]; + this.formProcessorSession = (FormProcessor.Session)values[3]; } public Object saveState(FacesContext context) @@ -67,7 +69,8 @@ public class UIFormProcessor extends SelfRenderingComponent // standard component attributes are saved by the super class super.saveState(context), this.formInstanceData, - this.form + this.form, + this.formProcessorSession }; return values; } @@ -79,16 +82,37 @@ public class UIFormProcessor extends SelfRenderingComponent public void encodeBegin(final FacesContext context) throws IOException { - if (isRendered() == false) + if (!isRendered()) { return; } final ResponseWriter out = context.getResponseWriter(); final Form form = this.getForm(); - final FormProcessor.InstanceData formInstanceData = this.getFormInstanceData(); - final FormProcessor tim = form.getFormProcessors().get(0); - tim.process(formInstanceData, form, out); + final FormProcessor fp = form.getFormProcessors().get(0); + try + { + if (this.getFormProcessorSession() != null && + this.getFormProcessorSession().getForm().equals(this.getForm())) + { + fp.process(this.getFormProcessorSession(), out); + } + else + { + if (this.getFormProcessorSession() != null) + { + this.getFormProcessorSession().destroy(); + this.setFormProcessorSession(null); + } + this.setFormProcessorSession(fp.process(this.getFormInstanceData(), + form, + out)); + } + } + catch (FormProcessor.ProcessingException fppe) + { + Utils.addErrorMessage(fppe.getMessage(), fppe); + } } // ------------------------------------------------------------------------------ @@ -99,12 +123,12 @@ public class UIFormProcessor extends SelfRenderingComponent * * @return The instance data to render */ - public FormProcessor.InstanceData getFormInstanceData() + public Document getFormInstanceData() { final ValueBinding vb = getValueBinding("formInstanceData"); if (vb != null) { - this.formInstanceData = (FormProcessor.InstanceData)vb.getValue(getFacesContext()); + this.formInstanceData = (Document)vb.getValue(getFacesContext()); } return this.formInstanceData; @@ -115,7 +139,7 @@ public class UIFormProcessor extends SelfRenderingComponent * * @param formInstanceData The instance data to render */ - public void setFormInstanceData(final FormProcessor.InstanceData formInstanceData) + public void setFormInstanceData(final Document formInstanceData) { this.formInstanceData = formInstanceData; } @@ -127,7 +151,7 @@ public class UIFormProcessor extends SelfRenderingComponent */ public Form getForm() { - final ValueBinding vb = getValueBinding("form"); + final ValueBinding vb = this.getValueBinding("form"); if (vb != null) { this.form = (Form)vb.getValue(getFacesContext()); @@ -145,4 +169,36 @@ public class UIFormProcessor extends SelfRenderingComponent { this.form = form; } + + /** + * Returns the form processor session + * + * @return the form processor session + */ + public FormProcessor.Session getFormProcessorSession() + { + final ValueBinding vb = this.getValueBinding("formProcessorSession"); + if (vb != null) + { + this.formProcessorSession = (FormProcessor.Session) + vb.getValue(getFacesContext()); + } + + return this.formProcessorSession; + } + + /** + * Sets the form processor session + * + * @param formProcessorSession the form processor session. + */ + public void setFormProcessorSession(final FormProcessor.Session formProcessorSession) + { + final ValueBinding vb = this.getValueBinding("formProcessorSession"); + if (vb != null) + { + vb.setValue(getFacesContext(), formProcessorSession); + } + this.formProcessorSession = formProcessorSession; + } } diff --git a/source/java/org/alfresco/web/ui/wcm/tag/FormProcessorTag.java b/source/java/org/alfresco/web/ui/wcm/tag/FormProcessorTag.java index 771206661b..2c5ae44f2a 100644 --- a/source/java/org/alfresco/web/ui/wcm/tag/FormProcessorTag.java +++ b/source/java/org/alfresco/web/ui/wcm/tag/FormProcessorTag.java @@ -27,6 +27,11 @@ import org.alfresco.web.ui.common.tag.BaseComponentTag; */ public class FormProcessorTag extends BaseComponentTag { + + private String formInstanceData; + private String templateType; + private String formProcessorSession; + /** * @see javax.faces.webapp.UIComponentTag#getComponentType() */ @@ -50,10 +55,10 @@ public class FormProcessorTag extends BaseComponentTag { super.setProperties(component); final Application app = this.getFacesContext().getApplication(); - if (this.instanceData != null) + if (this.formInstanceData != null) { - assert isValueReference(this.instanceData); - final ValueBinding vb = app.createValueBinding(this.instanceData); + assert isValueReference(this.formInstanceData); + final ValueBinding vb = app.createValueBinding(this.formInstanceData); component.setValueBinding("formInstanceData", vb); } if (this.templateType != null) @@ -62,6 +67,12 @@ public class FormProcessorTag extends BaseComponentTag final ValueBinding vb = app.createValueBinding(this.templateType); component.setValueBinding("form", vb); } + if (this.formProcessorSession != null) + { + assert this.isValueReference(this.formProcessorSession); + final ValueBinding vb = app.createValueBinding(this.formProcessorSession); + component.setValueBinding("formProcessorSession", vb); + } } /** @@ -70,18 +81,19 @@ public class FormProcessorTag extends BaseComponentTag public void release() { super.release(); - this.instanceData = null; + this.formInstanceData = null; this.templateType = null; + this.formProcessorSession = null; } /** * Set the instance data * - * @param instanceData the instance data for the processor + * @param formInstanceData the instance data for the processor */ - public void setFormInstanceData(final String instanceData) + public void setFormInstanceData(final String formInstanceData) { - this.instanceData = instanceData; + this.formInstanceData = formInstanceData; } /** @@ -93,7 +105,14 @@ public class FormProcessorTag extends BaseComponentTag { this.templateType = templateType; } - - private String instanceData; - private String templateType; + + /** + * Sets the form processor session + * + * @param formProcessorSession the binding for the form processor session + */ + public void setFormProcessorSession(final String formProcessorSession) + { + this.formProcessorSession = formProcessorSession; + } } diff --git a/source/web/WEB-INF/faces-config-beans.xml b/source/web/WEB-INF/faces-config-beans.xml index e64876eeb4..12e516c0d7 100644 --- a/source/web/WEB-INF/faces-config-beans.xml +++ b/source/web/WEB-INF/faces-config-beans.xml @@ -2326,6 +2326,10 @@ avmService #{AVMService} + + avmSyncService + #{AVMSyncService} + contentService #{ContentService} diff --git a/source/web/WEB-INF/wcm.tld b/source/web/WEB-INF/wcm.tld index 90595f47ae..e9278bb122 100644 --- a/source/web/WEB-INF/wcm.tld +++ b/source/web/WEB-INF/wcm.tld @@ -112,6 +112,13 @@ true The form to use to render this form. + + + formProcessorSession + true + true + The form processor session value binding. + binding diff --git a/source/web/jsp/wcm/create-web-content-wizard/create-xml.jsp b/source/web/jsp/wcm/create-web-content-wizard/create-xml.jsp index 98d8b88799..c83e1f30e4 100644 --- a/source/web/jsp/wcm/create-web-content-wizard/create-xml.jsp +++ b/source/web/jsp/wcm/create-web-content-wizard/create-xml.jsp @@ -28,5 +28,6 @@ function _xforms_getSubmitButtons() } diff --git a/source/web/jsp/wcm/create-web-content-wizard/summary.jsp b/source/web/jsp/wcm/create-web-content-wizard/summary.jsp index 1aa8ba3769..3e78444fc1 100644 --- a/source/web/jsp/wcm/create-web-content-wizard/summary.jsp +++ b/source/web/jsp/wcm/create-web-content-wizard/summary.jsp @@ -88,6 +88,21 @@ + + + + + + + + + + diff --git a/source/web/jsp/wcm/edit-xml-inline.jsp b/source/web/jsp/wcm/edit-xml-inline.jsp index cca70988d2..18f84890de 100644 --- a/source/web/jsp/wcm/edit-xml-inline.jsp +++ b/source/web/jsp/wcm/edit-xml-inline.jsp @@ -104,7 +104,8 @@ function _xforms_getSubmitButtons() <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "white", "white"); %> <% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "white"); %>