/* * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others. * * 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. * * Contributors: * Florent Guillaume */ package org.nuxeo.ecm.core.blob; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.nuxeo.ecm.core.api.Blob; import org.nuxeo.ecm.core.api.NuxeoException; import org.nuxeo.ecm.core.blob.binary.BinaryBlobProvider; import org.nuxeo.ecm.core.blob.binary.BinaryManager; import org.nuxeo.runtime.model.ComponentContext; import org.nuxeo.runtime.model.ComponentInstance; import org.nuxeo.runtime.model.DefaultComponent; import org.nuxeo.runtime.model.SimpleContributionRegistry; /** * Implementation of the service managing the storage and retrieval of {@link Blob}s, through internally-registered * {@link BlobProvider}s. * * @since 7.2 */ public class BlobManagerComponent extends DefaultComponent implements BlobManager { protected static final String XP = "configuration"; protected BlobProviderDescriptorRegistry blobProviderDescriptorsRegistry = new BlobProviderDescriptorRegistry(); protected Map<String, BlobProvider> blobProviders = new HashMap<>(); protected static class BlobProviderDescriptorRegistry extends SimpleContributionRegistry<BlobProviderDescriptor> { @Override public String getContributionId(BlobProviderDescriptor contrib) { return contrib.name; } @Override public BlobProviderDescriptor clone(BlobProviderDescriptor orig) { return new BlobProviderDescriptor(orig); } @Override public void merge(BlobProviderDescriptor src, BlobProviderDescriptor dst) { dst.merge(src); } @Override public boolean isSupportingMerge() { return true; } public void clear() { currentContribs.clear(); } public BlobProviderDescriptor getBlobProviderDescriptor(String id) { return getCurrentContribution(id); } } @Override public void deactivate(ComponentContext context) { blobProviderDescriptorsRegistry.clear(); // close each blob provider for (BlobProvider blobProvider : blobProviders.values()) { blobProvider.close(); } blobProviders.clear(); } @Override public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { if (XP.equals(extensionPoint)) { if (contribution instanceof BlobProviderDescriptor) { registerBlobProvider((BlobProviderDescriptor) contribution); } else { throw new NuxeoException("Invalid descriptor: " + contribution.getClass()); } } else { throw new NuxeoException("Invalid extension point: " + extensionPoint); } } @Override public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { if (XP.equals(extensionPoint)) { if (contribution instanceof BlobProviderDescriptor) { unregisterBlobProvider((BlobProviderDescriptor) contribution); } } } // public for tests public void registerBlobProvider(BlobProviderDescriptor descr) { closeOldBlobProvider(descr.name); blobProviderDescriptorsRegistry.addContribution(descr); // lookup now to have immediate feedback on eror getBlobProvider(descr.name); } // public for tests public void unregisterBlobProvider(BlobProviderDescriptor descr) { closeOldBlobProvider(descr.name); blobProviderDescriptorsRegistry.removeContribution(descr); } /** * We're about to change something about a contributed blob provider. Close the old one. */ protected synchronized void closeOldBlobProvider(String id) { BlobProvider blobProvider = blobProviders.remove(id); if (blobProvider != null) { blobProvider.close(); } } @Override public synchronized BlobProvider getBlobProvider(String providerId) { BlobProvider blobProvider = blobProviders.get(providerId); if (blobProvider == null) { BlobProviderDescriptor descr = blobProviderDescriptorsRegistry.getBlobProviderDescriptor(providerId); if (descr == null) { return null; } Class<?> klass = descr.klass; Map<String, String> properties = descr.properties; try { if (BlobProvider.class.isAssignableFrom(klass)) { @SuppressWarnings("unchecked") Class<? extends BlobProvider> blobProviderClass = (Class<? extends BlobProvider>) klass; blobProvider = blobProviderClass.newInstance(); } else if (BinaryManager.class.isAssignableFrom(klass)) { @SuppressWarnings("unchecked") Class<? extends BinaryManager> binaryManagerClass = (Class<? extends BinaryManager>) klass; BinaryManager binaryManager = binaryManagerClass.newInstance(); blobProvider = new BinaryBlobProvider(binaryManager); } else { throw new RuntimeException("Unknown class for blob provider: " + klass); } } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } try { blobProvider.initialize(providerId, properties); } catch (IOException e) { throw new RuntimeException(e); } blobProviders.put(providerId, blobProvider); } return blobProvider; } @Override public BlobProvider getBlobProvider(Blob blob) { if (!(blob instanceof ManagedBlob)) { return null; } ManagedBlob managedBlob = (ManagedBlob) blob; return getBlobProvider(managedBlob.getProviderId()); } @Override public InputStream getStream(Blob blob) throws IOException { BlobProvider blobProvider = getBlobProvider(blob); if (blobProvider == null) { return null; } return blobProvider.getStream((ManagedBlob) blob); } @Override public InputStream getThumbnail(Blob blob) throws IOException { BlobProvider blobProvider = getBlobProvider(blob); if (blobProvider == null) { return null; } return blobProvider.getThumbnail((ManagedBlob) blob); } @Override public URI getURI(Blob blob, UsageHint hint, HttpServletRequest servletRequest) throws IOException { BlobProvider blobProvider = getBlobProvider(blob); if (blobProvider == null) { return null; } return blobProvider.getURI((ManagedBlob) blob, hint, servletRequest); } @Override public Map<String, URI> getAvailableConversions(Blob blob, UsageHint hint) throws IOException { BlobProvider blobProvider = getBlobProvider(blob); if (blobProvider == null) { return Collections.emptyMap(); } return blobProvider.getAvailableConversions((ManagedBlob) blob, hint); } @Override public Map<String, BlobProvider> getBlobProviders() { return blobProviders; } }