com.gradecak.alfresco.simpless.MetadataManager.java Source code

Java tutorial

Introduction

Here is the source code for com.gradecak.alfresco.simpless.MetadataManager.java

Source

/**
 * 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;
    }

}