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