001/* 002 * (C) Copyright 2015 Nuxeo SA (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 * Contributors: 017 * Florent Guillaume 018 */ 019package org.nuxeo.ecm.core.blob; 020 021import java.io.IOException; 022import java.io.InputStream; 023import java.net.URI; 024import java.util.Collections; 025import java.util.HashMap; 026import java.util.Map; 027 028import javax.servlet.http.HttpServletRequest; 029 030import org.nuxeo.ecm.core.api.Blob; 031import org.nuxeo.ecm.core.api.NuxeoException; 032import org.nuxeo.ecm.core.blob.binary.BinaryBlobProvider; 033import org.nuxeo.ecm.core.blob.binary.BinaryManager; 034import org.nuxeo.runtime.model.ComponentContext; 035import org.nuxeo.runtime.model.ComponentInstance; 036import org.nuxeo.runtime.model.DefaultComponent; 037import org.nuxeo.runtime.model.SimpleContributionRegistry; 038 039/** 040 * Implementation of the service managing the storage and retrieval of {@link Blob}s, through internally-registered 041 * {@link BlobProvider}s. 042 * 043 * @since 7.2 044 */ 045public class BlobManagerComponent extends DefaultComponent implements BlobManager { 046 047 protected static final String XP = "configuration"; 048 049 protected BlobProviderDescriptorRegistry blobProviderDescriptorsRegistry = new BlobProviderDescriptorRegistry(); 050 051 protected Map<String, BlobProvider> blobProviders = new HashMap<>(); 052 053 protected static class BlobProviderDescriptorRegistry extends SimpleContributionRegistry<BlobProviderDescriptor> { 054 055 @Override 056 public String getContributionId(BlobProviderDescriptor contrib) { 057 return contrib.name; 058 } 059 060 @Override 061 public BlobProviderDescriptor clone(BlobProviderDescriptor orig) { 062 return new BlobProviderDescriptor(orig); 063 } 064 065 @Override 066 public void merge(BlobProviderDescriptor src, BlobProviderDescriptor dst) { 067 dst.merge(src); 068 } 069 070 @Override 071 public boolean isSupportingMerge() { 072 return true; 073 } 074 075 public void clear() { 076 currentContribs.clear(); 077 } 078 079 public BlobProviderDescriptor getBlobProviderDescriptor(String id) { 080 return getCurrentContribution(id); 081 } 082 } 083 084 @Override 085 public void deactivate(ComponentContext context) { 086 blobProviderDescriptorsRegistry.clear(); 087 // close each blob provider 088 for (BlobProvider blobProvider : blobProviders.values()) { 089 blobProvider.close(); 090 } 091 blobProviders.clear(); 092 } 093 094 @Override 095 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 096 if (XP.equals(extensionPoint)) { 097 if (contribution instanceof BlobProviderDescriptor) { 098 registerBlobProvider((BlobProviderDescriptor) contribution); 099 } else { 100 throw new NuxeoException("Invalid descriptor: " + contribution.getClass()); 101 } 102 } else { 103 throw new NuxeoException("Invalid extension point: " + extensionPoint); 104 } 105 } 106 107 @Override 108 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 109 if (XP.equals(extensionPoint)) { 110 if (contribution instanceof BlobProviderDescriptor) { 111 unregisterBlobProvider((BlobProviderDescriptor) contribution); 112 } 113 } 114 } 115 116 // public for tests 117 public void registerBlobProvider(BlobProviderDescriptor descr) { 118 closeOldBlobProvider(descr.name); 119 blobProviderDescriptorsRegistry.addContribution(descr); 120 // lookup now to have immediate feedback on eror 121 getBlobProvider(descr.name); 122 } 123 124 // public for tests 125 public void unregisterBlobProvider(BlobProviderDescriptor descr) { 126 closeOldBlobProvider(descr.name); 127 blobProviderDescriptorsRegistry.removeContribution(descr); 128 } 129 130 /** 131 * We're about to change something about a contributed blob provider. Close the old one. 132 */ 133 protected synchronized void closeOldBlobProvider(String id) { 134 BlobProvider blobProvider = blobProviders.remove(id); 135 if (blobProvider != null) { 136 blobProvider.close(); 137 } 138 } 139 140 @Override 141 public synchronized BlobProvider getBlobProvider(String providerId) { 142 BlobProvider blobProvider = blobProviders.get(providerId); 143 if (blobProvider == null) { 144 BlobProviderDescriptor descr = blobProviderDescriptorsRegistry.getBlobProviderDescriptor(providerId); 145 if (descr == null) { 146 return null; 147 } 148 Class<?> klass = descr.klass; 149 Map<String, String> properties = descr.properties; 150 try { 151 if (BlobProvider.class.isAssignableFrom(klass)) { 152 @SuppressWarnings("unchecked") 153 Class<? extends BlobProvider> blobProviderClass = (Class<? extends BlobProvider>) klass; 154 blobProvider = blobProviderClass.newInstance(); 155 } else if (BinaryManager.class.isAssignableFrom(klass)) { 156 @SuppressWarnings("unchecked") 157 Class<? extends BinaryManager> binaryManagerClass = (Class<? extends BinaryManager>) klass; 158 BinaryManager binaryManager = binaryManagerClass.newInstance(); 159 blobProvider = new BinaryBlobProvider(binaryManager); 160 } else { 161 throw new RuntimeException("Unknown class for blob provider: " + klass); 162 } 163 } catch (ReflectiveOperationException e) { 164 throw new RuntimeException(e); 165 } 166 try { 167 blobProvider.initialize(providerId, properties); 168 } catch (IOException e) { 169 throw new RuntimeException(e); 170 } 171 blobProviders.put(providerId, blobProvider); 172 } 173 return blobProvider; 174 } 175 176 @Override 177 public BlobProvider getBlobProvider(Blob blob) { 178 if (!(blob instanceof ManagedBlob)) { 179 return null; 180 } 181 ManagedBlob managedBlob = (ManagedBlob) blob; 182 return getBlobProvider(managedBlob.getProviderId()); 183 } 184 185 @Override 186 public InputStream getStream(Blob blob) throws IOException { 187 BlobProvider blobProvider = getBlobProvider(blob); 188 if (blobProvider == null) { 189 return null; 190 } 191 return blobProvider.getStream((ManagedBlob) blob); 192 } 193 194 @Override 195 public InputStream getThumbnail(Blob blob) throws IOException { 196 BlobProvider blobProvider = getBlobProvider(blob); 197 if (blobProvider == null) { 198 return null; 199 } 200 return blobProvider.getThumbnail((ManagedBlob) blob); 201 } 202 203 @Override 204 public URI getURI(Blob blob, UsageHint hint, HttpServletRequest servletRequest) throws IOException { 205 BlobProvider blobProvider = getBlobProvider(blob); 206 if (blobProvider == null) { 207 return null; 208 } 209 return blobProvider.getURI((ManagedBlob) blob, hint, servletRequest); 210 } 211 212 @Override 213 public Map<String, URI> getAvailableConversions(Blob blob, UsageHint hint) throws IOException { 214 BlobProvider blobProvider = getBlobProvider(blob); 215 if (blobProvider == null) { 216 return Collections.emptyMap(); 217 } 218 return blobProvider.getAvailableConversions((ManagedBlob) blob, hint); 219 } 220 221 @Override 222 public Map<String, BlobProvider> getBlobProviders() { 223 return blobProviders; 224 } 225 226}