001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Florent Guillaume 011 * Laurent Doguin 012 */ 013package org.nuxeo.ecm.core.versioning; 014 015import java.io.Serializable; 016import java.util.ArrayDeque; 017import java.util.Deque; 018import java.util.LinkedHashMap; 019import java.util.List; 020import java.util.Map; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024import org.nuxeo.ecm.core.api.DocumentModel; 025import org.nuxeo.ecm.core.api.VersioningOption; 026import org.nuxeo.ecm.core.model.Document; 027import org.nuxeo.runtime.model.ComponentContext; 028import org.nuxeo.runtime.model.ComponentInstance; 029import org.nuxeo.runtime.model.DefaultComponent; 030import org.nuxeo.runtime.model.SimpleContributionRegistry; 031 032/** 033 * Versioning service component and implementation. 034 */ 035public class VersioningComponent extends DefaultComponent implements VersioningService { 036 037 private static final Log log = LogFactory.getLog(VersioningComponent.class); 038 039 public static final String VERSIONING_SERVICE_XP = "versioningService"; 040 041 public static final String VERSIONING_RULE_XP = "versioningRules"; 042 043 protected static final StandardVersioningService STANDARD_VERSIONING_SERVICE = new StandardVersioningService(); 044 045 protected Map<VersioningServiceDescriptor, VersioningService> versioningServices = new LinkedHashMap<>(); 046 047 protected VersioningRuleRegistry versioningRulesRegistry = new VersioningRuleRegistry(); 048 049 protected static class VersioningRuleRegistry extends SimpleContributionRegistry<VersioningRuleDescriptor> { 050 051 @Override 052 public String getContributionId(VersioningRuleDescriptor contrib) { 053 return contrib.getTypeName(); 054 } 055 056 @Override 057 public VersioningRuleDescriptor clone(VersioningRuleDescriptor orig) { 058 return new VersioningRuleDescriptor(orig); 059 } 060 061 @Override 062 public void merge(VersioningRuleDescriptor src, VersioningRuleDescriptor dst) { 063 dst.merge(src); 064 } 065 066 @Override 067 public boolean isSupportingMerge() { 068 return true; 069 } 070 071 @Override 072 public void contributionUpdated(String id, VersioningRuleDescriptor contrib, 073 VersioningRuleDescriptor newOrigContrib) { 074 if (contrib.isEnabled()) { 075 currentContribs.put(id, contrib); 076 } else { 077 currentContribs.remove(id); 078 } 079 } 080 081 public void clear() { 082 currentContribs.clear(); 083 } 084 085 public Map<String, VersioningRuleDescriptor> getVersioningRuleDescriptors() { 086 return currentContribs; 087 } 088 } 089 090 protected Deque<DefaultVersioningRuleDescriptor> defaultVersioningRuleList = new ArrayDeque<>(); 091 092 // public for tests 093 public VersioningService service = STANDARD_VERSIONING_SERVICE; 094 095 protected ComponentContext context; 096 097 @Override 098 public void activate(ComponentContext context) { 099 this.context = context; 100 } 101 102 @Override 103 public void deactivate(ComponentContext context) { 104 this.context = null; 105 } 106 107 @Override 108 public void registerContribution(Object contrib, String point, ComponentInstance contributor) { 109 if (VERSIONING_SERVICE_XP.equals(point)) { 110 registerVersioningService((VersioningServiceDescriptor) contrib); 111 } else if (VERSIONING_RULE_XP.equals(point)) { 112 if (contrib instanceof VersioningRuleDescriptor) { 113 registerVersioningRule((VersioningRuleDescriptor) contrib); 114 } else if (contrib instanceof DefaultVersioningRuleDescriptor) { 115 registerDefaultVersioningRule((DefaultVersioningRuleDescriptor) contrib); 116 } else { 117 throw new RuntimeException("Unknown contribution to " + point + ": " + contrib.getClass()); 118 } 119 } else { 120 throw new RuntimeException("Unknown extension point: " + point); 121 } 122 } 123 124 @Override 125 public void unregisterContribution(Object contrib, String point, ComponentInstance contributor) { 126 if (VERSIONING_SERVICE_XP.equals(point)) { 127 unregisterVersioningService((VersioningServiceDescriptor) contrib); 128 } else if (VERSIONING_RULE_XP.equals(point)) { 129 if (contrib instanceof VersioningRuleDescriptor) { 130 unregisterVersioningRule((VersioningRuleDescriptor) contrib); 131 } else if (contrib instanceof DefaultVersioningRuleDescriptor) { 132 unregisterDefaultVersioningRule((DefaultVersioningRuleDescriptor) contrib); 133 } 134 } 135 } 136 137 protected void registerVersioningService(VersioningServiceDescriptor contrib) { 138 String klass = contrib.className; 139 try { 140 VersioningService vs = (VersioningService) context.getRuntimeContext().loadClass(klass).newInstance(); 141 versioningServices.put(contrib, vs); 142 } catch (ReflectiveOperationException e) { 143 throw new RuntimeException("Failed to instantiate: " + klass, e); 144 } 145 log.info("Registered versioning service: " + klass); 146 recompute(); 147 } 148 149 protected void unregisterVersioningService(VersioningServiceDescriptor contrib) { 150 versioningServices.remove(contrib); 151 log.info("Unregistered versioning service: " + contrib.className); 152 recompute(); 153 } 154 155 protected void registerVersioningRule(VersioningRuleDescriptor contrib) { 156 versioningRulesRegistry.addContribution(contrib); 157 log.info("Registered versioning rule: " + contrib.getTypeName()); 158 recompute(); 159 } 160 161 protected void unregisterVersioningRule(VersioningRuleDescriptor contrib) { 162 versioningRulesRegistry.removeContribution(contrib); 163 log.info("Unregistered versioning rule: " + contrib.getTypeName()); 164 recompute(); 165 } 166 167 protected void registerDefaultVersioningRule(DefaultVersioningRuleDescriptor contrib) { 168 // could use a linked set instead, but given the size a linked list is enough 169 defaultVersioningRuleList.add(contrib); 170 recompute(); 171 } 172 173 protected void unregisterDefaultVersioningRule(DefaultVersioningRuleDescriptor contrib) { 174 defaultVersioningRuleList.remove(contrib); 175 recompute(); 176 } 177 178 protected void recompute() { 179 VersioningService versioningService = STANDARD_VERSIONING_SERVICE; 180 for (VersioningService vs : versioningServices.values()) { 181 versioningService = vs; 182 } 183 if (versioningService instanceof ExtendableVersioningService) { 184 ExtendableVersioningService vs = (ExtendableVersioningService) versioningService; 185 vs.setVersioningRules(getVersioningRules()); 186 vs.setDefaultVersioningRule(getDefaultVersioningRule()); 187 } 188 this.service = versioningService; 189 } 190 191 protected Map<String, VersioningRuleDescriptor> getVersioningRules() { 192 return versioningRulesRegistry.getVersioningRuleDescriptors(); 193 } 194 195 protected DefaultVersioningRuleDescriptor getDefaultVersioningRule() { 196 return defaultVersioningRuleList.peekLast(); 197 } 198 199 @Override 200 public String getVersionLabel(DocumentModel doc) { 201 return service.getVersionLabel(doc); 202 } 203 204 @Override 205 public void doPostCreate(Document doc, Map<String, Serializable> options) { 206 service.doPostCreate(doc, options); 207 } 208 209 @Override 210 public List<VersioningOption> getSaveOptions(DocumentModel docModel) { 211 return service.getSaveOptions(docModel); 212 } 213 214 @Override 215 public boolean isPreSaveDoingCheckOut(Document doc, boolean isDirty, VersioningOption option, 216 Map<String, Serializable> options) { 217 return service.isPreSaveDoingCheckOut(doc, isDirty, option, options); 218 } 219 220 @Override 221 public VersioningOption doPreSave(Document doc, boolean isDirty, VersioningOption option, String checkinComment, 222 Map<String, Serializable> options) { 223 return service.doPreSave(doc, isDirty, option, checkinComment, options); 224 } 225 226 @Override 227 public boolean isPostSaveDoingCheckIn(Document doc, VersioningOption option, Map<String, Serializable> options) { 228 return service.isPostSaveDoingCheckIn(doc, option, options); 229 } 230 231 @Override 232 public Document doPostSave(Document doc, VersioningOption option, String checkinComment, 233 Map<String, Serializable> options) { 234 return service.doPostSave(doc, option, checkinComment, options); 235 } 236 237 @Override 238 public Document doCheckIn(Document doc, VersioningOption option, String checkinComment) { 239 return service.doCheckIn(doc, option, checkinComment); 240 } 241 242 @Override 243 public void doCheckOut(Document doc) { 244 service.doCheckOut(doc); 245 } 246}