001/* 002 * (C) Copyright 2006-2017 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 * Contributors: 017 * Dragos Mihalache 018 */ 019package org.nuxeo.ecm.core.uidgen; 020 021import java.util.HashMap; 022import java.util.LinkedHashMap; 023import java.util.Map; 024 025import org.apache.commons.logging.Log; 026import org.apache.commons.logging.LogFactory; 027import org.nuxeo.ecm.core.api.DocumentModel; 028import org.nuxeo.ecm.core.api.model.PropertyNotFoundException; 029import org.nuxeo.runtime.api.Framework; 030import org.nuxeo.runtime.model.ComponentContext; 031import org.nuxeo.runtime.model.DefaultComponent; 032import org.nuxeo.runtime.model.Extension; 033 034/** 035 * Service that writes MetaData. 036 */ 037public class UIDGeneratorComponent extends DefaultComponent implements UIDGeneratorService { 038 039 public static final String ID = "org.nuxeo.ecm.core.uidgen.UIDGeneratorService"; 040 041 public static final String UID_GENERATORS_EXTENSION_POINT = "generators"; 042 043 public static final String SEQUENCERS_EXTENSION_POINT = "sequencers"; 044 045 /** 046 * Extension point is deprecated should be removed - preserved for now only for startup warnings. 047 */ 048 public static final String EXTENSION_POINT_SEQUENCER_FACTORY = "sequencerFactory"; 049 050 private static final Log log = LogFactory.getLog(UIDGeneratorComponent.class); 051 052 protected final Map<String, UIDGenerator> generators = new HashMap<>(); 053 054 protected final Map<String, UIDSequencer> sequencers = new HashMap<>(); 055 056 protected final LinkedHashMap<String, UIDSequencerProviderDescriptor> sequencerContribs = new LinkedHashMap<>(); 057 058 protected String defaultSequencer; 059 060 @Override 061 public void start(ComponentContext context) { 062 for (String name : sequencers.keySet()) { 063 sequencers.get(name).init(); 064 } 065 } 066 067 @Override 068 public void stop(ComponentContext context) { 069 for (String name : sequencers.keySet()) { 070 sequencers.get(name).dispose(); 071 } 072 } 073 074 @Override 075 public void registerExtension(Extension extension) { 076 super.registerExtension(extension); 077 final String extPoint = extension.getExtensionPoint(); 078 if (UID_GENERATORS_EXTENSION_POINT.equals(extPoint)) { 079 log.info("register contributions for extension point: " + UID_GENERATORS_EXTENSION_POINT); 080 final Object[] contribs = extension.getContributions(); 081 registerGenerators(extension, contribs); 082 } else if (SEQUENCERS_EXTENSION_POINT.equals(extPoint)) { 083 log.info("register contributions for extension point: " + SEQUENCERS_EXTENSION_POINT); 084 final Object[] contribs = extension.getContributions(); 085 registerSequencers(extension, contribs); 086 computeDefault(); 087 } else if (EXTENSION_POINT_SEQUENCER_FACTORY.equals(extPoint)) { 088 String msg = "UIDSequencer factory no more supported from version 5.4. Faulty component: " 089 + extension.getComponent(); 090 Framework.getRuntime().getMessageHandler().addWarning(msg); 091 log.error(msg); 092 } else { 093 log.warn("extension not handled: " + extPoint); 094 } 095 } 096 097 @Override 098 public void unregisterExtension(Extension extension) { 099 final String extPoint = extension.getExtensionPoint(); 100 if (UID_GENERATORS_EXTENSION_POINT.equals(extPoint)) { 101 log.info("unregister contributions for extension point: " + UID_GENERATORS_EXTENSION_POINT); 102 // final Object[] contribs = extension.getContributions(); 103 // unregisterGenerators(extension, contribs); 104 } else if (SEQUENCERS_EXTENSION_POINT.equals(extPoint)) { 105 log.info("unregister contributions for extension point: " + SEQUENCERS_EXTENSION_POINT); 106 final Object[] contribs = extension.getContributions(); 107 unregisterSequencers(extension, contribs); 108 computeDefault(); 109 } else { 110 log.warn("extension not handled: " + extPoint); 111 } 112 super.unregisterExtension(extension); 113 } 114 115 protected void computeDefault() { 116 String def = null; 117 String last = null; 118 for (UIDSequencerProviderDescriptor contrib : sequencerContribs.values()) { 119 if (contrib.isIsdefault()) { 120 def = contrib.getName(); 121 } 122 last = contrib.getName(); 123 } 124 125 if (def == null) { 126 def = last; 127 } 128 defaultSequencer = def; 129 } 130 131 protected void registerSequencers(Extension extension, final Object[] contribs) { 132 for (Object contrib : contribs) { 133 UIDSequencerProviderDescriptor seqDescriptor = (UIDSequencerProviderDescriptor) contrib; 134 String name = seqDescriptor.getName(); 135 136 try { 137 UIDSequencer seq = seqDescriptor.getSequencer(); 138 if (seq != null) { 139 seq.setName(name); 140 } 141 sequencers.put(name, seq); 142 sequencerContribs.put(name, seqDescriptor); 143 } catch (Exception e) { 144 log.error("Unable to create UIDSequencer with name " + name, e); 145 } 146 } 147 } 148 149 protected void unregisterSequencers(Extension extension, final Object[] contribs) { 150 for (Object contrib : contribs) { 151 UIDSequencerProviderDescriptor seqDescriptor = (UIDSequencerProviderDescriptor) contrib; 152 String name = seqDescriptor.getName(); 153 sequencers.remove(name); 154 sequencerContribs.remove(name); 155 } 156 } 157 158 protected void registerGenerators(Extension extension, final Object[] contribs) { 159 160 // read the list of generators 161 for (Object contrib : contribs) { 162 final UIDGeneratorDescriptor generatorDescriptor = (UIDGeneratorDescriptor) contrib; 163 final String generatorName = generatorDescriptor.getName(); 164 165 UIDGenerator generator; 166 try { 167 generator = (UIDGenerator) extension.getContext() 168 .loadClass(generatorDescriptor.getClassName()) 169 .newInstance(); 170 } catch (ReflectiveOperationException e) { 171 throw new RuntimeException(e); 172 } 173 174 final String[] propNames = generatorDescriptor.getPropertyNames(); 175 if (propNames.length == 0) { 176 log.error("no property name defined on generator " + generatorName); 177 } 178 // set the property name on generator 179 generator.setPropertyNames(propNames); 180 181 // Register Generator for DocTypes and property name 182 final String[] docTypes = generatorDescriptor.getDocTypes(); 183 registerGeneratorForDocTypes(generator, docTypes); 184 185 log.info("registered UID generator: " + generatorName); 186 } 187 } 188 189 /** 190 * Registers given UIDGenerator for the given document types. If there is already a generator registered for one of 191 * document type it will be discarded (and replaced with the new generator). 192 */ 193 private void registerGeneratorForDocTypes(final UIDGenerator generator, final String[] docTypes) { 194 195 for (String docType : docTypes) { 196 final UIDGenerator previous = generators.put(docType, generator); 197 if (previous != null) { 198 log.info("Overwriting generator: " + previous.getClass() + " for docType: " + docType); 199 } 200 log.info("Registered generator: " + generator.getClass() + " for docType: " + docType); 201 } 202 } 203 204 /** 205 * Returns the uid generator to use for this document. 206 * <p> 207 * Choice is made following the document type and the generator configuration. 208 */ 209 @Override 210 public UIDGenerator getUIDGeneratorFor(DocumentModel doc) { 211 final String docTypeName = doc.getType(); 212 final UIDGenerator generator = generators.get(docTypeName); 213 214 if (generator == null) { 215 log.debug("No UID Generator defined for doc type: " + docTypeName); 216 return null; 217 } 218 // TODO maybe maintain an initialization state for generators 219 // so the next call could be avoided (for each request) 220 generator.setSequencer(Framework.getService(UIDSequencer.class)); 221 222 return generator; 223 } 224 225 /** 226 * Creates a new UID for the given doc and sets the field configured in the generator component with this value. 227 */ 228 @Override 229 public void setUID(DocumentModel doc) throws PropertyNotFoundException { 230 final UIDGenerator generator = getUIDGeneratorFor(doc); 231 if (generator != null) { 232 generator.setUID(doc); 233 } 234 } 235 236 /** 237 * @return a new UID for the given document 238 */ 239 @Override 240 public String createUID(DocumentModel doc) { 241 final UIDGenerator generator = getUIDGeneratorFor(doc); 242 if (generator == null) { 243 return null; 244 } else { 245 return generator.createUID(doc); 246 } 247 } 248 249 @Override 250 public <T> T getAdapter(Class<T> adapter) { 251 if (UIDSequencer.class.isAssignableFrom(adapter)) { 252 return adapter.cast(getSequencer()); 253 } 254 if (UIDGeneratorService.class.isAssignableFrom(adapter)) { 255 return adapter.cast(this); 256 } 257 return null; 258 } 259 260 @Override 261 public UIDSequencer getSequencer() { 262 return getSequencer(null); 263 } 264 265 @Override 266 public UIDSequencer getSequencer(String name) { 267 if (name == null) { 268 name = defaultSequencer; 269 } 270 return sequencers.get(name); 271 } 272 273}