001/*
002 * (C) Copyright 2008 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 * $Id: IndexingAdapterService.java 31426 2008-04-09 17:00:34Z ogrisel $
018 */
019
020package org.nuxeo.ecm.platform.indexing.gateway.adapter;
021
022import java.util.ArrayList;
023import java.util.Collections;
024import java.util.HashMap;
025import java.util.LinkedList;
026import java.util.List;
027import java.util.Map;
028
029import org.nuxeo.ecm.core.api.CoreSession;
030import org.nuxeo.ecm.platform.api.ws.DocumentBlob;
031import org.nuxeo.ecm.platform.api.ws.DocumentDescriptor;
032import org.nuxeo.ecm.platform.api.ws.DocumentProperty;
033import org.nuxeo.ecm.platform.api.ws.WsACE;
034import org.nuxeo.runtime.RuntimeServiceException;
035import org.nuxeo.runtime.model.ComponentInstance;
036import org.nuxeo.runtime.model.DefaultComponent;
037
038/**
039 * Service to allow client code to register converters for the datastructures served to the Sinequa Intuition to be
040 * indexed. This is especially useful to be able to index Access Control Policy after some post-processing since the ACL
041 * model of Intuition is not as expressive as the Nuxeo Core security model.
042 *
043 * @author Olivier Grisel <ogrisel@nuxeo.com>
044 */
045public class IndexingAdapterService extends DefaultComponent implements IndexingAdapter {
046
047    public static final String INTUITION_ADAPTER_XP = "adapters";
048
049    public static final String BLOB_FORMAT_XP = "blobFormat";
050
051    protected final List<IndexingAdapterDescriptor> registeredAdapters = new LinkedList<IndexingAdapterDescriptor>();
052
053    protected final List<IndexingAdapter> mergedAdapters = new LinkedList<IndexingAdapter>();
054
055    protected boolean useDownloadUrl = true;
056
057    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
058        if (INTUITION_ADAPTER_XP.equals(extensionPoint)) {
059            mergedAdapters.clear(); // invalidate merged contributions
060            IndexingAdapterDescriptor descriptor = (IndexingAdapterDescriptor) contribution;
061            if (descriptor.isEnabled()) {
062                // do not try to instantiate classes to be disabled by the
063                // contribution
064                IndexingAdapter adapterInstance;
065                try {
066                    adapterInstance = (IndexingAdapter) contributor.getContext().loadClass(descriptor.getClassName()).newInstance();
067                } catch (ReflectiveOperationException e) {
068                    throw new RuntimeException(e);
069                }
070                descriptor.setAdapterInstance(adapterInstance);
071            }
072            registeredAdapters.add(descriptor);
073        } else if (BLOB_FORMAT_XP.equals(extensionPoint)) {
074            BlobFormatDescriptor desc = (BlobFormatDescriptor) contribution;
075            useDownloadUrl = desc.isUseDownloadUrl();
076        } else {
077            throw new RuntimeServiceException("unsupported extension point: " + extensionPoint);
078        }
079    }
080
081    public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
082        if (INTUITION_ADAPTER_XP.equals(extensionPoint)) {
083            mergedAdapters.clear(); // invalidate merged contributions
084            IndexingAdapterDescriptor descriptor = (IndexingAdapterDescriptor) contribution;
085            registeredAdapters.remove(registeredAdapters.lastIndexOf(descriptor));
086
087        } else {
088            throw new RuntimeServiceException("unsupported extension point: " + extensionPoint);
089        }
090    }
091
092    public DocumentDescriptor adaptDocumentDescriptor(CoreSession session, String uuid, DocumentDescriptor dd)
093            {
094        for (IndexingAdapter adapter : getMergedAdapters()) {
095            dd = adapter.adaptDocumentDescriptor(session, uuid, dd);
096        }
097        return dd;
098    }
099
100    public WsACE[] adaptDocumentACL(CoreSession session, String uuid, WsACE[] aces) {
101        for (IndexingAdapter adapter : getMergedAdapters()) {
102            aces = adapter.adaptDocumentACL(session, uuid, aces);
103        }
104        return aces;
105    }
106
107    public WsACE[] adaptDocumentLocalACL(CoreSession session, String uuid, WsACE[] aces) {
108        for (IndexingAdapter adapter : getMergedAdapters()) {
109            aces = adapter.adaptDocumentLocalACL(session, uuid, aces);
110        }
111        return aces;
112    }
113
114    public DocumentBlob[] adaptDocumentBlobs(CoreSession session, String uuid, DocumentBlob[] blobs)
115            {
116        for (IndexingAdapter adapter : getMergedAdapters()) {
117            blobs = adapter.adaptDocumentBlobs(session, uuid, blobs);
118        }
119        return blobs;
120    }
121
122    public DocumentProperty[] adaptDocumentNoBlobProperties(CoreSession session, String uuid,
123            DocumentProperty[] properties) {
124        for (IndexingAdapter adapter : getMergedAdapters()) {
125            properties = adapter.adaptDocumentNoBlobProperties(session, uuid, properties);
126        }
127        return properties;
128    }
129
130    public DocumentProperty[] adaptDocumentProperties(CoreSession session, String uuid, DocumentProperty[] properties)
131            {
132        for (IndexingAdapter adapter : getMergedAdapters()) {
133            properties = adapter.adaptDocumentProperties(session, uuid, properties);
134        }
135        return properties;
136    }
137
138    protected List<IndexingAdapter> getMergedAdapters() {
139        if (mergedAdapters.isEmpty()) {
140            synchronized (this) {
141                Map<String, IndexingAdapterDescriptor> descriptorByClass = new HashMap<String, IndexingAdapterDescriptor>();
142                // merge registered contribution by class names
143                for (IndexingAdapterDescriptor descriptor : registeredAdapters) {
144                    descriptorByClass.put(descriptor.getClassName(), descriptor);
145                }
146
147                // sort merge contributions by order
148                List<IndexingAdapterDescriptor> mergedDescriptors = new ArrayList<IndexingAdapterDescriptor>(
149                        descriptorByClass.values());
150                Collections.sort(mergedDescriptors);
151
152                // filter out disabled adapters and collect the instances of the
153                // remaining sorted contributions
154                for (IndexingAdapterDescriptor descriptor : mergedDescriptors) {
155                    if (descriptor.isEnabled()) {
156                        mergedAdapters.add(descriptor.getAdapterInstance());
157                    }
158                }
159            }
160        }
161        return mergedAdapters;
162    }
163
164    public boolean useDownloadUrlForBlob() {
165        return useDownloadUrl;
166    }
167}