001/*
002 * (C) Copyright 2006-2018 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 */
017package org.nuxeo.ecm.diff.content.adapter;
018
019import java.util.HashMap;
020import java.util.Map;
021
022import org.apache.commons.lang3.StringUtils;
023import org.apache.commons.logging.Log;
024import org.apache.commons.logging.LogFactory;
025import org.nuxeo.ecm.core.api.DocumentModel;
026import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
027import org.nuxeo.ecm.diff.content.ContentDiffAdapter;
028import org.nuxeo.ecm.diff.content.ContentDiffException;
029import org.nuxeo.ecm.diff.content.adapter.factories.BlobHolderContentDiffAdapterFactory;
030import org.nuxeo.ecm.diff.content.adapter.factories.FileBasedContentDiffAdapterFactory;
031import org.nuxeo.runtime.model.ComponentInstance;
032import org.nuxeo.runtime.model.DefaultComponent;
033
034/**
035 * Runtime component that handles the extension points and the service interface for content diff Adapter management.
036 *
037 * @author Antoine Taillefer
038 */
039public class ContentDiffAdapterManagerComponent extends DefaultComponent implements ContentDiffAdapterManager {
040
041    public static final String ADAPTER_FACTORY_EP = "adapterFactory";
042
043    public static final String MIME_TYPE_CONTENT_DIFFER_EP = "mimeTypeContentDiffer";
044
045    private static final Log log = LogFactory.getLog(ContentDiffAdapterManagerComponent.class);
046
047    protected Map<String, ContentDiffAdapterFactory> factoryRegistry = new HashMap<>();
048
049    protected Map<String, MimeTypeContentDiffer> contentDifferFactory = new HashMap<>();
050
051    protected Map<String, MimeTypeContentDiffer> contentDifferFactoryByName = new HashMap<>();
052
053    // Component and EP management
054
055    @Override
056    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
057
058        if (ADAPTER_FACTORY_EP.equals(extensionPoint)) {
059            ContentDiffAdapterFactoryDescriptor desc = (ContentDiffAdapterFactoryDescriptor) contribution;
060            if (desc.isEnabled()) {
061                ContentDiffAdapterFactory factory = desc.getNewInstance();
062                if (factory != null) {
063                    factoryRegistry.put(desc.getTypeName(), factory);
064                }
065            } else {
066                factoryRegistry.remove(desc.getTypeName());
067            }
068        } else if (MIME_TYPE_CONTENT_DIFFER_EP.equals(extensionPoint)) {
069            MimeTypeContentDifferDescriptor desc = (MimeTypeContentDifferDescriptor) contribution;
070            try {
071                MimeTypeContentDiffer contentDiffer = desc.getKlass().newInstance();
072                contentDifferFactory.put(desc.getPattern(), contentDiffer);
073
074                // Also (since 7.4) add a name in the contribution
075                String name = desc.getName();
076                if (StringUtils.isNotBlank(name)) {
077                    contentDifferFactoryByName.put(name, contentDiffer);
078                }
079            } catch (ReflectiveOperationException e) {
080                throw new RuntimeException(e);
081            }
082        }
083    }
084
085    @Override
086    public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
087    }
088
089    // Service interface impl
090
091    @Override
092    public boolean hasAdapter(DocumentModel doc) {
093        if (doc == null) {
094            return false;
095        }
096
097        String docType = doc.getType();
098        if (factoryRegistry.containsKey(docType)) {
099            return true;
100        }
101
102        return doc.hasSchema("file") || doc.hasSchema("files");
103    }
104
105    @Override
106    public ContentDiffAdapter getAdapter(DocumentModel doc) {
107        if (doc == null) {
108            return null;
109        }
110
111        String docType = doc.getType();
112
113        log.debug("Looking for ContentDiffAdapter for type " + docType);
114
115        if (factoryRegistry.containsKey(docType)) {
116            log.debug("Dedicated ContentDiffAdapter factory found");
117            return factoryRegistry.get(docType).getAdapter(doc);
118        }
119
120        if (doc.isFolder()) {
121            return null;
122        }
123
124        BlobHolder bh = doc.getAdapter(BlobHolder.class);
125        if (bh != null) {
126            log.debug("Using Blob Holder based ContentDiffAdapter factory");
127            ContentDiffAdapterFactory factory = new BlobHolderContentDiffAdapterFactory();
128            return factory.getAdapter(doc);
129
130        }
131
132        if (doc.hasSchema("file") || doc.hasSchema("files")) {
133            log.debug("Using default file based ContentDiffAdapter factory");
134            ContentDiffAdapterFactory factory = new FileBasedContentDiffAdapterFactory();
135            return factory.getAdapter(doc);
136        } else {
137            return null;
138        }
139    }
140
141    @Override
142    public MimeTypeContentDiffer getContentDiffer(String mimeType) {
143        for (Map.Entry<String, MimeTypeContentDiffer> entry : contentDifferFactory.entrySet()) {
144            if (mimeType.matches(entry.getKey())) {
145                return entry.getValue();
146            }
147        }
148        return null;
149    }
150
151    @Override
152    public MimeTypeContentDiffer getContentDifferForName(String name) {
153        for (Map.Entry<String, MimeTypeContentDiffer> entry : contentDifferFactoryByName.entrySet()) {
154            if (name.equals(entry.getKey())) {
155                return entry.getValue();
156            }
157        }
158        return null;
159    }
160
161    @Override
162    public HtmlContentDiffer getHtmlContentDiffer() throws ContentDiffException {
163        MimeTypeContentDiffer htmlContentDiffer = contentDifferFactory.get("text/html");
164        if (htmlContentDiffer == null || !(htmlContentDiffer instanceof HtmlContentDiffer)) {
165            throw new ContentDiffException(
166                    "No content differ of type HtmlContentDiffer found for the 'text/html' mime-type. Please check the 'mimeTypeContentDiffer' contributions.");
167        }
168        return (HtmlContentDiffer) htmlContentDiffer;
169    }
170
171}