XmpToJcrMetadataBuilder.java 16.9 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.xmp.XMPDateTime
 *  com.adobe.xmp.XMPDateTimeFactory
 *  com.adobe.xmp.XMPException
 *  com.adobe.xmp.XMPIterator
 *  com.adobe.xmp.XMPMeta
 *  com.adobe.xmp.XMPMetaFactory
 *  com.adobe.xmp.options.PropertyOptions
 *  com.adobe.xmp.properties.XMPPropertyInfo
 *  com.day.cq.dam.api.metadata.ExtractedMetadata
 *  com.day.cq.dam.api.metadata.xmp.XmpMappings
 *  javax.jcr.Binary
 *  javax.jcr.Item
 *  javax.jcr.NamespaceException
 *  javax.jcr.NamespaceRegistry
 *  javax.jcr.Node
 *  javax.jcr.NodeIterator
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.ValueFactory
 *  javax.jcr.Workspace
 *  org.apache.commons.io.IOUtils
 *  org.apache.jackrabbit.util.Text
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.dam.commons.metadata;

import com.adobe.xmp.XMPDateTime;
import com.adobe.xmp.XMPDateTimeFactory;
import com.adobe.xmp.XMPException;
import com.adobe.xmp.XMPIterator;
import com.adobe.xmp.XMPMeta;
import com.adobe.xmp.XMPMetaFactory;
import com.adobe.xmp.options.PropertyOptions;
import com.adobe.xmp.properties.XMPPropertyInfo;
import com.day.cq.dam.api.metadata.ExtractedMetadata;
import com.day.cq.dam.api.metadata.xmp.XmpMappings;
import com.day.cq.dam.commons.util.DateParser;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import javax.jcr.Binary;
import javax.jcr.Item;
import javax.jcr.NamespaceException;
import javax.jcr.NamespaceRegistry;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.ValueFactory;
import javax.jcr.Workspace;
import org.apache.commons.io.IOUtils;
import org.apache.jackrabbit.util.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class XmpToJcrMetadataBuilder {
    private static final Logger log = LoggerFactory.getLogger(XmpToJcrMetadataBuilder.class);
    public static final String VALUE_NODE_NAME = "value";
    public static final String PN_NAMESPACE = "namespace";
    public static final String PN_VALUE = "value";
    public static final String NT_XMP_PROPERTY = "xmp:Property";
    public static final String NT_XMP_STRUCT = "xmp:Struct";
    public static final String NT_XMP_SIMPLE = "xmp:Simple";
    public static final String NT_RDF_BAG = "rdf:Bag";
    public static final String NT_RDF_SEQ = "rdf:Seq";
    public static final String NT_RDF_ALT = "rdf:Alt";

    public void storeXmp(Node metadataRoot, XMPMeta meta) throws XMPException, RepositoryException {
        XMPIterator itr = meta.iterator();
        String rootPath = metadataRoot.getPath();
        String parent = null;
        while (itr.hasNext()) {
            String p;
            Node node;
            XMPPropertyInfo prop = (XMPPropertyInfo)itr.next();
            if (prop.getOptions().isSchemaNode()) continue;
            String string = parent = parent != null && prop.getPath().startsWith(parent) ? parent : null;
            if (prop.getOptions().isQualifier() || prop.getOptions().isSimple()) {
                p = rootPath + XmpToJcrMetadataBuilder.getPath(prop, parent);
                this.checkNamespace(prop, metadataRoot);
                node = this.getOrCreateNode(metadataRoot.getSession(), p, "xmp:Property");
                node.setProperty("namespace", prop.getNamespace());
                log.debug("PATH: " + node.getPath() + " (" + "xmp:Property" + ") namespace:" + prop.getNamespace());
                p = p + "/" + "value";
                Node vnode = this.getOrCreateNode(metadataRoot.getSession(), p, "xmp:Simple");
                this.setProperty(vnode, prop);
                log.debug("PATH: " + vnode.getPath() + " (" + "xmp:Simple" + ") value:" + prop.getValue());
                continue;
            }
            if (prop.getOptions().isArray()) {
                parent = prop.getPath();
                this.checkNamespace(prop, metadataRoot);
                p = rootPath + "/" + prop.getPath();
                node = this.getOrCreateNode(metadataRoot.getSession(), p, "xmp:Property");
                log.debug("PATH: " + node.getPath() + " (" + "xmp:Property" + ")");
                String name = "rdf:Bag";
                if (prop.getOptions().isArrayOrdered()) {
                    name = "rdf:Seq";
                } else if (prop.getOptions().isArrayAlternate()) {
                    name = "rdf:Alt";
                }
                p = rootPath + "/" + prop.getPath() + "/" + "value";
                Node anode = this.getOrCreateNode(metadataRoot.getSession(), p, name);
                log.debug("PATH: " + anode.getPath() + name);
                continue;
            }
            if (!prop.getOptions().isStruct()) continue;
            parent = prop.getPath();
            this.checkNamespace(prop, metadataRoot);
            p = rootPath + "/" + prop.getPath();
            node = this.getOrCreateNode(metadataRoot.getSession(), p, "xmp:Property");
            log.debug("PATH: " + node.getPath() + " (" + "xmp:Property" + ")");
            p = rootPath + "/" + prop.getPath() + "/" + "value";
            Node snode = this.getOrCreateNode(metadataRoot.getSession(), p, "xmp:Struct");
            log.debug("PATH: " + snode.getPath() + " (" + "xmp:Struct" + ")");
        }
        metadataRoot.getSession().save();
    }

    public XMPMeta getXmpFromJcr(Node metadataRoot) throws RepositoryException, XMPException {
        XMPMeta meta = XMPMetaFactory.create();
        NodeIterator itr = metadataRoot.getNodes();
        while (itr.hasNext()) {
            String namespace;
            Node n = itr.nextNode();
            if (!n.isNodeType("xmp:Property")) continue;
            Node value = n.getNode("value");
            if (n.hasProperty("namespace")) {
                namespace = n.getProperty("namespace").getString();
            } else {
                String nsPrefix = n.getName().substring(0, n.getName().indexOf(":"));
                namespace = XMPMetaFactory.getSchemaRegistry().getNamespaceURI(nsPrefix);
            }
            Object val = this.getValue(value);
            try {
                String key = n.getName();
                String nsPrefix = key.substring(0, key.indexOf(":"));
                if (XMPMetaFactory.getSchemaRegistry().getNamespacePrefix(namespace) == null) {
                    XMPMetaFactory.getSchemaRegistry().registerNamespace(namespace, nsPrefix);
                }
                meta.setProperty(namespace, key, val);
            }
            catch (XMPException xmpe) {
                log.warn("Cannot set xmp property: " + xmpe.getMessage());
            }
        }
        return meta;
    }

    public void storeAsXmp(ExtractedMetadata metadata, Node metadataRoot) throws XMPException, RepositoryException {
        XMPMeta meta = XMPMetaFactory.create();
        Set keys = metadata.getMetaDataProperties().keySet();
        for (String key : keys) {
            if (XmpMappings.defaultSimpleXmpMappings.containsKey(key)) {
                String[] xmpKeys;
                for (String xmpKey : xmpKeys = this.getXmpKeys((String)XmpMappings.defaultSimpleXmpMappings.get(key))) {
                    try {
                        this.setXmpProperty(meta, xmpKey, metadata.getMetaDataProperties().get(key));
                        continue;
                    }
                    catch (XMPException e) {
                        log.debug("Cannot create xmp property: " + e.getMessage());
                    }
                }
                continue;
            }
            if (XmpMappings.defaultBagXmpMappings.containsKey(key) || XmpMappings.defaultSeqXmpMappings.containsKey(key)) continue;
            if (key.indexOf(":") < 0) {
                XMPMetaFactory.getSchemaRegistry().registerNamespace("http://www.day.com/dam/1.0", "dam");
                try {
                    meta.setProperty("http://www.day.com/dam/1.0", "dam:" + key.replace(" ", "").trim(), metadata.getMetaDataProperties().get(key));
                }
                catch (XMPException e) {
                    log.warn("Cannot set xmp property:" + e.getMessage());
                }
                continue;
            }
            try {
                String nsPrefix = key.substring(0, key.indexOf(":"));
                String nsUri = metadataRoot.getSession().getNamespaceURI(nsPrefix);
                if (XMPMetaFactory.getSchemaRegistry().getNamespacePrefix(nsUri) == null) {
                    XMPMetaFactory.getSchemaRegistry().registerNamespace(nsUri, nsPrefix);
                }
                this.setXmpProperty(meta, key, metadata.getMetaDataProperties().get(key));
            }
            catch (XMPException e) {
                log.debug("Cannot create xmp property: " + e.getMessage());
            }
        }
        this.storeXmp(metadataRoot, meta);
    }

    private void setXmpProperty(XMPMeta meta, String xmpKey, Object value) throws XMPException {
        if (value instanceof Boolean) {
            meta.setPropertyBoolean(this.getNamespace(xmpKey), xmpKey, ((Boolean)value).booleanValue());
        } else if (value instanceof Calendar) {
            meta.setPropertyCalendar(this.getNamespace(xmpKey), xmpKey, (Calendar)value);
        } else if (value instanceof Date) {
            Calendar cal = Calendar.getInstance();
            cal.setTime((Date)value);
            meta.setPropertyDate(this.getNamespace(xmpKey), xmpKey, XMPDateTimeFactory.createFromCalendar((Calendar)cal));
        } else if (value instanceof Double) {
            meta.setPropertyDouble(this.getNamespace(xmpKey), xmpKey, ((Double)value).doubleValue());
        } else if (value instanceof Integer) {
            meta.setPropertyInteger(this.getNamespace(xmpKey), xmpKey, ((Integer)value).intValue());
        } else if (value instanceof Long) {
            meta.setPropertyLong(this.getNamespace(xmpKey), xmpKey, ((Long)value).longValue());
        } else {
            meta.setProperty(this.getNamespace(xmpKey), xmpKey, value);
        }
    }

    private String[] getXmpKeys(String keyString) {
        if (keyString.indexOf(",") > 0) {
            return keyString.split(",");
        }
        return new String[]{keyString};
    }

    private String getNamespace(String xmpKey) {
        if (xmpKey.indexOf(":") > 0) {
            String nsPrefix = xmpKey.substring(0, xmpKey.indexOf(":"));
            return XMPMetaFactory.getSchemaRegistry().getNamespaceURI(nsPrefix);
        }
        return null;
    }

    private Node getOrCreateNode(Session session, String path, String nodetype) throws RepositoryException {
        if (session.itemExists(path)) {
            return (Node)session.getItem(path);
        }
        return session.getRootNode().addNode(path.substring(1), nodetype);
    }

    private static String getPath(XMPPropertyInfo prop, String parent) {
        if (parent != null) {
            String postPath = prop.getPath().substring(parent.length());
            String string = postPath = postPath.startsWith("/") ? postPath.substring(1) : postPath;
            if (postPath.indexOf(":") > 0) {
                String[] name = postPath.split(":");
                postPath = XMPMetaFactory.getSchemaRegistry().getNamespaceURI(name[0]) != null && XMPMetaFactory.getSchemaRegistry().getNamespaceURI(name[0]).equals(prop.getNamespace()) ? name[0] + ":" + Text.escapeIllegalJcrChars((String)name[1]) : Text.escapeIllegalJcrChars((String)postPath);
            } else {
                postPath = Text.escapeIllegalJcrChars((String)postPath);
            }
            String path = parent + "/" + "value" + (postPath.startsWith("/") ? "" : "/") + postPath;
            return path.startsWith("/") ? path : "/" + path;
        }
        return "/" + prop.getPath();
    }

    private void setProperty(Node node, XMPPropertyInfo prop) {
        block24 : {
            try {
                Object val = prop.getOriValue();
                if (node.hasProperty("value")) {
                    int type = node.getProperty("value").getType();
                    switch (type) {
                        case 5: {
                            Object v = this.checkForDate(val);
                            if (v instanceof Date) {
                                Calendar cal = Calendar.getInstance();
                                cal.setTime((Date)v);
                                node.setProperty("value", cal);
                            }
                            break block24;
                        }
                        case 6: {
                            node.setProperty("value", Boolean.valueOf((String)val).booleanValue());
                            break block24;
                        }
                        case 4: {
                            node.setProperty("value", Double.valueOf((String)val).doubleValue());
                            break block24;
                        }
                        case 3: {
                            node.setProperty("value", Long.valueOf((String)val).longValue());
                            break block24;
                        }
                    }
                    node.setProperty("value", (String)val);
                    break block24;
                }
                if ((val = this.checkForDate(val)) instanceof Boolean) {
                    node.setProperty("value", ((Boolean)val).booleanValue());
                } else if (val instanceof Integer) {
                    node.setProperty("value", (long)((Integer)val).intValue());
                } else if (val instanceof Long) {
                    node.setProperty("value", ((Long)val).longValue());
                } else if (val instanceof Double) {
                    node.setProperty("value", ((Double)val).doubleValue());
                } else if (val instanceof XMPDateTime) {
                    node.setProperty("value", ((XMPDateTime)val).getCalendar());
                } else if (val instanceof byte[]) {
                    node.setProperty("value", node.getSession().getValueFactory().createBinary((InputStream)new ByteArrayInputStream((byte[])val)));
                } else if (val instanceof Date) {
                    Calendar cal = Calendar.getInstance();
                    cal.setTime((Date)val);
                    node.setProperty("value", cal);
                } else {
                    node.setProperty("value", (String)prop.getValue());
                }
            }
            catch (Throwable re) {
                log.warn("Cannot set xmp property (" + prop.getPath() + "): " + re.getMessage());
            }
        }
    }

    private Object checkForDate(Object val) {
        if (val instanceof String) {
            Date date = DateParser.parseDate((String)val);
            return date == null ? val : date;
        }
        return val;
    }

    private Object getValue(Node value) {
        byte[] val;
        block10 : {
            val = null;
            try {
                Property prop = value.getProperty("value");
                switch (prop.getType()) {
                    case 2: {
                        val = IOUtils.toByteArray((InputStream)prop.getBinary().getStream());
                        break block10;
                    }
                    case 5: {
                        val = XMPDateTimeFactory.createFromCalendar((Calendar)prop.getDate());
                        break block10;
                    }
                    case 6: {
                        val = prop.getBoolean();
                        break block10;
                    }
                    case 4: {
                        val = prop.getDouble();
                        break block10;
                    }
                    case 3: {
                        val = prop.getLong();
                        break block10;
                    }
                }
                val = prop.getString();
            }
            catch (RepositoryException re) {
                log.warn("Problem while getting xmp value from jcr property: " + re.getMessage());
            }
            catch (IOException ioe) {
                log.warn("Problem while getting binary xmp value from jcr property: " + ioe.getMessage());
            }
        }
        return val;
    }

    private void checkNamespace(XMPPropertyInfo prop, Node metadataRoot) throws RepositoryException {
        try {
            String prefix = metadataRoot.getSession().getWorkspace().getNamespaceRegistry().getPrefix(prop.getNamespace());
        }
        catch (NamespaceException e) {
            String prefix = XMPMetaFactory.getSchemaRegistry().getNamespacePrefix(prop.getNamespace());
            prefix = prefix.substring(0, prefix.indexOf(":"));
            try {
                metadataRoot.getSession().getWorkspace().getNamespaceRegistry().registerNamespace(prefix, prop.getNamespace());
            }
            catch (RepositoryException re) {
                // empty catch block
            }
        }
    }
}