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 if (seqDescriptor.isEnabled()) { 138 UIDSequencer seq = seqDescriptor.getSequencer(); 139 if (seq != null) { 140 seq.setName(name); 141 } 142 sequencers.put(name, seq); 143 sequencerContribs.put(name, seqDescriptor); 144 145 } else { 146 log.info(String.format("Sequencer %s is disabled.", name)); 147 } 148 } catch (Exception e) { 149 log.error("Unable to create UIDSequencer with name " + name, e); 150 } 151 } 152 } 153 154 protected void unregisterSequencers(Extension extension, final Object[] contribs) { 155 for (Object contrib : contribs) { 156 UIDSequencerProviderDescriptor seqDescriptor = (UIDSequencerProviderDescriptor) contrib; 157 String name = seqDescriptor.getName(); 158 sequencers.remove(name); 159 sequencerContribs.remove(name); 160 } 161 } 162 163 protected void registerGenerators(Extension extension, final Object[] contribs) { 164 165 // read the list of generators 166 for (Object contrib : contribs) { 167 final UIDGeneratorDescriptor generatorDescriptor = (UIDGeneratorDescriptor) contrib; 168 final String generatorName = generatorDescriptor.getName(); 169 170 UIDGenerator generator; 171 try { 172 generator = (UIDGenerator) extension.getContext() 173 .loadClass(generatorDescriptor.getClassName()) 174 .newInstance(); 175 } catch (ReflectiveOperationException e) { 176 throw new RuntimeException(e); 177 } 178 179 final String[] propNames = generatorDescriptor.getPropertyNames(); 180 if (propNames.length == 0) { 181 log.error("no property name defined on generator " + generatorName); 182 } 183 // set the property name on generator 184 generator.setPropertyNames(propNames); 185 186 // Register Generator for DocTypes and property name 187 final String[] docTypes = generatorDescriptor.getDocTypes(); 188 registerGeneratorForDocTypes(generator, docTypes); 189 190 log.info("registered UID generator: " + generatorName); 191 } 192 } 193 194 /** 195 * Registers given UIDGenerator for the given document types. If there is already a generator registered for one of 196 * document type it will be discarded (and replaced with the new generator). 197 */ 198 private void registerGeneratorForDocTypes(final UIDGenerator generator, final String[] docTypes) { 199 200 for (String docType : docTypes) { 201 final UIDGenerator previous = generators.put(docType, generator); 202 if (previous != null) { 203 log.info("Overwriting generator: " + previous.getClass() + " for docType: " + docType); 204 } 205 log.info("Registered generator: " + generator.getClass() + " for docType: " + docType); 206 } 207 } 208 209 /** 210 * Returns the uid generator to use for this document. 211 * <p> 212 * Choice is made following the document type and the generator configuration. 213 */ 214 @Override 215 public UIDGenerator getUIDGeneratorFor(DocumentModel doc) { 216 final String docTypeName = doc.getType(); 217 final UIDGenerator generator = generators.get(docTypeName); 218 219 if (generator == null) { 220 log.debug("No UID Generator defined for doc type: " + docTypeName); 221 return null; 222 } 223 // TODO maybe maintain an initialization state for generators 224 // so the next call could be avoided (for each request) 225 generator.setSequencer(Framework.getService(UIDSequencer.class)); 226 227 return generator; 228 } 229 230 /** 231 * Creates a new UID for the given doc and sets the field configured in the generator component with this value. 232 */ 233 @Override 234 public void setUID(DocumentModel doc) throws PropertyNotFoundException { 235 final UIDGenerator generator = getUIDGeneratorFor(doc); 236 if (generator != null) { 237 generator.setUID(doc); 238 } 239 } 240 241 /** 242 * @return a new UID for the given document 243 */ 244 @Override 245 public String createUID(DocumentModel doc) { 246 final UIDGenerator generator = getUIDGeneratorFor(doc); 247 if (generator == null) { 248 return null; 249 } else { 250 return generator.createUID(doc); 251 } 252 } 253 254 @Override 255 public <T> T getAdapter(Class<T> adapter) { 256 if (UIDSequencer.class.isAssignableFrom(adapter)) { 257 return adapter.cast(getSequencer()); 258 } 259 if (UIDGeneratorService.class.isAssignableFrom(adapter)) { 260 return adapter.cast(this); 261 } 262 return null; 263 } 264 265 @Override 266 public UIDSequencer getSequencer() { 267 return getSequencer(null); 268 } 269 270 @Override 271 public UIDSequencer getSequencer(String name) { 272 if (name == null) { 273 name = defaultSequencer; 274 } 275 return sequencers.get(name); 276 } 277 278}