Java tutorial
/** * Copyright gradecak.com * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 com.gradecak.alfresco.simpless; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.alfresco.model.ContentModel; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.lock.LockStatus; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.repository.datatype.TypeConverter; import org.alfresco.service.namespace.QName; import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.multipart.commons.CommonsMultipartFile; import com.gradecak.alfresco.simpless.domain.SysBase; public class MetadataManager { static private TypeConverter converter = DefaultTypeConverter.INSTANCE; private ServiceRegistry serviceRegistry; private AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor; /** * handles only simple types (no associations ... complex types) * * any null properties will be removed from the node by calling nodeService.removeProperty, as * setting null is considered as a removal of the value * * if a cm:content property is present than the value might be a file, a multipart, a ContentData * or a String. Otherwise the value must be <code>Serializable</code> However, before saving an * alfresco converter is executed on the vale for the given type repreented in the model * * Any readonly properties will not be serialized/saved * * return {@link SysBase} with converted values (did not check the repository) but without syncing * actions & aspects as we belongs to the same transaction and so the sync should be done after * the call to this method. As example we might consider behaviors that can change values of the * node */ public <T extends SysBase> T save(final T object) { Assert.notNull(object, "object must not be null"); MetadataHolder holder = object.getMetadataHolder(); Assert.notNull(holder, "the holder object must not be null"); Map<QName, Serializable> allProps = holder.getPropertiesMap(); // resolve unkown properties and put it all together Map<String, Serializable> unkwonProperties = object.getUnkwonProperties(); for (Entry<String, Serializable> entry : unkwonProperties.entrySet()) { QName qname = QName.resolveToQName(serviceRegistry.getNamespaceService(), entry.getKey()); allProps.put(qname, entry.getValue()); } NodeRef toNode = object.getNodeRef(); // works on latest alfresco versions. if // if (this.serviceRegistry.getCheckOutCheckInService().isCheckedOut(toNode)) { // works on all alfresco versions if (this.serviceRegistry.getCheckOutCheckInService().getWorkingCopy(toNode) != null) { if (LockStatus.LOCK_OWNER.equals(this.serviceRegistry.getLockService().getLockStatus(toNode))) { toNode = this.serviceRegistry.getCheckOutCheckInService().getWorkingCopy(toNode); } } Metadata properties = new Metadata(); for (Entry<QName, Serializable> entry : allProps.entrySet()) { QName qname = entry.getKey(); if (qname == null) { continue; } PropertyDefinition propertyDef = this.serviceRegistry.getDictionaryService().getProperty(qname); if (propertyDef == null) { continue; } if (holder.isReadOnlyProperty(qname)) { continue; } Serializable value = entry.getValue(); if (value instanceof String[]) { // TODO: check if we need to handle props different than String[] value = ((String[]) value)[0]; } DataTypeDefinition dataType = propertyDef.getDataType(); if (DataTypeDefinition.CONTENT.equals(dataType.getName())) { if (toNode != null) { ContentWriter writer = this.serviceRegistry.getContentService().getWriter(toNode, propertyDef.getName(), true); if (value instanceof CommonsMultipartFile) { CommonsMultipartFile file = (CommonsMultipartFile) value; writer.setMimetype(this.serviceRegistry.getMimetypeService() .guessMimetype(file.getOriginalFilename())); try { writer.putContent(file.getInputStream()); } catch (IOException e) { throw new ContentIOException("Could not write the file input stream", e); } } else if (value instanceof File) { File file = (File) value; writer.setMimetype(this.serviceRegistry.getMimetypeService().guessMimetype(file.getName())); writer.putContent(file); } else if (value instanceof String) { writer.setMimetype("text/plain"); writer.putContent((String) value); } else if (value instanceof ContentData) { properties.put(qname, (ContentData) value); } else { if (value != null) { throw new RuntimeException( "Unhandled property of type d:content. Name : " + propertyDef.getName()); } } } } else { if (DataTypeDefinition.QNAME.equals(dataType.getName())) { if (value instanceof String && !StringUtils.hasText((String) value)) { continue; } } Object convertedValue = converter.convert(dataType, value); if (convertedValue == null) { // TODO marked in order to verify this behavior // we remove the specific property as its value has been erased this.serviceRegistry.getNodeService().removeProperty(toNode, qname); } else { properties.put(qname, (Serializable) convertedValue); object.getMetadataHolder().setProperty(qname, (Serializable) convertedValue); } } } // assure to remove nodeRef property before saving properties.remove(ContentModel.PROP_NODE_REF); if (!properties.isEmpty()) { this.serviceRegistry.getNodeService().addProperties(toNode, properties); } syncAspectsAndActions(toNode, object); return object; } /** * Does not handle associations or complex types. * * return {@link SysBase} with values from the repository. If a property is of cm:content type, a * value of <code>ContentData</code> is returned. But if the mimetype of cm:content is text based * (<code>MimetypeService.isText</code>) than a String value is returned. */ public <T extends SysBase> T get(final T alfrescoObject) { Assert.notNull(alfrescoObject, "object must not be null"); MetadataHolder obj = alfrescoObject.getMetadataHolder(); Assert.notNull(obj, "The holder object must not be null"); NodeRef fromNode = alfrescoObject.getNodeRef(); // works on latest alfresco versions. if // if (this.serviceRegistry.getCheckOutCheckInService().isCheckedOut(fromNode)) { if (this.serviceRegistry.getCheckOutCheckInService().getWorkingCopy(fromNode) != null) { if (LockStatus.LOCK_OWNER.equals(this.serviceRegistry.getLockService().getLockStatus(fromNode))) { fromNode = this.serviceRegistry.getCheckOutCheckInService().getWorkingCopy(fromNode); } } // TODO maybe get only the properties present on the class? Map<QName, Serializable> properties = this.serviceRegistry.getNodeService().getProperties(fromNode); for (Entry<QName, Serializable> entry : properties.entrySet()) { QName qName = entry.getKey(); PropertyDefinition def = this.serviceRegistry.getDictionaryService().getProperty(qName); // Skip when there is no property definition. This might be the case if property was renamed. if (def == null) { continue; } DataTypeDefinition dataType = def.getDataType(); Serializable value = entry.getValue(); if (DataTypeDefinition.CONTENT.equals(dataType.getName())) { ContentReader reader = this.serviceRegistry.getContentService().getReader(fromNode, qName); if (reader != null) { String mimetype = reader.getMimetype(); if (this.serviceRegistry.getMimetypeService().isText(mimetype)) { value = reader.getContentString(); } else { value = reader.getContentData(); } } } obj.setProperty(qName, value); } syncAspectsAndActions(fromNode, alfrescoObject); return alfrescoObject; } private void syncAspectsAndActions(NodeRef fromNode, SysBase object) { Set<QName> aspects = this.serviceRegistry.getNodeService().getAspects(fromNode); List<QName> cmAspects = new ArrayList<QName>(aspects); Collections.sort(cmAspects); object.getMetadataHolder().setAspects(cmAspects); if (object instanceof ActionList) { // bind actions if (autowiredAnnotationBeanPostProcessor != null) { List<Action> actions = ((ActionList) object).getActionList(); if (actions != null) { for (Action action : actions) { autowiredAnnotationBeanPostProcessor.processInjection(action); } } } } } public void setServiceRegistry(ServiceRegistry serviceRegistry) { this.serviceRegistry = serviceRegistry; } public void setAutowiredAnnotationBeanPostProcessor( AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor) { this.autowiredAnnotationBeanPostProcessor = autowiredAnnotationBeanPostProcessor; } }