diff --git a/config/alfresco/web-client-application-context.xml b/config/alfresco/web-client-application-context.xml index 1a3c05c9b8..f43f7ea6d2 100644 --- a/config/alfresco/web-client-application-context.xml +++ b/config/alfresco/web-client-application-context.xml @@ -57,6 +57,9 @@ + + + diff --git a/source/java/org/alfresco/web/bean/wcm/AVMConstants.java b/source/java/org/alfresco/web/bean/wcm/AVMConstants.java index 22f49c72dd..6ffc782764 100644 --- a/source/java/org/alfresco/web/bean/wcm/AVMConstants.java +++ b/source/java/org/alfresco/web/bean/wcm/AVMConstants.java @@ -18,6 +18,8 @@ package org.alfresco.web.bean.wcm; import java.text.MessageFormat; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.faces.context.FacesContext; @@ -122,6 +124,44 @@ public final class AVMConstants return dns; } + + /** + * Converts the provided path to an absolute path within the avm. + * + * @param parentAVMPath used as the parent path if the provided path + * is relative, otherwise used to extract the parent path portion up until + * the webapp directory. + * @param path a path relative to the parentAVMPath path, or if it is + * absolute, it is relative to the webapp used in the parentAVMPath. + * + * @return an absolute path within the avm using the paths provided. + */ + public static String buildAbsoluteAVMPath(final String parentAVMPath, final String path) + { + String parent = parentAVMPath; + if (path == null || path.length() == 0 || + ".".equals(path) || "./".equals(path)) + { + return parent; + } + + if (path.charAt(0) == '/') + { + final Pattern p = Pattern.compile("([^:]+:/" + AVMConstants.DIR_APPBASE + + "/[^/]+/[^/]+).*"); + final Matcher m = p.matcher(parent); + if (m.matches()) + { + parent = m.group(1); + } + } + else if (parent.charAt(parent.length() - 1) != '/') + { + parent = parent + '/'; + } + + return parent + path; + } // names of the stores representing the layers for an AVM website public final static String STORE_STAGING = "-staging"; diff --git a/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java index b9d596c1a1..d2555fe07d 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java @@ -27,13 +27,16 @@ import java.util.Map; import java.util.ResourceBundle; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; +import javax.faces.event.ValueChangeEvent; import javax.faces.model.DataModel; import javax.faces.model.ListDataModel; import javax.faces.model.SelectItem; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.model.WCMModel; +import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.service.cmr.model.FileExistsException; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.MimetypeService; @@ -57,7 +60,8 @@ import org.w3c.dom.Document; * * @author arielb */ -public class CreateFormWizard extends BaseWizardBean +public class CreateFormWizard + extends BaseWizardBean { ///////////////////////////////////////////////////////////////////////////// @@ -65,35 +69,35 @@ public class CreateFormWizard extends BaseWizardBean /** * Simple wrapper class to represent a form data renderer */ - public class RenderingEngineData + public class RenderingEngineTemplateData { private final String fileName; private final File file; - private final String fileExtension; - private final String mimetype; - private final Class renderingEngineType; + private final String mimetypeForRendition; + private final String outputPathPatternForRendition; + private final RenderingEngine renderingEngine; - public RenderingEngineData(final String fileName, - final File file, - final String fileExtension, - final String mimetype, - final Class renderingEngineType) + public RenderingEngineTemplateData(final String fileName, + final File file, + final String outputPathPatternForRendition, + final String mimetypeForRendition, + final RenderingEngine renderingEngine) { this.fileName = fileName; this.file = file; - this.fileExtension = fileExtension; - this.mimetype = mimetype; - this.renderingEngineType = renderingEngineType; + this.outputPathPatternForRendition = outputPathPatternForRendition; + this.mimetypeForRendition = mimetypeForRendition; + this.renderingEngine = renderingEngine; } - public String getFileExtension() + public String getOutputPathPatternForRendition() { - return this.fileExtension; + return this.outputPathPatternForRendition; } - public String getMimetype() + public String getMimetypeForRendition() { - return this.mimetype; + return this.mimetypeForRendition; } public String getFileName() @@ -106,20 +110,26 @@ public class CreateFormWizard extends BaseWizardBean return this.file; } - public Class getRenderingEngineType() + public RenderingEngine getRenderingEngine() { - return this.renderingEngineType; + return this.renderingEngine; } - - public String getRenderingEngineTypeName() + + public String toString() { - return CreateFormWizard.this.getRenderingEngineTypeName(this.getRenderingEngineType()); + return (this.getClass().getName() + "{" + + "fileName: " + this.getFileName() + "," + + "mimetypeForRendition: " + this.getMimetypeForRendition() + "," + + "outputPathPatternForRendition: " + this.getOutputPathPatternForRendition() + "," + + "renderingEngine: " + this.getRenderingEngine().getName() + + "}"); } } ///////////////////////////////////////////////////////////////////////////// - public static final String FILE_RENDERING_ENGINE = "rendering-engine"; + public static final String FILE_RENDERING_ENGINE_TEMPLATE = + "rendering-engine-template"; public static final String FILE_SCHEMA = "schema"; @@ -129,22 +139,25 @@ public class CreateFormWizard extends BaseWizardBean private String formName; private String formTitle; private String formDescription; - private Class renderingEngineType = null; + private RenderingEngine renderingEngine = null; protected ContentService contentService; protected MimetypeService mimetypeService; - private DataModel renderingEnginesDataModel; - private List renderingEngines = null; - private String fileExtension = null; - private String mimetype = null; + private DataModel renderingEngineTemplatesDataModel; + private List renderingEngineTemplates = null; + private String outputPathPatternForFormInstanceData = null; + private String outputPathPatternForRendition = null; + private String mimetypeForRendition = null; private List mimetypeChoices = null; // ------------------------------------------------------------------------------ // Wizard implementation @Override - protected String finishImpl(FacesContext context, String outcome) + protected String finishImpl(final FacesContext context, final String outcome) throws Exception { + LOGGER.debug("creating form " + this.getFormName()); + final FormsService ts = FormsService.getInstance(); // get the node ref of the node that will contain the content final NodeRef contentFormsNodeRef = ts.getContentFormsNodeRef(); @@ -157,18 +170,12 @@ public class CreateFormWizard extends BaseWizardBean this.fileFolderService.create(folderInfo.getNodeRef(), this.getSchemaFileName(), ContentModel.TYPE_CONTENT); - final NodeRef schemaNodeRef = fileInfo.getNodeRef(); - - if (LOGGER.isDebugEnabled()) - LOGGER.debug("Created file node for file: " + - this.getSchemaFileName()); - // get a writer for the content and put the file - ContentWriter writer = this.contentService.getWriter(schemaNodeRef, + ContentWriter writer = this.contentService.getWriter(fileInfo.getNodeRef(), ContentModel.PROP_CONTENT, true); // set the mimetype and encoding - writer.setMimetype("text/xml"); + writer.setMimetype(MimetypeMap.MIMETYPE_XML); writer.setEncoding("UTF-8"); writer.putContent(this.getSchemaFile()); @@ -176,46 +183,74 @@ public class CreateFormWizard extends BaseWizardBean Map props = new HashMap(2, 1.0f); props.put(ContentModel.PROP_TITLE, this.getFormTitle()); props.put(ContentModel.PROP_DESCRIPTION, this.getFormDescription()); - this.nodeService.addAspect(schemaNodeRef, ContentModel.ASPECT_TITLED, props); + this.nodeService.addAspect(folderInfo.getNodeRef(), ContentModel.ASPECT_TITLED, props); - props = new HashMap(1, 1.0f); - props.put(WCMModel.PROP_SCHEMA_ROOT_ELEMENT_NAME, this.getSchemaRootElementName()); - this.nodeService.addAspect(schemaNodeRef, WCMModel.ASPECT_FORM, props); + props = new HashMap(3, 1.0f); + props.put(WCMModel.PROP_XML_SCHEMA, fileInfo.getNodeRef()); + props.put(WCMModel.PROP_XML_SCHEMA_ROOT_ELEMENT_NAME, + this.getSchemaRootElementName()); + props.put(WCMModel.PROP_OUTPUT_PATH_PATTERN_FOR_FORM_INSTANCE_DATA, + this.getOutputPathPatternForFormInstanceData()); + this.nodeService.addAspect(folderInfo.getNodeRef(), WCMModel.ASPECT_FORM, props); - for (RenderingEngineData tomd : this.renderingEngines) + for (RenderingEngineTemplateData retd : this.renderingEngineTemplates) { - fileInfo = this.fileFolderService.create(folderInfo.getNodeRef(), - tomd.getFileName(), - ContentModel.TYPE_CONTENT); - final NodeRef renderingEngineNodeRef = fileInfo.getNodeRef(); - - if (LOGGER.isDebugEnabled()) - LOGGER.debug("Created file node for file: " + tomd.getFileName()); - - // get a writer for the content and put the file - writer = this.contentService.getWriter(renderingEngineNodeRef, - ContentModel.PROP_CONTENT, - true); - // set the mimetype and encoding - writer.setMimetype("text/xml"); - writer.setEncoding("UTF-8"); - writer.putContent(tomd.getFile()); + LOGGER.debug("adding rendering engine template " + retd + + " to form " + this.getFormName()); - this.nodeService.createAssociation(schemaNodeRef, - renderingEngineNodeRef, - WCMModel.ASSOC_RENDERING_ENGINES); - - props = new HashMap(3, 1.0f); - props.put(WCMModel.PROP_RENDERING_ENGINE_TYPE, - tomd.getRenderingEngineType().getName()); - props.put(WCMModel.PROP_FORM_SOURCE, schemaNodeRef); - props.put(WCMModel.PROP_FILE_EXTENSION_FOR_RENDITION, - tomd.getFileExtension()); + NodeRef renderingEngineTemplateNodeRef = + this.fileFolderService.searchSimple(folderInfo.getNodeRef(), retd.getFileName()); + if (renderingEngineTemplateNodeRef == null) + { + try + { + fileInfo = this.fileFolderService.create(folderInfo.getNodeRef(), + retd.getFileName(), + ContentModel.TYPE_CONTENT); + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Created file node for file: " + retd.getFileName()); + renderingEngineTemplateNodeRef = fileInfo.getNodeRef(); + } + catch (final FileExistsException fee) + { + LOGGER.error(fee.getName() + " already exists in " + + fee.getParentNodeRef()); + throw fee; + } + + // get a writer for the content and put the file + writer = this.contentService.getWriter(renderingEngineTemplateNodeRef, + ContentModel.PROP_CONTENT, + true); + // set the mimetype and encoding + // XXXarielb mime type of template isn't known + // writer.setMimetype("text/xml"); + writer.setEncoding("UTF-8"); + writer.putContent(retd.getFile()); + + this.nodeService.createAssociation(folderInfo.getNodeRef(), + renderingEngineTemplateNodeRef, + WCMModel.ASSOC_RENDERING_ENGINE_TEMPLATES); + props = new HashMap(2, 1.0f); + props.put(WCMModel.PROP_PARENT_RENDERING_ENGINE_NAME, + retd.getRenderingEngine().getName()); + props.put(WCMModel.PROP_FORM_SOURCE, folderInfo.getNodeRef()); + this.nodeService.addAspect(renderingEngineTemplateNodeRef, + WCMModel.ASPECT_RENDERING_ENGINE_TEMPLATE, + props); + } + + LOGGER.debug("adding rendition properties to " + renderingEngineTemplateNodeRef); + props = new HashMap(2, 1.0f); + props.put(WCMModel.PROP_OUTPUT_PATH_PATTERN_FOR_RENDITION, + retd.getOutputPathPatternForRendition()); props.put(WCMModel.PROP_MIMETYPE_FOR_RENDITION, - tomd.getMimetype()); - this.nodeService.addAspect(renderingEngineNodeRef, - WCMModel.ASPECT_RENDERING_ENGINE, - props); + retd.getMimetypeForRendition()); + this.nodeService.createNode(renderingEngineTemplateNodeRef, + WCMModel.ASSOC_RENDITION_PROPERTIES, + WCMModel.ASSOC_RENDITION_PROPERTIES, + WCMModel.TYPE_RENDITION_PROPERTIES, + props); } // return the default outcome return outcome; @@ -227,22 +262,23 @@ public class CreateFormWizard extends BaseWizardBean super.init(parameters); this.removeUploadedSchemaFile(); - this.removeUploadedRenderingEngineFile(); + this.removeUploadedRenderingEngineTemplateFile(); this.schemaRootElementName = null; this.formName = null; this.formTitle = null; this.formDescription = null; - this.renderingEngineType = null; - this.renderingEngines = new ArrayList(); - this.fileExtension = null; - this.mimetype = null; + this.renderingEngine = null; + this.renderingEngineTemplates = new ArrayList(); + this.outputPathPatternForFormInstanceData = null; + this.outputPathPatternForRendition = null; + this.mimetypeForRendition = null; } @Override public String cancel() { this.removeUploadedSchemaFile(); - this.removeUploadedRenderingEngineFile(); + this.removeUploadedRenderingEngineTemplateFile(); return super.cancel(); } @@ -274,89 +310,101 @@ public class CreateFormWizard extends BaseWizardBean */ public boolean getAddToListDisabled() { - return getRenderingEngineFileName() == null; + return this.getRenderingEngineTemplateFileName() == null; } /** - * @return Returns the fileExtension. + * @return Returns the output path for the rendition. */ - public String getFileExtension() + public String getOutputPathPatternForRendition() { - if (this.fileExtension == null && this.mimetype != null) + if (this.outputPathPatternForRendition == null && this.mimetypeForRendition != null) { - this.fileExtension = this.mimetypeService.getExtension(this.mimetype); + this.outputPathPatternForRendition = + ("${formInstanceData.name}." + + this.mimetypeService.getExtension(this.mimetypeForRendition)); } - return this.fileExtension; + return this.outputPathPatternForRendition; } /** - * @param fileExtension The fileExtension to set. + * @param outputPathPatternForRendition The output path for the rendition. */ - public void setFileExtension(String fileExtension) + public void setOutputPathPatternForRendition(final String outputPathPatternForRendition) { - this.fileExtension = fileExtension; + this.outputPathPatternForRendition = outputPathPatternForRendition; } /** * @return Returns the mimetype. */ - public String getMimetype() + public String getMimetypeForRendition() { - if (this.mimetype == null && this.fileExtension != null) + if (this.mimetypeForRendition == null && this.outputPathPatternForRendition != null) { - this.mimetype = this.mimetypeService.guessMimetype(this.fileExtension); + this.mimetypeForRendition = + this.mimetypeService.guessMimetype(this.outputPathPatternForRendition); } - return this.mimetype; + return this.mimetypeForRendition; } /** * @param mimetype The mimetype to set. */ - public void setMimetype(String mimetype) + public void setMimetypeForRendition(final String mimetypeForRendition) { - this.mimetype = mimetype; + this.mimetypeForRendition = mimetypeForRendition; } /** * Add the selected rendering engine to the list */ - public void addSelectedRenderingEngine(ActionEvent event) + public void addSelectedRenderingEngineTemplate(final ActionEvent event) { - for (RenderingEngineData tomd : this.renderingEngines) + for (RenderingEngineTemplateData retd : this.renderingEngineTemplates) { - if (tomd.getFileExtension().equals(this.fileExtension)) + if (retd.getOutputPathPatternForRendition().equals(this.outputPathPatternForRendition)) { - throw new AlfrescoRuntimeException("rendering engine with extension " + this.fileExtension + + throw new AlfrescoRuntimeException("rendering engine template with output path " + this.outputPathPatternForRendition + " already exists"); } } - final RenderingEngineData data = - this.new RenderingEngineData(this.getRenderingEngineFileName(), - this.getRenderingEngineFile(), - this.getFileExtension(), - this.getMimetype(), - this.renderingEngineType); - this.renderingEngines.add(data); - this.removeUploadedRenderingEngineFile(); - this.renderingEngineType = null; - this.fileExtension = null; - this.mimetype = null; + final RenderingEngineTemplateData data = + this.new RenderingEngineTemplateData(this.getRenderingEngineTemplateFileName(), + this.getRenderingEngineTemplateFile(), + this.getOutputPathPatternForRendition(), + this.getMimetypeForRendition(), + this.renderingEngine); + this.renderingEngineTemplates.add(data); + this.removeUploadedRenderingEngineTemplateFile(); + this.renderingEngine = null; + this.outputPathPatternForRendition = null; + this.mimetypeForRendition = null; } /** * Action handler called when the Remove button is pressed to remove a * rendering engine */ - public void removeSelectedRenderingEngine(ActionEvent event) + public void removeSelectedRenderingEngineTemplate(final ActionEvent event) { - final RenderingEngineData wrapper = (RenderingEngineData) - this.renderingEnginesDataModel.getRowData(); + final RenderingEngineTemplateData wrapper = (RenderingEngineTemplateData) + this.renderingEngineTemplatesDataModel.getRowData(); if (wrapper != null) { - this.renderingEngines.remove(wrapper); + this.renderingEngineTemplates.remove(wrapper); } } + + /** + * Action handler called when the user changes the selected mimetype + */ + public String mimetypeForRenditionChanged(final ValueChangeEvent vce) + { + // refresh the current page + return null; + } /** * Action handler called when the user wishes to remove an uploaded file @@ -372,9 +420,9 @@ public class CreateFormWizard extends BaseWizardBean /** * Action handler called when the user wishes to remove an uploaded file */ - public String removeUploadedRenderingEngineFile() + public String removeUploadedRenderingEngineTemplateFile() { - clearUpload(FILE_RENDERING_ENGINE); + clearUpload(FILE_RENDERING_ENGINE_TEMPLATE); // refresh the current page return null; @@ -389,65 +437,58 @@ public class CreateFormWizard extends BaseWizardBean * * @return JSF DataModel representing the current configured output methods */ - public DataModel getRenderingEnginesDataModel() + public DataModel getRenderingEngineTemplatesDataModel() { - if (this.renderingEnginesDataModel == null) + if (this.renderingEngineTemplatesDataModel == null) { - this.renderingEnginesDataModel = new ListDataModel(); + this.renderingEngineTemplatesDataModel = new ListDataModel(); } - this.renderingEnginesDataModel.setWrappedData(this.renderingEngines); + this.renderingEngineTemplatesDataModel.setWrappedData(this.renderingEngineTemplates); - return this.renderingEnginesDataModel; + return this.renderingEngineTemplatesDataModel; } /** * @return Returns the mime type currenty selected */ - public String getRenderingEngineType() + public String getRenderingEngineName() { - if (this.renderingEngineType == null && - this.getRenderingEngineFileName() != null) + if (this.renderingEngine == null && + this.getRenderingEngineTemplateFileName() != null) { - this.renderingEngineType = - (this.getRenderingEngineFileName().endsWith(".xsl") - ? XSLTRenderingEngine.class - : (this.getRenderingEngineFileName().endsWith(".ftl") - ? FreeMarkerRenderingEngine.class - : (this.getRenderingEngineFileName().endsWith(".fo") - ? XSLFORenderingEngine.class - : null))); + final FormsService fs = FormsService.getInstance(); + this.renderingEngine = + fs.guessRenderingEngine(this.getRenderingEngineTemplateFileName()); } - return (this.renderingEngineType == null + return (this.renderingEngine == null ? null - : this.renderingEngineType.getName()); + : this.renderingEngine.getName()); } /** - * @param renderingEngineType Sets the currently selected mime type + * @param renderingEngineName Sets the currently selected rendering engine name */ - public void setRenderingEngineType(final String renderingEngineType) - throws ClassNotFoundException + public void setRenderingEngineName(final String renderingEngineName) { - this.renderingEngineType = (renderingEngineType == null - ? null - : Class.forName(renderingEngineType)); + final FormsService fs = FormsService.getInstance(); + this.renderingEngine = (renderingEngineName == null + ? null + : fs.getRenderingEngine(renderingEngineName)); } /** * @return Returns a list of mime types to allow the user to select from */ - public List getRenderingEngineTypeChoices() + public List getRenderingEngineChoices() { - return (List)Arrays.asList(new SelectItem[] + final FormsService fs = FormsService.getInstance(); + final List result = new LinkedList(); + for (RenderingEngine re : fs.getRenderingEngines()) { - new SelectItem(FreeMarkerRenderingEngine.class.getName(), - getRenderingEngineTypeName(FreeMarkerRenderingEngine.class)), - new SelectItem(XSLTRenderingEngine.class.getName(), - getRenderingEngineTypeName(XSLTRenderingEngine.class)), - new SelectItem(XSLFORenderingEngine.class.getName(), - getRenderingEngineTypeName(XSLFORenderingEngine.class)) - }); + result.add(new SelectItem(re.getName(), re.getName())); + } + return result; } /** @@ -479,17 +520,6 @@ public class CreateFormWizard extends BaseWizardBean return this.mimetypeChoices; } - private String getRenderingEngineTypeName(Class type) - { - return (FreeMarkerRenderingEngine.class.equals(type) - ? "FreeMarker" - : (XSLTRenderingEngine.class.equals(type) - ? "XSLT" - : (XSLFORenderingEngine.class.equals(type) - ? "XSL-FO" - : null))); - } - private FileUploadBean getFileUploadBean(final String id) { final FacesContext ctx = FacesContext.getCurrentInstance(); @@ -540,17 +570,17 @@ public class CreateFormWizard extends BaseWizardBean /** * @return Returns the schema file or null */ - public String getRenderingEngineFileName() + public String getRenderingEngineTemplateFileName() { - return this.getFileName(FILE_RENDERING_ENGINE); + return this.getFileName(FILE_RENDERING_ENGINE_TEMPLATE); } /** * @return Returns the rendering engine file or null */ - public File getRenderingEngineFile() + public File getRenderingEngineTemplateFile() { - return this.getFile(FILE_RENDERING_ENGINE); + return this.getFile(FILE_RENDERING_ENGINE_TEMPLATE); } /** @@ -618,6 +648,25 @@ public class CreateFormWizard extends BaseWizardBean ? this.getSchemaFileName().replaceAll("(.+)\\..*", "$1") : this.formName); } + /** + * @return Returns the output path for form instance data. + */ + public String getOutputPathPatternForFormInstanceData() + { + if (this.outputPathPatternForFormInstanceData == null) + { + this.outputPathPatternForFormInstanceData = "${formInstanceData.name}.xml"; + } + return this.outputPathPatternForFormInstanceData; + } + + /** + * @param outputPathPatternForFormInstanceData the output path for form instance data + */ + public void setOutputPathPatternForFormInstanceData(final String outputPathPatternForFormInstanceData) + { + this.outputPathPatternForFormInstanceData = outputPathPatternForFormInstanceData; + } /** * Sets the title for this form. @@ -659,16 +708,16 @@ public class CreateFormWizard extends BaseWizardBean public String getSummary() { final ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance()); - final String[] labels = new String[1 + this.renderingEngines.size()]; - final String[] values = new String[1 + this.renderingEngines.size()]; + final String[] labels = new String[1 + this.renderingEngineTemplates.size()]; + final String[] values = new String[1 + this.renderingEngineTemplates.size()]; labels[0] = "Schema File"; values[0] = this.getSchemaFileName(); - for (int i = 0; i < this.renderingEngines.size(); i++) + for (int i = 0; i < this.renderingEngineTemplates.size(); i++) { - final RenderingEngineData tomd = this.renderingEngines.get(i); - labels[1 + i] = ("RenderingEngine for " + tomd.getFileExtension() + - " mimetype " + tomd.getMimetype()); - values[1 + i] = tomd.getFileName(); + final RenderingEngineTemplateData retd = this.renderingEngineTemplates.get(i); + labels[1 + i] = ("RenderingEngine for " + retd.getOutputPathPatternForRendition() + + " mimetype " + retd.getMimetypeForRendition()); + values[1 + i] = retd.getFileName(); } return this.buildSummary(labels, values); @@ -681,7 +730,7 @@ public class CreateFormWizard extends BaseWizardBean /** * @param contentService The contentService to set. */ - public void setContentService(ContentService contentService) + public void setContentService(final ContentService contentService) { this.contentService = contentService; } @@ -689,7 +738,7 @@ public class CreateFormWizard extends BaseWizardBean /** * @param mimetypeService The mimetypeService to set. */ - public void setMimetypeService(MimetypeService mimetypeService) + public void setMimetypeService(final MimetypeService mimetypeService) { this.mimetypeService = mimetypeService; } diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java index d6641e09ca..88f07c9785 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java @@ -102,22 +102,12 @@ public class CreateWebContentWizard extends BaseContentWizard if (MimetypeMap.MIMETYPE_XML.equals(this.mimeType) && this.formName != null) { - if (logger.isDebugEnabled()) - logger.debug("generating form data renderer output for " + this.formName); final Form form = this.getForm(); - final FormsService fs = FormsService.getInstance(); final NodeRef formInstanceDataNodeRef = AVMNodeConverter.ToNodeRef(-1, this.createdPath); - final Map props = new HashMap(1, 1.0f); - props.put(WCMModel.PROP_PARENT_FORM, form.getNodeRef()); - props.put(WCMModel.PROP_PARENT_FORM_NAME, form.getName()); - this.nodeService.addAspect(formInstanceDataNodeRef, - WCMModel.ASPECT_FORM_INSTANCE_DATA, - props); - fs.generateRenditions(formInstanceDataNodeRef, - fs.parseXML(this.content), - form); + form.registerFormInstanceData(formInstanceDataNodeRef); + FormsService.getInstance().generateRenditions(formInstanceDataNodeRef); } // return the default outcome @@ -137,7 +127,23 @@ public class CreateWebContentWizard extends BaseContentWizard { // get the parent path of the location to save the content String path = this.avmBrowseBean.getCurrentPath(); - + if (MimetypeMap.MIMETYPE_XML.equals(this.mimeType) && this.formName != null) + { + final FormsService fs = FormsService.getInstance(); + final Document formInstanceData = (fileContent != null + ? fs.parseXML(fileContent) + : fs.parseXML(strContent)); + + path = this.getForm().getOutputPathForFormInstanceData(path, this.fileName, formInstanceData); + final String[] sb = AVMNodeConverter.SplitBase(path); + path = sb[0]; + this.fileName = sb[1]; + fs.makeAllDirectories(path); + } + + if (logger.isDebugEnabled()) + logger.debug("creating file " + this.fileName + " in " + path); + // put the content of the file into the AVM store if (fileContent != null) { @@ -193,16 +199,6 @@ public class CreateWebContentWizard extends BaseContentWizard // ------------------------------------------------------------------------------ // Bean Getters and Setters - - /** - * @param fileName The name of the file - */ - public void setFileName(String fileName) - { - super.setFileName(fileName != null && fileName.indexOf('.') == -1 - ? fileName + ".xml" - : fileName); - } /** * @return Returns the content from the edited form. @@ -219,7 +215,7 @@ public class CreateWebContentWizard extends BaseContentWizard { this.content = content; } - + /** * @return the available forms that can be created. */ diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java index 22f3301d10..690cb33c9d 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java @@ -60,7 +60,7 @@ import org.alfresco.web.bean.wizard.BaseWizardBean; import org.alfresco.web.bean.wizard.InviteUsersWizard.UserGroupRole; import org.alfresco.web.forms.Form; import org.alfresco.web.forms.FormsService; -import org.alfresco.web.forms.RenderingEngine; +import org.alfresco.web.forms.RenderingEngineTemplate; import org.alfresco.web.ui.common.component.UIListItem; import org.alfresco.web.ui.common.component.UISelectList; import org.alfresco.web.ui.wcm.WebResources; @@ -293,7 +293,7 @@ public class CreateWebsiteWizard extends BaseWizardBean for (PresentationTemplate template : form.getTemplates()) { props.clear(); - props.put(ContentModel.PROP_ENGINE, template.getRenderingEngine().getNodeRef()); + props.put(ContentModel.PROP_ENGINE, template.getRenderingEngineTemplate().getNodeRef()); NodeRef templateRef = this.nodeService.createNode(formRef, ContentModel.ASSOC_WEBFORMTEMPLATE, ContentModel.ASSOC_WEBFORMTEMPLATE, @@ -533,8 +533,7 @@ public class CreateWebsiteWizard extends BaseWizardBean UIListItem item = new UIListItem(); item.setValue(form); item.setLabel(form.getName()); - item.setDescription((String)this.nodeService.getProperty( - form.getNodeRef(), ContentModel.PROP_DESCRIPTION)); + item.setDescription(form.getDescription()); item.setImage(WebResources.IMAGE_WEBFORM_32); items.add(item); } @@ -1083,29 +1082,27 @@ public class CreateWebsiteWizard extends BaseWizardBean */ public static class PresentationTemplate { - private RenderingEngine engine; + private RenderingEngineTemplate ret; private String title; private String description; private String filenamePattern; - public PresentationTemplate(RenderingEngine engine, String filenamePattern) + public PresentationTemplate(RenderingEngineTemplate ret, String filenamePattern) { - this.engine = engine; + this.ret = ret; this.filenamePattern = filenamePattern; } - public RenderingEngine getRenderingEngine() + public RenderingEngineTemplate getRenderingEngineTemplate() { - return this.engine; + return this.ret; } public String getTitle() { if (this.title == null) { - this.title = (String)Repository.getServiceRegistry( - FacesContext.getCurrentInstance()).getNodeService().getProperty( - engine.getNodeRef(), ContentModel.PROP_NAME); + this.title = ret.getName(); } return this.title; } @@ -1114,9 +1111,7 @@ public class CreateWebsiteWizard extends BaseWizardBean { if (this.description == null) { - this.description = (String)Repository.getServiceRegistry( - FacesContext.getCurrentInstance()).getNodeService().getProperty( - engine.getNodeRef(), ContentModel.PROP_DESCRIPTION); + this.description = ret.getDescription(); } return this.description; } diff --git a/source/java/org/alfresco/web/bean/wcm/FormTemplatesDialog.java b/source/java/org/alfresco/web/bean/wcm/FormTemplatesDialog.java index 9474eaaa11..90a28e9d64 100644 --- a/source/java/org/alfresco/web/bean/wcm/FormTemplatesDialog.java +++ b/source/java/org/alfresco/web/bean/wcm/FormTemplatesDialog.java @@ -30,7 +30,7 @@ import org.alfresco.web.bean.dialog.BaseDialogBean; import org.alfresco.web.bean.wcm.CreateWebsiteWizard.FormWrapper; import org.alfresco.web.bean.wcm.CreateWebsiteWizard.PresentationTemplate; import org.alfresco.web.forms.Form; -import org.alfresco.web.forms.RenderingEngine; +import org.alfresco.web.forms.RenderingEngineTemplate; import org.alfresco.web.ui.common.component.UIListItem; import org.alfresco.web.ui.common.component.UISelectList; import org.alfresco.web.ui.wcm.WebResources; @@ -126,9 +126,9 @@ public class FormTemplatesDialog extends BaseDialogBean public List getTemplatesList() { Form form = getActionForm().getForm(); - List engines = form.getRenderingEngines(); + List engines = form.getRenderingEngineTemplates(); List items = new ArrayList(engines.size()); - for (RenderingEngine engine : engines) + for (RenderingEngineTemplate engine : engines) { PresentationTemplate wrapper = new PresentationTemplate(engine, null); UIListItem item = new UIListItem(); @@ -153,7 +153,7 @@ public class FormTemplatesDialog extends BaseDialogBean { PresentationTemplate template = (PresentationTemplate)this.templateList.get(index).getValue(); // clone the PresentationTemplate into one the user can modify - this.templates.add(new PresentationTemplate(template.getRenderingEngine(), template.getFilenamePattern())); + this.templates.add(new PresentationTemplate(template.getRenderingEngineTemplate(), template.getFilenamePattern())); } } diff --git a/source/java/org/alfresco/web/forms/AbstractRenderingEngine.java b/source/java/org/alfresco/web/forms/AbstractRenderingEngine.java index 8afa6a6452..d521049616 100644 --- a/source/java/org/alfresco/web/forms/AbstractRenderingEngine.java +++ b/source/java/org/alfresco/web/forms/AbstractRenderingEngine.java @@ -16,8 +16,6 @@ */ package org.alfresco.web.forms; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.faces.context.FacesContext; import org.alfresco.model.WCMModel; import org.alfresco.repo.avm.AVMRemote; @@ -41,51 +39,8 @@ public abstract class AbstractRenderingEngine protected static final String ALFRESCO_NS = "http://www.alfresco.org/alfresco"; protected static final String ALFRESCO_NS_PREFIX = "alfresco"; - private final NodeRef nodeRef; - protected final NodeService nodeService; - protected final ContentService contentService; - - protected AbstractRenderingEngine(final NodeRef nodeRef, - final NodeService nodeService, - final ContentService contentService) + protected AbstractRenderingEngine() { - this.nodeRef = nodeRef; - this.nodeService = nodeService; - this.contentService = contentService; - } - - /** - * Returns the node ref for the rendering engine template. - * - * @return the node ref for the rendering engine template. - */ - public NodeRef getNodeRef() - { - return this.nodeRef; - } - - /** - * Returns the file extension to use for generated assets. - * - * @return the file extension to use for generated assets. - */ - public String getFileExtensionForRendition() - { - return (String) - this.nodeService.getProperty(this.nodeRef, - WCMModel.PROP_FILE_EXTENSION_FOR_RENDITION); - } - - /** - * Returns the file extension to use for generated assets. - * - * @return the file extension to use for generated assets. - */ - public String getMimetypeForRendition() - { - return (String) - this.nodeService.getProperty(this.nodeRef, - WCMModel.PROP_MIMETYPE_FOR_RENDITION); } protected static AVMRemote getAVMRemote() @@ -101,48 +56,4 @@ public abstract class AbstractRenderingEngine { return new FormDataFunctions(AbstractRenderingEngine.getAVMRemote()); } - - /** - * Converts the provided path to an absolute path within the avm. - * - * @param parentAVMPath used as the parent path if the provided path - * is relative, otherwise used to extract the parent path portion up until - * the webapp directory. - * @param path a path relative to the parentAVMPath path, or if it is - * absolute, it is relative to the webapp used in the parentAVMPath. - * - * @return an absolute path within the avm using the paths provided. - */ - protected static String toAVMPath(final String parentAVMPath, final String path) - { - String parent = parentAVMPath; - if (path == null || - path.length() == 0 || - ".".equals(path) || - "./".equals(path)) - { - return parentAVMPath; - } - - if (path.charAt(0) == '/') - { - final Pattern p = Pattern.compile("([^:]+:/" + AVMConstants.DIR_APPBASE + - "/[^/]+/[^/]+).*"); - final Matcher m = p.matcher(parentAVMPath); - if (m.matches()) - { - parent = m.group(1); - } - } - else if (parentAVMPath.charAt(parentAVMPath.length() - 1) != '/') - { - parent = parent + '/'; - } - - final String result = parent + path; - LOGGER.debug("built full avmPath " + result + - " for parent " + parentAVMPath + - " and request path " + path); - return result; - } } \ No newline at end of file diff --git a/source/java/org/alfresco/web/forms/Form.java b/source/java/org/alfresco/web/forms/Form.java index 7f111a3d66..d2605b1c90 100644 --- a/source/java/org/alfresco/web/forms/Form.java +++ b/source/java/org/alfresco/web/forms/Form.java @@ -18,6 +18,8 @@ package org.alfresco.web.forms; import org.alfresco.service.cmr.repository.NodeRef; import org.w3c.dom.Document; +import org.xml.sax.SAXException; +import java.io.IOException; import java.io.Serializable; import java.net.URI; import java.util.List; @@ -31,16 +33,32 @@ public interface Form extends Serializable { - /** the name of the template, which must be unique within the FormsService */ + /** the name of the form, which must be unique within the FormsService */ public String getName(); + /** the description of the form */ + public String getDescription(); + /** the root tag to use within the schema */ - public String getRootTagName(); + public String getSchemaRootElementName(); /** the xml schema for this template type */ - public Document getSchema(); + public Document getSchema() + throws IOException, SAXException; - public NodeRef getNodeRef(); + /** + * provides the output path for the form instance data based on the + * configured output path pattern. + * + * @param parentAVMPath the parent avm path + * @param formInstanceDataFileName the file name provided by the user. + * @param formInstanceData the parsed xml content + * + * @return the path to use for writing the form instance data. + */ + public String getOutputPathForFormInstanceData(final String parentAVMPath, + final String formInstanceDataFileName, + final Document formInstanceData); //XXXarielb not used currently and not sure if it's necessary... // public void addInputMethod(final TemplateInputMethod in); @@ -53,10 +71,17 @@ public interface Form /** * adds an output method to this template type. */ - public void addRenderingEngine(RenderingEngine output); + public void addRenderingEngineTemplate(RenderingEngineTemplate output); /** * Provides the set of output methods for this template. */ - public List getRenderingEngines(); + public List getRenderingEngineTemplates(); + + + /** + * Associates properties with the form instance data registering it as + * generated by this form. + */ + public void registerFormInstanceData(final NodeRef formInstanceDataNodeRef); } diff --git a/source/java/org/alfresco/web/forms/FormDataFunctions.java b/source/java/org/alfresco/web/forms/FormDataFunctions.java index 915275debc..6ee11bb196 100644 --- a/source/java/org/alfresco/web/forms/FormDataFunctions.java +++ b/source/java/org/alfresco/web/forms/FormDataFunctions.java @@ -113,11 +113,11 @@ public class FormDataFunctions pv = this.avmRemote.getNodeProperty(-1, avmPath + '/' + entryName, - WCMModel.PROP_PARENT_RENDERING_ENGINE); + WCMModel.PROP_PARENT_RENDERING_ENGINE_TEMPLATE); if (pv != null) { - // it's generated by a transformer (not the xml file) + // it's generated by a rendering engine (it's not the xml file) continue; } diff --git a/source/java/org/alfresco/web/forms/FormImpl.java b/source/java/org/alfresco/web/forms/FormImpl.java index 1b6f79a439..2b0037040c 100644 --- a/source/java/org/alfresco/web/forms/FormImpl.java +++ b/source/java/org/alfresco/web/forms/FormImpl.java @@ -16,11 +16,28 @@ */ package org.alfresco.web.forms; +import freemarker.ext.dom.NodeModel; +import freemarker.template.SimpleDate; +import freemarker.template.SimpleHash; +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateHashModel; +import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; import java.io.*; import java.net.URI; +import java.io.Serializable; import java.util.*; import org.alfresco.model.ContentModel; +import org.alfresco.model.WCMModel; +import org.alfresco.service.cmr.repository.AssociationRef; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.TemplateService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.RegexQNamePattern; +import org.alfresco.web.bean.wcm.AVMConstants; import org.alfresco.web.forms.xforms.XFormsProcessor; import org.alfresco.web.app.servlet.DownloadContentServlet; import org.apache.commons.logging.Log; @@ -33,60 +50,116 @@ public class FormImpl { private static final Log LOGGER = LogFactory.getLog(FormImpl.class); - private transient Document schema; - private final NodeRef schemaNodeRef; - private final String name; - private final String rootTagName; - private final LinkedList renderingEngines = - new LinkedList(); + private final NodeRef folderNodeRef; + private final NodeService nodeService; + private final ContentService contentService; + private final TemplateService templateService; + private final static LinkedList PROCESSORS = new LinkedList(); - static { - PROCESSORS.add(new XFormsProcessor()); + FormImpl.PROCESSORS.add(new XFormsProcessor()); } - public FormImpl(final String name, - final NodeRef schemaNodeRef, - final String rootTagName) + public FormImpl(final NodeRef folderNodeRef, + final NodeService nodeService, + final ContentService contentService, + final TemplateService templateService) { - this.name = name; - this.schemaNodeRef = schemaNodeRef; - this.rootTagName = rootTagName; - } - - public String getName() - { - return this.name; + this.folderNodeRef = folderNodeRef; + this.nodeService = nodeService; + this.contentService = contentService; + this.templateService = templateService; } - public String getRootTagName() + public String getName() { - return this.rootTagName; + return (String) + this.nodeService.getProperty(this.folderNodeRef, + ContentModel.PROP_TITLE); + } + + public String getDescription() + { + return (String) + this.nodeService.getProperty(this.folderNodeRef, + ContentModel.PROP_DESCRIPTION); + } + + public String getOutputPathForFormInstanceData(final String parentAVMPath, + final String formInstanceDataFileName, + final Document formInstanceData) + { + final String outputPathPattern = (String) + this.nodeService.getProperty(this.folderNodeRef, + WCMModel.PROP_OUTPUT_PATH_PATTERN_FOR_FORM_INSTANCE_DATA); + + final TemplateHashModel formInstanceDataModel = new TemplateHashModel() + { + + private TemplateModel formInstanceDataModel; + + public TemplateModel get(final String key) + { + LOGGER.debug("looking up property " + key); + if ("xml".equals(key)) + { + try + { + if (formInstanceDataModel == null) + { + formInstanceDataModel = NodeModel.wrap(formInstanceData); + } + return formInstanceDataModel; + } + catch (Exception e) + { + LOGGER.error(e); + return null; + } + } + else if ("name".equals(key)) + { + return new SimpleScalar(formInstanceDataFileName); + } + return null; + } + + public boolean isEmpty() + { + return false; + } + }; + + final Map root = new HashMap(); + root.put("formInstanceData", formInstanceDataModel); + root.put("date", new SimpleDate(new Date(), SimpleDate.DATETIME)); + + String result = templateService.processTemplateString(null, + outputPathPattern, + new SimpleHash(root)); + result = AVMConstants.buildAbsoluteAVMPath(parentAVMPath, result); + LOGGER.debug("processed pattern " + outputPathPattern + " as " + result); + return result; + } + + public String getSchemaRootElementName() + { + return (String) + this.nodeService.getProperty(folderNodeRef, + WCMModel.PROP_XML_SCHEMA_ROOT_ELEMENT_NAME); } public Document getSchema() + throws IOException, + SAXException { - if (this.schema == null) - { - final FormsService ts = FormsService.getInstance(); - try - { - //XXXarielb maybe cloneNode instead? - return /* this.schema = */ ts.parseXML(this.schemaNodeRef); - } - catch (Exception e) - { - LOGGER.error(e); - } - } - return this.schema; - } - - public NodeRef getNodeRef() - { - return this.schemaNodeRef; + final FormsService ts = FormsService.getInstance(); + final NodeRef schemaNodeRef = (NodeRef) + this.nodeService.getProperty(folderNodeRef, + WCMModel.PROP_XML_SCHEMA); + return ts.parseXML(schemaNodeRef); } public List getFormProcessors() @@ -94,18 +167,57 @@ public class FormImpl return PROCESSORS; } - public void addRenderingEngine(final RenderingEngine output) + public void addRenderingEngineTemplate(final RenderingEngineTemplate ret) { - this.renderingEngines.add(output); +// this.renderingEngineTemplates.add(ret); + throw new UnsupportedOperationException(); } - public List getRenderingEngines() + public List getRenderingEngineTemplates() { - return this.renderingEngines; + final List result = new ArrayList(); + for (AssociationRef assoc : this.nodeService.getTargetAssocs(this.folderNodeRef, + WCMModel.ASSOC_RENDERING_ENGINE_TEMPLATES)) + { + final NodeRef retNodeRef = assoc.getTargetRef(); + for (ChildAssociationRef assoc2 : this.nodeService.getChildAssocs(retNodeRef, + WCMModel.ASSOC_RENDITION_PROPERTIES, + RegexQNamePattern.MATCH_ALL)) + { + final NodeRef renditionPropertiesNodeRef = assoc2.getChildRef(); + + final RenderingEngineTemplate ret = + new RenderingEngineTemplateImpl(retNodeRef, + renditionPropertiesNodeRef, + this.nodeService, + this.contentService, + this.templateService); + LOGGER.debug("loaded rendering engine template " + ret); + result.add(ret); + } + } + return result; + } + + public void registerFormInstanceData(final NodeRef formInstanceDataNodeRef) + { + final Map props = new HashMap(2, 1.0f); + props.put(WCMModel.PROP_PARENT_FORM, this.folderNodeRef); + props.put(WCMModel.PROP_PARENT_FORM_NAME, this.getName()); + this.nodeService.addAspect(formInstanceDataNodeRef, WCMModel.ASPECT_FORM_INSTANCE_DATA, props); } public int hashCode() { return this.getName().hashCode(); } + + public String toString() + { + return (this.getClass().getName() + "{" + + "name: " + this.getName() + "," + + "schemaRootElementName: " + this.getSchemaRootElementName() + "," + + "renderingEngineTemplates: " + this.getRenderingEngineTemplates() + + "}"); + } } \ No newline at end of file diff --git a/source/java/org/alfresco/web/forms/FormsService.java b/source/java/org/alfresco/web/forms/FormsService.java index d6f97c7977..f66e91d68f 100644 --- a/source/java/org/alfresco/web/forms/FormsService.java +++ b/source/java/org/alfresco/web/forms/FormsService.java @@ -26,12 +26,12 @@ import java.io.OutputStream; import java.io.Serializable; import java.io.StringWriter; import java.io.Writer; -import java.lang.reflect.Constructor; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Stack; import javax.faces.context.FacesContext; import javax.xml.parsers.DocumentBuilder; @@ -57,6 +57,7 @@ import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.TemplateService; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.ResultSetRow; import org.alfresco.service.cmr.search.SearchParameters; @@ -89,6 +90,13 @@ public final class FormsService /** internal storage of forms, keyed by the form name */ private HashMap forms = new HashMap(); + + private static final RenderingEngine[] RENDERING_ENGINES = new RenderingEngine[] + { + new FreeMarkerRenderingEngine(), + new XSLTRenderingEngine(), + new XSLFORenderingEngine() + }; private final ContentService contentService; private final NodeService nodeService; @@ -97,6 +105,7 @@ public final class FormsService private final NamespaceService namespaceService; private final SearchService searchService; private final AVMService avmService; + private final TemplateService templateService; private NodeRef contentFormsNodeRef; @@ -107,7 +116,8 @@ public final class FormsService final DictionaryService dictionaryService, final NamespaceService namespaceService, final SearchService searchService, - final AVMService avmService) + final AVMService avmService, + final TemplateService templateService) { this.contentService = contentService; this.nodeService = nodeService; @@ -116,6 +126,7 @@ public final class FormsService this.namespaceService = namespaceService; this.searchService = searchService; this.avmService = avmService; + this.templateService = templateService; if (INSTANCE == null) INSTANCE = this; } @@ -126,6 +137,45 @@ public final class FormsService return FormsService.INSTANCE; } + /** + * Provides all registered rendering engines. + */ + public RenderingEngine[] getRenderingEngines() + { + return FormsService.RENDERING_ENGINES; + } + + /** + * Returns the rendering engine with the given name. + * + * @param name the name of the rendering engine. + * + * @return the rendering engine or null if not found. + */ + public RenderingEngine getRenderingEngine(final String name) + { + for (RenderingEngine re : this.getRenderingEngines()) + { + if (re.getName().equals(name)) + { + return re; + } + } + return null; + } + + public RenderingEngine guessRenderingEngine(final String fileName) + { + for (RenderingEngine re : this.getRenderingEngines()) + { + if (fileName.endsWith(re.getDefaultTemplateFileExtension())) + { + return re; + } + } + return null; + } + /** * @return the cached reference to the WCM Content Forms folder */ @@ -169,7 +219,7 @@ public final class FormsService for (ResultSetRow row : rs) { final NodeRef nodeRef = row.getNodeRef(); - result.add(this.newForm(nodeRef)); + result.add(this.getForm(nodeRef)); } return result; } @@ -202,7 +252,7 @@ public final class FormsService } if (result == null && LOGGER.isDebugEnabled()) LOGGER.debug("unable to find tempalte type " + name); - return result != null ? this.newForm(result) : null; + return result != null ? this.getForm(result) : null; } /** @@ -213,114 +263,70 @@ public final class FormsService * @return the form for the given node ref. */ public Form getForm(final NodeRef nodeRef) - { - return this.newForm(nodeRef); - } - - /** - * instantiate a form. for now this will always generate the - * xforms implementation, but will at some point be configurable such that - * the form processor type implementation can be configured for the system, - * or specified in the gui. - */ - private Form newForm(final NodeRef schemaNodeRef) { if (LOGGER.isDebugEnabled()) - LOGGER.debug("creating form for " + schemaNodeRef); - final String title = (String) - this.nodeService.getProperty(schemaNodeRef, ContentModel.PROP_TITLE); + LOGGER.debug("loading form for " + nodeRef); + final Form result = new FormImpl(nodeRef, + this.nodeService, + this.contentService, + this.templateService); if (LOGGER.isDebugEnabled()) - LOGGER.debug("title is " + title); - final String schemaRootTagName = (String) - this.nodeService.getProperty(schemaNodeRef, WCMModel.PROP_SCHEMA_ROOT_ELEMENT_NAME); - if (LOGGER.isDebugEnabled()) - LOGGER.debug("root tag name is " + schemaRootTagName); - final Form tt = new FormImpl(title, schemaNodeRef, schemaRootTagName); - for (AssociationRef assoc : this.nodeService.getTargetAssocs(schemaNodeRef, - WCMModel.ASSOC_RENDERING_ENGINES)) - { - final NodeRef tomNodeRef = assoc.getTargetRef(); - try - { - final Class formDataRendererType = - Class.forName((String)this.nodeService.getProperty(tomNodeRef, - WCMModel.PROP_RENDERING_ENGINE_TYPE)); - - final Constructor c = formDataRendererType.getConstructor(NodeRef.class, NodeService.class, ContentService.class); - final RenderingEngine tom = (RenderingEngine) - c.newInstance(tomNodeRef, this.nodeService, this.contentService); - if (LOGGER.isDebugEnabled()) - { - LOGGER.debug("loaded form data renderer type " + tom.getClass().getName() + - " for extension " + tom.getFileExtensionForRendition() + - ", " + tomNodeRef); - } - tt.addRenderingEngine(tom); - } - catch (Exception e) - { - throw new AlfrescoRuntimeException(e.getMessage(), e); - } - } - return tt; + LOGGER.debug("loaded form " + result); + return result; } /** * Generates renditions for the provided formInstanceData. * * @param formInstanceDataNodeRef the noderef containing the form instance data - * @param formInstanceData the parsed contents of the form. - * @param form the form to use when generating renditions. */ - public void generateRenditions(final NodeRef formInstanceDataNodeRef, - final Document formInstanceData, - final Form form) + public void generateRenditions(final NodeRef formInstanceDataNodeRef) throws IOException, + SAXException, RenderingEngine.RenderingException { - final String formInstanceDataFileName = (String) - nodeService.getProperty(formInstanceDataNodeRef, ContentModel.PROP_NAME); - final String formInstanceDataAvmPath = AVMNodeConverter.ToAVMVersionPath(formInstanceDataNodeRef).getSecond(); - final String parentPath = AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[0]; + final Form form = + this.getForm((NodeRef)this.nodeService.getProperty(formInstanceDataNodeRef, + WCMModel.PROP_PARENT_FORM)); + final Document formInstanceData = this.parseXML(formInstanceDataNodeRef); - for (RenderingEngine re : form.getRenderingEngines()) + final String formInstanceDataFileName = (String) + this.nodeService.getProperty(formInstanceDataNodeRef, ContentModel.PROP_NAME); + final String formInstanceDataAvmPath = + AVMNodeConverter.ToAVMVersionPath(formInstanceDataNodeRef).getSecond(); + LOGGER.debug("generating renditions for " + formInstanceDataAvmPath); + + for (RenderingEngineTemplate ret : form.getRenderingEngineTemplates()) { // get the node ref of the node that will contain the content - final String renditionFileName = - (this.stripExtension(formInstanceDataFileName) + - "." + re.getFileExtensionForRendition()); - final OutputStream out = this.avmService.createFile(parentPath, renditionFileName); - final String renditionAvmPath = parentPath + '/' + renditionFileName; + final String renditionAvmPath = + this.getOutputAvmPathForRendition(ret, formInstanceDataNodeRef); + final String parentAVMPath = AVMNodeConverter.SplitBase(renditionAvmPath)[0]; + this.makeAllDirectories(parentAVMPath); + final OutputStream out = this.avmService.createFile(parentAVMPath, + AVMNodeConverter.SplitBase(renditionAvmPath)[1]); if (LOGGER.isDebugEnabled()) LOGGER.debug("Created file node for file: " + renditionAvmPath); final HashMap parameters = - this.getRenderingEngineParameters(formInstanceDataFileName, - renditionFileName, - parentPath); - re.render(formInstanceData, parameters, out); + this.getRenderingEngineParameters(formInstanceDataAvmPath, + renditionAvmPath); + ret.getRenderingEngine().render(formInstanceData, ret, parameters, out); out.close(); final NodeRef renditionNodeRef = - AVMNodeConverter.ToNodeRef(-1, parentPath + '/' + renditionFileName); + AVMNodeConverter.ToNodeRef(-1, renditionAvmPath); - Map props = new HashMap(2, 1.0f); - props.put(WCMModel.PROP_PARENT_FORM, form.getNodeRef()); - props.put(WCMModel.PROP_PARENT_FORM_NAME, form.getName()); - nodeService.addAspect(renditionNodeRef, WCMModel.ASPECT_FORM_INSTANCE_DATA, props); + form.registerFormInstanceData(renditionNodeRef); + ret.registerRendition(renditionNodeRef, formInstanceDataNodeRef); - props = new HashMap(2, 1.0f); - props.put(WCMModel.PROP_PARENT_RENDERING_ENGINE, re.getNodeRef()); - props.put(WCMModel.PROP_PRIMARY_FORM_INSTANCE_DATA, formInstanceDataNodeRef); - nodeService.addAspect(renditionNodeRef, WCMModel.ASPECT_RENDITION, props); - - props = new HashMap(1, 1.0f); - props.put(ContentModel.PROP_TITLE, renditionFileName); + Map props = new HashMap(1, 1.0f); + props.put(ContentModel.PROP_TITLE, AVMNodeConverter.SplitBase(renditionAvmPath)[1]); nodeService.addAspect(renditionNodeRef, ContentModel.ASPECT_TITLED, props); if (LOGGER.isDebugEnabled()) - LOGGER.debug("generated " + renditionFileName + " using " + re); + LOGGER.debug("generated " + renditionAvmPath + " using " + ret); } } @@ -346,56 +352,100 @@ public final class FormsService // other parameter values passed to rendering engine final String formInstanceDataAvmPath = AVMNodeConverter.ToAVMVersionPath(formInstanceDataNodeRef).getSecond(); - final String parentPath = AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[0]; + LOGGER.debug("regenerating renditions for " + formInstanceDataAvmPath); - for (RenderingEngine re : form.getRenderingEngines()) + for (RenderingEngineTemplate ret : form.getRenderingEngineTemplates()) { - final String renditionFileName = - (this.stripExtension(formInstanceDataFileName) + "." + - re.getFileExtensionForRendition()); + final String renditionAvmPath = + this.getOutputAvmPathForRendition(ret, formInstanceDataNodeRef); if (LOGGER.isDebugEnabled()) LOGGER.debug("regenerating file node for : " + formInstanceDataFileName + " (" + formInstanceDataNodeRef.toString() + - ") to " + parentPath + - "/" + renditionFileName); + ") to " + renditionAvmPath); // get a writer for the content and put the file OutputStream out = null; try { - out = this.avmService.getFileOutputStream(parentPath + "/" + renditionFileName); + out = this.avmService.getFileOutputStream(renditionAvmPath); } catch (AVMNotFoundException e) { - out = this.avmService.createFile(parentPath, renditionFileName); + out = this.avmService.createFile(AVMNodeConverter.SplitBase(renditionAvmPath)[0], + AVMNodeConverter.SplitBase(renditionAvmPath)[1]); } final HashMap parameters = - this.getRenderingEngineParameters(formInstanceDataFileName, - renditionFileName, - parentPath); - re.render(formInstanceData, parameters, out); + this.getRenderingEngineParameters(formInstanceDataAvmPath, renditionAvmPath); + ret.getRenderingEngine().render(formInstanceData, ret, parameters, out); out.close(); if (LOGGER.isDebugEnabled()) - LOGGER.debug("generated " + renditionFileName + " using " + re); + LOGGER.debug("generated " + renditionAvmPath + " using " + ret); } } - private static HashMap getRenderingEngineParameters(final String formInstanceDataFileName, - final String renditionFileName, - final String parentAvmPath) + private static String getOutputAvmPathForRendition(final RenderingEngineTemplate ret, + final NodeRef formInstanceDataNodeRef) + { + final String formInstanceDataAvmPath = + AVMNodeConverter.ToAVMVersionPath(formInstanceDataNodeRef).getSecond(); + String formInstanceDataFileName = AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[1]; + formInstanceDataFileName = FormsService.stripExtension(formInstanceDataFileName); + String result = ret.getOutputPathForRendition(formInstanceDataNodeRef); + if (result != null && result.charAt(0) == '/') + { + + } + return result; + } + + private static HashMap getRenderingEngineParameters(final String formInstanceDataAvmPath, + final String renditionAvmPath) { final HashMap parameters = new HashMap(); - parameters.put("avm_sandbox_url", AVMConstants.buildAVMStoreUrl(parentAvmPath)); - parameters.put("form_instance_data_file_name", formInstanceDataFileName); - parameters.put("rendition_file_name", renditionFileName); - parameters.put("parent_path", parentAvmPath); + parameters.put("avm_sandbox_url", AVMConstants.buildAVMStoreUrl(formInstanceDataAvmPath)); + parameters.put("form_instance_data_file_name", AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[1]); + parameters.put("rendition_file_name", AVMNodeConverter.SplitBase(renditionAvmPath)[1]); + parameters.put("parent_path", AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[0]); final FacesContext fc = FacesContext.getCurrentInstance(); parameters.put("request_context_path", fc.getExternalContext().getRequestContextPath()); return parameters; } + + // XXXarielb relocate + public void makeAllDirectories(final String avmDirectoryPath) + { + LOGGER.debug("mkdir -p " + avmDirectoryPath); + String s = avmDirectoryPath; + final Stack dirNames = new Stack(); + while (s != null) + { + try + { + if (this.avmService.lookup(-1, s) != null) + { + LOGGER.debug("path " + s + " exists"); + break; + } + } + catch (AVMNotFoundException avmfe) + { + } + final String[] sb = AVMNodeConverter.SplitBase(s); + s = sb[0]; + LOGGER.debug("pushing " + sb[1]); + dirNames.push(sb); + } + + while (!dirNames.isEmpty()) + { + final String[] sb = dirNames.pop(); + LOGGER.debug("creating " + sb[1] + " in " + sb[0]); + this.avmService.createDirectory(sb[0], sb[1]); + } + } /** utility function for creating a document */ public Document newDocument() diff --git a/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java b/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java index 567ce7ae0c..61d586c2c9 100644 --- a/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java +++ b/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java @@ -29,6 +29,7 @@ import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.web.bean.wcm.AVMConstants; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chiba.xml.util.DOMUtil; @@ -48,11 +49,19 @@ public class FreeMarkerRenderingEngine private static final Log LOGGER = LogFactory.getLog(FreeMarkerRenderingEngine.class); - public FreeMarkerRenderingEngine(final NodeRef nodeRef, - final NodeService nodeService, - final ContentService contentService) + public FreeMarkerRenderingEngine() { - super(nodeRef, nodeService, contentService); + super(); + } + + public String getName() + { + return "FreeMarker"; + } + + public String getDefaultTemplateFileExtension() + { + return "ftl"; } /** @@ -62,25 +71,26 @@ public class FreeMarkerRenderingEngine * all parameters and all extension functions. */ public void render(final Document xmlContent, + final RenderingEngineTemplate ret, final Map parameters, final OutputStream out) throws IOException, RenderingEngine.RenderingException { - final ContentReader contentReader = - this.contentService.getReader(this.getNodeRef(), ContentModel.TYPE_CONTENT); - final Reader reader = new InputStreamReader(contentReader.getContentInputStream()); + final Configuration cfg = new Configuration(); cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); - - final Template t = new Template("freemarker_template", reader, cfg); + + final Template t = new Template("freemarker_template", + new InputStreamReader(ret.getInputStream()), + cfg); // wrap the xml instance in a model final TemplateHashModel instanceDataModel = NodeModel.wrap(xmlContent); // build models for each of the extension functions final HashMap methodModels = - new HashMap(3, 1.0f); + new HashMap(3, 1.0f); methodModels.put("parseXMLDocument", new TemplateMethodModel() { public Object exec(final List args) @@ -89,8 +99,8 @@ public class FreeMarkerRenderingEngine try { final FormDataFunctions ef = FreeMarkerRenderingEngine.getFormDataFunctions(); - final String path = FreeMarkerRenderingEngine.toAVMPath(parameters.get("parent_path"), - (String)args.get(0)); + final String path = AVMConstants.buildAbsoluteAVMPath(parameters.get("parent_path"), + (String)args.get(0)); final Document d = ef.parseXMLDocument(path); return d != null ? d.getDocumentElement() : null; } @@ -110,8 +120,8 @@ public class FreeMarkerRenderingEngine { final FormDataFunctions ef = FreeMarkerRenderingEngine.getFormDataFunctions(); final String path = - FreeMarkerRenderingEngine.toAVMPath(parameters.get("parent_path"), - args.size() == 1 ? "" : (String)args.get(1)); + AVMConstants.buildAbsoluteAVMPath(parameters.get("parent_path"), + args.size() == 1 ? "" : (String)args.get(1)); final Map resultMap = ef.parseXMLDocuments((String)args.get(0), path); LOGGER.debug("received " + resultMap.size() + " documents in " + path); @@ -156,8 +166,8 @@ public class FreeMarkerRenderingEngine { try { - return FreeMarkerRenderingEngine.toAVMPath(parameters.get("parent_path"), - (String)args.get(0)); + return AVMConstants.buildAbsoluteAVMPath(parameters.get("parent_path"), + (String)args.get(0)); } catch (Exception e) { diff --git a/source/java/org/alfresco/web/forms/RenderingEngine.java b/source/java/org/alfresco/web/forms/RenderingEngine.java index 083fc7fb30..922fa1d901 100644 --- a/source/java/org/alfresco/web/forms/RenderingEngine.java +++ b/source/java/org/alfresco/web/forms/RenderingEngine.java @@ -50,42 +50,35 @@ public interface RenderingEngine ///////////////////////////////////////////////////////////////////////////// - /** - * XXXarielb this shouldn't be in the interface... i'll figure out a - * different id scheme once i make rendering engines configurable. + /** + * Returns the rendering engines name. * - * the noderef associated with this output method + * @return the name of the rendering engine. */ - public NodeRef getNodeRef(); + public String getName(); + + + /** + * Returns the default file extension for rendering engine templates for this + * rendering engine. + * + * @return the default file extension for rendering engine templates for this + * rendering engine. + */ + public String getDefaultTemplateFileExtension(); /** * Renders the xml data in to a presentation format. * - * @param formInstanceData the xml content to serialize + * @param formInstanceData the xml content to serialize. + * @param ret the rendering engine template * @param form the form that collected the xml content. * @param parameters the set of parameters to the rendering engine * @param out the output stream to serialize to. */ public void render(final Document formInstanceData, + final RenderingEngineTemplate ret, final Map parameters, final OutputStream out) throws IOException, RenderingException; - - /** - * Returns the file extension to use when generating content for this - * output method. - * - * @return the file extension to use when generating content for this - * output method, such as html, xml, pdf. - */ - public String getFileExtensionForRendition(); - - /** - * Returns the mimetype to use when generating content for this - * output method. - * - * @return the mimetype to use when generating content for this - * output method, such as text/html, text/xml, application/pdf. - */ - public String getMimetypeForRendition(); } diff --git a/source/java/org/alfresco/web/forms/RenderingEngineTemplate.java b/source/java/org/alfresco/web/forms/RenderingEngineTemplate.java new file mode 100644 index 0000000000..80122fc9c6 --- /dev/null +++ b/source/java/org/alfresco/web/forms/RenderingEngineTemplate.java @@ -0,0 +1,81 @@ +/* + * 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. + */ +package org.alfresco.web.forms; + +import org.alfresco.service.cmr.repository.NodeRef; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.Map; +import org.w3c.dom.Document; + +/** + * Describes a template that is used for rendering form instance data. + * + * @author Ariel Backenroth + */ +public interface RenderingEngineTemplate + extends Serializable +{ + /** the name of the form, which must be unique within the FormsService */ + public String getName(); + + /** the description of the form */ + public String getDescription(); + + /** + * Provides the rendering engine to use to process this template. + * + * @return the rendering engine to use to process this template. + */ + public RenderingEngine getRenderingEngine(); + + /** + * Provides the noderef for this template. + * + * @return the noderef for this template. + * @deprecated i'd rather not expose this + */ + public NodeRef getNodeRef(); + + /** + * Provides an input stream to the rendering engine template. + * + * @return the input stream to the rendering engine template. + */ + public InputStream getInputStream() + throws IOException; + + /** + * Returns the output path for the rendition. + * + * @return the output path for the rendition. + */ + public String getOutputPathForRendition(final NodeRef formInstanceDataNodeRef); + + /** + * Returns the mimetype to use when generating content for this + * output method. + * + * @return the mimetype to use when generating content for this + * output method, such as text/html, text/xml, application/pdf. + */ + public String getMimetypeForRendition(); + + public void registerRendition(final NodeRef rendition, final NodeRef primaryFormInstanceData); +} diff --git a/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java b/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java new file mode 100644 index 0000000000..a0ce41414c --- /dev/null +++ b/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java @@ -0,0 +1,213 @@ +/* + * 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. + */ +package org.alfresco.web.forms; + +import freemarker.ext.dom.NodeModel; +import freemarker.template.SimpleDate; +import freemarker.template.SimpleHash; +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateHashModel; +import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import org.alfresco.model.ContentModel; +import org.alfresco.model.WCMModel; +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.TemplateService; +import org.alfresco.service.namespace.QName; +import org.alfresco.web.bean.wcm.AVMConstants; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +/** + * Implementation of a rendering engine template + */ +public class RenderingEngineTemplateImpl + implements RenderingEngineTemplate +{ + private static final Log LOGGER = LogFactory.getLog(RenderingEngineTemplateImpl.class); + + private final NodeRef nodeRef; + private final NodeRef renditionPropertiesNodeRef; + private final NodeService nodeService; + private final ContentService contentService; + private final TemplateService templateService; + + protected RenderingEngineTemplateImpl(final NodeRef nodeRef, + final NodeRef renditionPropertiesNodeRef, + final NodeService nodeService, + final ContentService contentService, + final TemplateService templateService) + { + this.nodeRef = nodeRef; + this.renditionPropertiesNodeRef = renditionPropertiesNodeRef; + this.nodeService = nodeService; + this.contentService = contentService; + this.templateService = templateService; + } + + public String getName() + { + return (String) + this.nodeService.getProperty(this.nodeRef, + ContentModel.PROP_TITLE); + } + + public String getDescription() + { + return (String) + this.nodeService.getProperty(this.nodeRef, + ContentModel.PROP_DESCRIPTION); + } + + public NodeRef getNodeRef() + { + return this.nodeRef; + } + + /** + * Provides an input stream to the rendering engine template. + * + * @return the input stream to the rendering engine template. + */ + public InputStream getInputStream() + throws IOException + { + final ContentReader contentReader = + this.contentService.getReader(this.nodeRef, ContentModel.TYPE_CONTENT); + return contentReader.getContentInputStream(); + } + + /** + * Provides the rendering engine to use when processing this template. + * + * @return the rendering engine to use when processing this template. + */ + public RenderingEngine getRenderingEngine() + { + final String renderingEngineName = (String) + this.nodeService.getProperty(this.nodeRef, + WCMModel.PROP_PARENT_RENDERING_ENGINE_NAME); + final FormsService fs = FormsService.getInstance(); + return fs.getRenderingEngine(renderingEngineName); + } + + /** + * Returns the output path to use for renditions. + * + * @return the output path to use for renditions. + */ + public String getOutputPathForRendition(final NodeRef formInstanceDataNodeRef) + { + final String outputPathPattern = (String) + this.nodeService.getProperty(this.renditionPropertiesNodeRef, + WCMModel.PROP_OUTPUT_PATH_PATTERN_FOR_RENDITION); + final String formInstanceDataAVMPath = + AVMNodeConverter.ToAVMVersionPath(formInstanceDataNodeRef).getSecond(); + + final TemplateHashModel formInstanceDataModel = new TemplateHashModel() + { + + private TemplateModel formInstanceDataModel; + + public TemplateModel get(final String key) + { + LOGGER.debug("looking up property " + key); + if ("xml".equals(key)) + { + try + { + if (formInstanceDataModel == null) + { + final FormsService fs = FormsService.getInstance(); + final Document formInstanceData = fs.parseXML(formInstanceDataNodeRef); + formInstanceDataModel = NodeModel.wrap(formInstanceData); + } + return formInstanceDataModel; + } + catch (Exception e) + { + LOGGER.error(e); + return null; + } + } + else + { + final Map properties = + nodeService.getProperties(formInstanceDataNodeRef); + for (QName qname : properties.keySet()) + { + if (qname.getLocalName().equals(key)) + { + return new SimpleScalar((String)properties.get(qname)); + } + } + } + return null; + } + + public boolean isEmpty() + { + return false; + } + }; + + final Map root = new HashMap(); + root.put("formInstanceData", formInstanceDataModel); + root.put("date", new SimpleDate(new Date(), SimpleDate.DATETIME)); + + String result = templateService.processTemplateString(null, + outputPathPattern, + new SimpleHash(root)); + final String parentAVMPath = AVMNodeConverter.SplitBase(formInstanceDataAVMPath)[0]; + result = AVMConstants.buildAbsoluteAVMPath(parentAVMPath, result); + LOGGER.debug("processed pattern " + outputPathPattern + " as " + result); + return result; + } + + /** + * Returns the mime type to use for generated assets. + * + * @return the mime type to use for generated assets. + */ + public String getMimetypeForRendition() + { + return (String) + this.nodeService.getProperty(this.renditionPropertiesNodeRef, + WCMModel.PROP_MIMETYPE_FOR_RENDITION); + } + + public void registerRendition(final NodeRef renditionNodeRef, + final NodeRef primaryFormInstanceDataNodeRef) + { + final Map props = new HashMap(2, 1.0f); + props.put(WCMModel.PROP_PARENT_RENDERING_ENGINE_TEMPLATE, this.nodeRef); + props.put(WCMModel.PROP_PRIMARY_FORM_INSTANCE_DATA, primaryFormInstanceDataNodeRef); + this.nodeService.addAspect(renditionNodeRef, WCMModel.ASPECT_RENDITION, props); + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java b/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java index dded5102b5..ff19168eeb 100644 --- a/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java +++ b/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java @@ -49,14 +49,23 @@ public class XSLFORenderingEngine private static final Log LOGGER = LogFactory.getLog(XSLFORenderingEngine.class); - public XSLFORenderingEngine(final NodeRef nodeRef, - final NodeService nodeService, - final ContentService contentService) + public XSLFORenderingEngine() { - super(nodeRef, nodeService, contentService); + super(); + } + + public String getName() + { + return "XSL-FO"; + } + + public String getDefaultTemplateFileExtension() + { + return "fo"; } public void render(final Document xmlContent, + final RenderingEngineTemplate ret, final Map parameters, final OutputStream out) throws IOException, @@ -67,7 +76,7 @@ public class XSLFORenderingEngine { final FopFactory fopFactory = FopFactory.newInstance(); final FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); - final Fop fop = fopFactory.newFop(this.getMimetypeForRendition(), + final Fop fop = fopFactory.newFop(ret.getMimetypeForRendition(), foUserAgent, out); // Resulting SAX events (the generated FO) must be piped through to FOP @@ -79,7 +88,6 @@ public class XSLFORenderingEngine throw new RenderingEngine.RenderingException(fope); } - super.render(new DOMSource(xmlContent), parameters, result); - + super.render(new DOMSource(xmlContent), ret, parameters, result); } } \ No newline at end of file diff --git a/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java b/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java index f08f902370..11a07dbb22 100644 --- a/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java +++ b/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java @@ -35,6 +35,7 @@ import javax.xml.transform.stream.StreamSource; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.web.bean.wcm.AVMConstants; import org.alfresco.web.forms.FormsService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -59,18 +60,26 @@ public class XSLTRenderingEngine private static final Log LOGGER = LogFactory.getLog(XSLTRenderingEngine.class); - public XSLTRenderingEngine(final NodeRef nodeRef, - final NodeService nodeService, - final ContentService contentService) + public XSLTRenderingEngine() { - super(nodeRef, nodeService, contentService); + super(); + } + + public String getName() + { + return "XSLT"; + } + + public String getDefaultTemplateFileExtension() + { + return "xsl"; } protected static String toAVMPath(final ExpressionContext ec, String path) throws TransformerException { final XObject o = ec.getVariableOrParam(new QName(ALFRESCO_NS, ALFRESCO_NS_PREFIX, "parent_path")); - return o == null ? null : XSLTRenderingEngine.toAVMPath(o.toString(), path); + return o == null ? null : AVMConstants.buildAbsoluteAVMPath(o.toString(), path); } /** @@ -276,15 +285,17 @@ public class XSLTRenderingEngine } public void render(final Document formInstanceData, + final RenderingEngineTemplate ret, final Map parameters, final OutputStream out) throws IOException, RenderingEngine.RenderingException { - this.render(new DOMSource(formInstanceData), parameters, new StreamResult(out)); + this.render(new DOMSource(formInstanceData), ret, parameters, new StreamResult(out)); } protected void render(final Source formInstanceDataSource, + final RenderingEngineTemplate ret, final Map parameters, final Result result) throws IOException, @@ -296,7 +307,7 @@ public class XSLTRenderingEngine Document xslTemplate = null; try { - xslTemplate = ts.parseXML(this.getNodeRef()); + xslTemplate = ts.parseXML(ret.getInputStream()); } catch (final SAXException sax) { diff --git a/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java b/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java index 5dadbc5069..6a14f69372 100644 --- a/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java +++ b/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java @@ -1175,15 +1175,6 @@ public class SchemaFormBuilder pathToRoot, relative, checkIfExtension); - - Element realModel = modelSection; - if (relative) - { - //modelSection: find the last element put in the modelSection = bind - realModel = DOMUtil.getLastChildElement(modelSection); - } - - this.endFormGroup(groupElement, controlType, o, realModel); } private void addComplexTypeChildren(final Document xForm, @@ -2265,18 +2256,18 @@ public class SchemaFormBuilder bindElement = this.startBindElement(bindElement, schema, controlType, owner, pathToRoot, o); // add a group if a repeat ! - if (owner instanceof XSElementDeclaration && o.maximum != 1) - { - Element groupElement = this.createGroup(xForm, - modelSection, - formSection, - (XSElementDeclaration) owner); - //set content - Element groupWrapper = groupElement; - if (groupElement != modelSection) - groupWrapper = this.wrapper.createGroupContentWrapper(groupElement); - formSection = groupWrapper; - } +// if (owner instanceof XSElementDeclaration && o.maximum != 1) +// { +// Element groupElement = this.createGroup(xForm, +// modelSection, +// formSection, +// (XSElementDeclaration) owner); +// //set content +// Element groupWrapper = groupElement; +// if (groupElement != modelSection) +// groupWrapper = this.wrapper.createGroupContentWrapper(groupElement); +// formSection = groupWrapper; +// } //eventual repeat final Element repeatSection = this.addRepeatIfNecessary(xForm, @@ -3303,18 +3294,6 @@ public class SchemaFormBuilder { } - /** - * __UNDOCUMENTED__ - * - * @param groupElement __UNDOCUMENTED__ - */ - public void endFormGroup(final Element groupElement, - final XSTypeDefinition controlType, - final Occurs o, - final Element modelSection) - { - } - /** * This method is invoked after an xforms:bind element is created for the specified SimpleType. * The implementation is responsible for setting setting any/all bind attributes diff --git a/source/java/org/alfresco/web/forms/xforms/XFormsBean.java b/source/java/org/alfresco/web/forms/xforms/XFormsBean.java index a74e5d0e22..610a146f75 100644 --- a/source/java/org/alfresco/web/forms/xforms/XFormsBean.java +++ b/source/java/org/alfresco/web/forms/xforms/XFormsBean.java @@ -53,6 +53,7 @@ import org.w3c.dom.ls.*; import org.w3c.dom.events.Event; import org.w3c.dom.events.EventListener; import org.w3c.dom.events.EventTarget; +import org.xml.sax.SAXException; /** * Bean for interacting with the chiba processor from the ui using ajax requests. @@ -151,6 +152,14 @@ public class XFormsBean { LOGGER.error(fbe); } + catch (IOException ioe) + { + LOGGER.error(ioe); + } + catch (SAXException saxe) + { + LOGGER.error(saxe); + } } /** @@ -348,7 +357,9 @@ public class XFormsBean final Form tt, final String cwdAvmPath, final HttpServletRequest request) - throws FormBuilderException + throws FormBuilderException, + IOException, + SAXException { final Document schemaDocument = tt.getSchema(); this.rewriteInlineURIs(schemaDocument, cwdAvmPath); @@ -365,7 +376,7 @@ public class XFormsBean LOGGER.debug("building xform for schema " + tt.getName()); final Document result = builder.buildForm(xmlContent, schemaDocument, - tt.getRootTagName()); + tt.getSchemaRootElementName()); LOGGER.debug("generated xform: " + result); // LOGGER.debug(ts.writeXMLToString(result)); return result; diff --git a/source/web/jsp/wcm/create-form-wizard/configure-rendering-engines.jsp b/source/web/jsp/wcm/create-form-wizard/configure-rendering-engines.jsp index 0ca938b285..da6f8db455 100644 --- a/source/web/jsp/wcm/create-form-wizard/configure-rendering-engines.jsp +++ b/source/web/jsp/wcm/create-form-wizard/configure-rendering-engines.jsp @@ -47,41 +47,52 @@ - - + <% final FileUploadBean upload = (FileUploadBean) - session.getAttribute(FileUploadBean.getKey(CreateFormWizard.FILE_RENDERING_ENGINE)); + session.getAttribute(FileUploadBean.getKey(CreateFormWizard.FILE_RENDERING_ENGINE_TEMPLATE)); if (upload == null || upload.getFile() == null) { %> - + - + - <% } else { %> + value="#{WizardManager.bean.renderingEngineTemplateFileName}"/> + + <% } %> + + + value="#{WizardManager.bean.renderingEngineName}"> + value="#{WizardManager.bean.renderingEngineChoices}"/> + valueChangeListener="#{WizardManager.bean.mimetypeForRenditionChanged}" + value="#{WizardManager.bean.mimetypeForRendition}"> @@ -99,31 +111,31 @@ else + value="#{WizardManager.bean.outputPathPatternForRendition}" + style="width:100%;"/> - - + rendered="#{WizardManager.bean.renderingEngineTemplatesDataModel.rowCount != 0}"> @@ -134,29 +146,29 @@ else - + - + - + - + - - + + + + + + - + <% FileUploadBean upload = (FileUploadBean) session.getAttribute(FileUploadBean.getKey("schema")); if (upload == null || upload.getFile() == null) { %> - - - - - + + + + + <% } else { %> - - - + + + <% } %> - + + + + + + + + - - - - - + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + +