diff --git a/config/alfresco/form-services-context.xml b/config/alfresco/form-services-context.xml index e84ce429cc..84aa8c8c09 100644 --- a/config/alfresco/form-services-context.xml +++ b/config/alfresco/form-services-context.xml @@ -76,6 +76,7 @@ + node @@ -89,6 +90,7 @@ + type diff --git a/source/java/org/alfresco/repo/forms/FormServiceImplTest.java b/source/java/org/alfresco/repo/forms/FormServiceImplTest.java index 39adba6350..2a3f908911 100644 --- a/source/java/org/alfresco/repo/forms/FormServiceImplTest.java +++ b/source/java/org/alfresco/repo/forms/FormServiceImplTest.java @@ -41,6 +41,7 @@ import org.alfresco.repo.forms.processor.node.TypeFormProcessor; import org.alfresco.repo.jscript.ClasspathScriptLocation; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; @@ -954,6 +955,51 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest assertNotNull("Expected new node to be created using itemId " + ContentModel.TYPE_CONTENT.toString(), newNode); } + public void testContentCreateForm() throws Exception + { + // create FormData object containing the values to update + FormData data = new FormData(); + + // supply the name + String name = "created-" + this.documentName; + data.addFieldData("prop_cm_name", name); + + // supply the title property + String title = "This is the title property"; + data.addFieldData("prop_cm_title", title); + + // specify the mimetype property + String mimetype = "text/html"; + data.addFieldData("prop_mimetype", mimetype); + + // supply the content property + String content = "This is the content."; + data.addFieldData("prop_cm_content", content); + + // supply the destination + data.addFieldData(TypeFormProcessor.DESTINATION, this.folder.toString()); + + // persist the data + NodeRef newNode = (NodeRef)this.formService.saveForm(new Item(TYPE_FORM_ITEM_KIND, "cm:content"), data); + + // retrieve the data directly from the node service to ensure its there + Map props = this.nodeService.getProperties(newNode); + String newName = (String)props.get(ContentModel.PROP_NAME); + String newTitle = (String)props.get(ContentModel.PROP_TITLE); + assertEquals(name, newName); + assertEquals(title, newTitle); + + ContentData contentData = (ContentData) this.nodeService.getProperty(newNode, ContentModel.PROP_CONTENT); + assertNotNull(contentData); + String newMimetype = contentData.getMimetype(); + assertEquals(mimetype, newMimetype); + + ContentReader reader = this.contentService.getReader(newNode, ContentModel.PROP_CONTENT); + assertNotNull(reader); + String newContent = reader.getContentString(); + assertEquals(content, newContent); + } + public void testNoForm() throws Exception { // test that a form can not be retrieved for a non-existent item diff --git a/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java index 0c0ef953ed..6ba096959f 100644 --- a/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java @@ -40,6 +40,8 @@ import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.Period; @@ -85,6 +87,8 @@ public abstract class ContentModelFormProcessor extends public static final String TRANSIENT_ENCODING = "encoding"; /** Protected constants */ + protected static final String DEFAULT_CONTENT_MIMETYPE = "text/plain"; + protected static final String MSG_MIMETYPE_LABEL = "form_service.mimetype.label"; protected static final String MSG_MIMETYPE_DESC = "form_service.mimetype.description"; @@ -105,6 +109,8 @@ public abstract class ContentModelFormProcessor extends protected DictionaryService dictionaryService; protected NamespaceService namespaceService; + + protected ContentService contentService; /** * A regular expression which can be used to match property names. These @@ -167,6 +173,16 @@ public abstract class ContentModelFormProcessor extends { this.namespaceService = namespaceService; } + + /** + * Sets the content service + * + * @param contentService The ContentService instance + */ + public void setContentService(ContentService contentService) + { + this.contentService = contentService; + } /** * Sets up a field definition for the given property. @@ -586,26 +602,27 @@ public abstract class ContentModelFormProcessor extends if (TRANSIENT_MIMETYPE.equals(fieldName) || TRANSIENT_ENCODING.equals(fieldName) || TRANSIENT_SIZE.equals(fieldName)) { - // if the node type is content or sublcass thereof generate - // appropriate field - if (nodeRef != null && this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) + // if the node type is content or sublcass thereof generate appropriate field + if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) { - ContentData content = (ContentData) this.nodeService.getProperty(nodeRef, - ContentModel.PROP_CONTENT); - if (content != null) + ContentData content = null; + + if (nodeRef != null) { - if (TRANSIENT_MIMETYPE.equals(fieldName)) - { - generateMimetypePropertyField(content, form); - } - else if (TRANSIENT_ENCODING.equals(fieldName)) - { - generateEncodingPropertyField(content, form); - } - else if (TRANSIENT_SIZE.equals(fieldName)) - { - generateSizePropertyField(content, form); - } + content = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); + } + + if (TRANSIENT_MIMETYPE.equals(fieldName)) + { + generateMimetypePropertyField(content, form); + } + else if (TRANSIENT_ENCODING.equals(fieldName)) + { + generateEncodingPropertyField(content, form); + } + else if (TRANSIENT_SIZE.equals(fieldName)) + { + generateSizePropertyField(content, form); } } } @@ -875,7 +892,7 @@ public abstract class ContentModelFormProcessor extends if (fieldName.startsWith(PROP_DATA_PREFIX)) { - processPropertyPersist(nodeRef, propDefs, fieldData, propsToPersist); + processPropertyPersist(nodeRef, propDefs, fieldData, propsToPersist, data); } else if (fieldName.startsWith(ASSOC_DATA_PREFIX)) { @@ -912,9 +929,10 @@ public abstract class ContentModelFormProcessor extends * @param propDefs Map of PropertyDefinition's for the node being persisted * @param fieldData Data to persist for the property * @param propsToPersist Map of properties to be persisted + * @param data The FormData to persist */ protected void processPropertyPersist(NodeRef nodeRef, Map propDefs, - FieldData fieldData, Map propsToPersist) + FieldData fieldData, Map propsToPersist, FormData data) { if (getLogger().isDebugEnabled()) getLogger().debug("Processing field " + fieldData + " for property persistence"); @@ -946,6 +964,10 @@ public abstract class ContentModelFormProcessor extends { processNamePropertyPersist(nodeRef, fieldData); } + else if (propDef.getDataType().getName().equals(DataTypeDefinition.CONTENT)) + { + processContentPropertyPersist(nodeRef, fieldData, propsToPersist, data); + } else { Object value = fieldData.getValue(); @@ -1264,6 +1286,84 @@ public abstract class ContentModelFormProcessor extends propsToPersist.put(ContentModel.PROP_CONTENT, contentData); } } + + /** + * Persists the given field data as the content + * + * @param nodeRef The NodeRef to update the content for + * @param fieldData The data representing the new content + * @param propsToPersist Map of properties to be persisted + * @param data The form data being persisted + */ + protected void processContentPropertyPersist(NodeRef nodeRef, FieldData fieldData, + Map propsToPersist, FormData data) + { + ContentWriter writer = this.contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true); + + if (writer != null) + { + // determine whether there is any content for the node yet i.e. it's a create + boolean defaultMimetypeRequired = (this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT) == null); + + // write the content + writer.putContent((String)fieldData.getValue()); + + // if there was no content set a sensible default mimetype if necessary + if (defaultMimetypeRequired) + { + // if the transient mimetype property has already set the mimetype don't do anything + ContentData contentData = (ContentData) propsToPersist.get(ContentModel.PROP_CONTENT); + if (contentData != null) + { + String mimetype = contentData.getMimetype(); + if (mimetype == null) + { + contentData = ContentData.setMimetype(contentData, determineDefaultMimetype(data)); + } + } + else + { + // content data has not been persisted yet so get it from the node + contentData = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); + if (contentData != null) + { + contentData = ContentData.setMimetype(contentData, determineDefaultMimetype(data)); + } + } + + // add the potentially changed content data object back to property map for persistence + propsToPersist.put(ContentModel.PROP_CONTENT, contentData); + } + } + } + + /** + * Looks through the form data for the 'mimetype' transient field + * and returns it's value if found, otherwise the default 'text/plain' + * is returned + * + * @param data Form data being persisted + * @return The default mimetype + */ + protected String determineDefaultMimetype(FormData data) + { + String mimetype = DEFAULT_CONTENT_MIMETYPE; + + if (data != null) + { + FieldData mimetypeField = data.getFieldData(PROP + DATA_KEY_SEPARATOR + TRANSIENT_MIMETYPE); + if (mimetypeField != null) + { + String mimetypeFieldValue = (String)mimetypeField.getValue(); + if (mimetypeFieldValue != null && mimetypeFieldValue.length() > 0) + { + mimetype = mimetypeFieldValue; + } + } + } + + return mimetype; + } } /** diff --git a/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java b/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java index 39a90c2d45..bf4089f8fc 100644 --- a/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java +++ b/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java @@ -205,15 +205,16 @@ public class TaggingServiceImpl implements TaggingService, /** * @see org.alfresco.service.cmr.tagging.TaggingService#createTag(java.lang.String) */ - public void createTag(StoreRef storeRef, String tag) + public NodeRef createTag(StoreRef storeRef, String tag) { // Lower the case of the tag tag = tag.toLowerCase(); if (isTag(storeRef, tag) == false) { - this.categoryService.createRootCategory(storeRef, ContentModel.ASPECT_TAGGABLE, tag); - } + return this.categoryService.createRootCategory(storeRef, ContentModel.ASPECT_TAGGABLE, tag); + } + return null; } /** @@ -326,7 +327,7 @@ public class TaggingServiceImpl implements TaggingService, * @param tag tag * @return NodeRef tag node reference or null not exist */ - private NodeRef getTagNodeRef(StoreRef storeRef, String tag) + public NodeRef getTagNodeRef(StoreRef storeRef, String tag) { NodeRef tagNodeRef = null; String query = "+PATH:\"cm:taggable/cm:" + ISO9075.encode(tag) + "\""; diff --git a/source/java/org/alfresco/repo/tagging/script/ScriptTaggingService.java b/source/java/org/alfresco/repo/tagging/script/ScriptTaggingService.java index c55c8a3d81..a8804b8876 100644 --- a/source/java/org/alfresco/repo/tagging/script/ScriptTaggingService.java +++ b/source/java/org/alfresco/repo/tagging/script/ScriptTaggingService.java @@ -27,7 +27,9 @@ package org.alfresco.repo.tagging.script; import java.util.List; import org.alfresco.repo.jscript.BaseScopableProcessorExtension; +import org.alfresco.repo.jscript.ScriptNode; import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; @@ -78,4 +80,39 @@ public class ScriptTaggingService extends BaseScopableProcessorExtension return (String[])result.toArray(new String[result.size()]); } + /** + * Get a tag by name if available in a store + * + * @param store store reference + * @param tag tag name + * @return ScriptNode tag node, or null if not found + */ + public ScriptNode getTag(String store, String tag) + { + StoreRef storeRef = new StoreRef(store); + NodeRef result = this.serviceRegistry.getTaggingService().getTagNodeRef(storeRef, tag); + if (result != null) + { + return new ScriptNode(result, this.serviceRegistry); + } + return null; + } + + /** + * Create a tag in a given store + * + * @param store store reference + * @param tag tag name + * @return ScriptNode newly created tag node, or null if unable to create + */ + public ScriptNode createTag(String store, String tag) + { + StoreRef storeRef = new StoreRef(store); + NodeRef result = this.serviceRegistry.getTaggingService().createTag(storeRef, tag); + if (result != null) + { + return new ScriptNode(result, this.serviceRegistry); + } + return null; + } } diff --git a/source/java/org/alfresco/service/cmr/tagging/TaggingService.java b/source/java/org/alfresco/service/cmr/tagging/TaggingService.java index 565721ccf5..65fea19568 100644 --- a/source/java/org/alfresco/service/cmr/tagging/TaggingService.java +++ b/source/java/org/alfresco/service/cmr/tagging/TaggingService.java @@ -67,7 +67,7 @@ public interface TaggingService * @param storeRef store reference * @param tag tag name */ - void createTag(StoreRef storeRef, String tag); + NodeRef createTag(StoreRef storeRef, String tag); /** * Delete an existing tag @@ -84,7 +84,18 @@ public interface TaggingService * @param tag tag name */ void addTag(NodeRef nodeRef, String tag); - + + /** + * Gets the node reference for a given tag. + *

+ * Returns null if tag is not present. + * + * @param storeRef store reference + * @param tag tag + * @return NodeRef tag node reference or null not exist + */ + NodeRef getTagNodeRef(StoreRef storeRef, String tag); + /** * Adds a list of tags to a node. *