001/* 002 * (C) Copyright 2006-2010 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 * Thierry Delprat 018 */ 019package org.nuxeo.apidoc.snapshot; 020 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.OutputStream; 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.Collections; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030 031import javax.servlet.http.HttpServletRequest; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035import org.nuxeo.apidoc.api.BundleGroup; 036import org.nuxeo.apidoc.api.BundleInfo; 037import org.nuxeo.apidoc.api.ComponentInfo; 038import org.nuxeo.apidoc.api.ExtensionInfo; 039import org.nuxeo.apidoc.api.ExtensionPointInfo; 040import org.nuxeo.apidoc.api.NuxeoArtifact; 041import org.nuxeo.apidoc.api.OperationInfo; 042import org.nuxeo.apidoc.api.ServiceInfo; 043import org.nuxeo.apidoc.introspection.RuntimeSnapshot; 044import org.nuxeo.apidoc.repository.RepositoryDistributionSnapshot; 045import org.nuxeo.apidoc.repository.SnapshotPersister; 046import org.nuxeo.ecm.core.api.CoreSession; 047import org.nuxeo.ecm.core.api.DocumentModel; 048import org.nuxeo.ecm.core.api.DocumentRef; 049import org.nuxeo.ecm.core.api.NuxeoException; 050import org.nuxeo.ecm.core.api.PathRef; 051import org.nuxeo.ecm.core.io.DocumentPipe; 052import org.nuxeo.ecm.core.io.DocumentReader; 053import org.nuxeo.ecm.core.io.DocumentWriter; 054import org.nuxeo.ecm.core.io.impl.DocumentPipeImpl; 055import org.nuxeo.ecm.core.io.impl.plugins.DocumentModelWriter; 056import org.nuxeo.ecm.core.io.impl.plugins.DocumentTreeReader; 057import org.nuxeo.ecm.core.io.impl.plugins.NuxeoArchiveReader; 058import org.nuxeo.ecm.core.io.impl.plugins.NuxeoArchiveWriter; 059import org.nuxeo.runtime.model.DefaultComponent; 060 061import static java.util.Collections.reverseOrder; 062import static java.util.Comparator.comparing; 063import static org.nuxeo.ecm.core.api.validation.DocumentValidationService.CTX_MAP_KEY; 064import static org.nuxeo.ecm.core.api.validation.DocumentValidationService.Forcing.TURN_OFF; 065 066public class SnapshotManagerComponent extends DefaultComponent implements SnapshotManager { 067 068 protected volatile DistributionSnapshot runtimeSnapshot; 069 070 public static final String RUNTIME = "current"; 071 072 public static final String RUNTIME_ADM = "adm"; 073 074 protected static final String IMPORT_TMP = "tmpImport"; 075 076 protected static final Log log = LogFactory.getLog(SnapshotManagerComponent.class); 077 078 protected final SnapshotPersister persister = new SnapshotPersister(); 079 080 @Override 081 public DistributionSnapshot getRuntimeSnapshot() { 082 if (runtimeSnapshot == null) { 083 synchronized (this) { 084 if (runtimeSnapshot == null) { 085 runtimeSnapshot = RuntimeSnapshot.build(); 086 } 087 } 088 } 089 return runtimeSnapshot; 090 } 091 092 @Override 093 public DistributionSnapshot getSnapshot(String key, CoreSession session) { 094 if (key == null || RUNTIME.equals(key) || RUNTIME_ADM.equals(key)) { 095 return getRuntimeSnapshot(); 096 } 097 DistributionSnapshot snap = getPersistentSnapshots(session).get(key); 098 if (snap == null) { 099 DistributionSnapshot rtsnap = getRuntimeSnapshot(); 100 if (rtsnap.getKey().equals(key)) { 101 return rtsnap; 102 } 103 } 104 return snap; 105 } 106 107 @Override 108 public List<DistributionSnapshot> readPersistentSnapshots(CoreSession session) { 109 return RepositoryDistributionSnapshot.readPersistentSnapshots(session); 110 } 111 112 @Override 113 public List<DistributionSnapshot> listPersistentSnapshots(CoreSession session) { 114 115 List<DistributionSnapshot> distribs = readPersistentSnapshots(session); 116 117 Collections.sort(distribs, 118 reverseOrder(comparing(DistributionSnapshot::getVersion)).thenComparing(DistributionSnapshot::getName)); 119 120 return distribs; 121 } 122 123 @Override 124 public Map<String, DistributionSnapshot> getPersistentSnapshots(CoreSession session) { 125 126 Map<String, DistributionSnapshot> persistentSnapshots = new HashMap<>(); 127 128 for (DistributionSnapshot snap : readPersistentSnapshots(session)) { 129 persistentSnapshots.put(snap.getKey(), snap); 130 } 131 132 return persistentSnapshots; 133 } 134 135 @Override 136 public List<String> getPersistentSnapshotNames(CoreSession session) { 137 List<String> names = new ArrayList<>(); 138 names.addAll(getPersistentSnapshots(session).keySet()); 139 return names; 140 } 141 142 @Override 143 public List<DistributionSnapshotDesc> getAvailableDistributions(CoreSession session) { 144 List<DistributionSnapshotDesc> names = new ArrayList<>(); 145 names.addAll(getPersistentSnapshots(session).values()); 146 names.add(0, getRuntimeSnapshot()); 147 return names; 148 } 149 150 @Override 151 public DistributionSnapshot persistRuntimeSnapshot(CoreSession session) { 152 return persistRuntimeSnapshot(session, null, null); 153 } 154 155 @Override 156 public DistributionSnapshot persistRuntimeSnapshot(CoreSession session, String name, 157 Map<String, Serializable> properties) { 158 return persistRuntimeSnapshot(session, name, properties, null); 159 } 160 161 @Override 162 public DistributionSnapshot persistRuntimeSnapshot(CoreSession session, String name, 163 Map<String, Serializable> properties, SnapshotFilter filter) { 164 DistributionSnapshot liveSnapshot = getRuntimeSnapshot(); 165 DistributionSnapshot snap = persister.persist(liveSnapshot, session, name, filter, properties); 166 addPersistentSnapshot(snap.getKey(), snap); 167 return snap; 168 } 169 170 @Override 171 public List<String> getAvailableVersions(CoreSession session, NuxeoArtifact nxItem) { 172 List<String> versions = new ArrayList<>(); 173 174 List<DistributionSnapshot> distribs = new ArrayList<>(); 175 distribs.addAll(getPersistentSnapshots(session).values()); 176 distribs.add(getRuntimeSnapshot()); 177 178 for (DistributionSnapshot snap : distribs) { 179 180 String version = null; 181 if (BundleGroup.TYPE_NAME.equals(nxItem.getArtifactType())) { 182 BundleGroup bg = snap.getBundleGroup(nxItem.getId()); 183 if (bg != null) { 184 version = bg.getVersion(); 185 } 186 } else if (BundleInfo.TYPE_NAME.equals(nxItem.getArtifactType())) { 187 BundleInfo bi = snap.getBundle(nxItem.getId()); 188 if (bi != null) { 189 version = bi.getVersion(); 190 } 191 } else if (ComponentInfo.TYPE_NAME.equals(nxItem.getArtifactType())) { 192 ComponentInfo ci = snap.getComponent(nxItem.getId()); 193 if (ci != null) { 194 version = ci.getVersion(); 195 } 196 } else if (ExtensionInfo.TYPE_NAME.equals(nxItem.getArtifactType())) { 197 ExtensionInfo ei = snap.getContribution(nxItem.getId()); 198 if (ei != null) { 199 version = ei.getVersion(); 200 } 201 } else if (ExtensionPointInfo.TYPE_NAME.equals(nxItem.getArtifactType())) { 202 ExtensionPointInfo epi = snap.getExtensionPoint(nxItem.getId()); 203 if (epi != null) { 204 version = epi.getVersion(); 205 } 206 } else if (ServiceInfo.TYPE_NAME.equals(nxItem.getArtifactType())) { 207 ServiceInfo si = snap.getService(nxItem.getId()); 208 if (si != null) { 209 version = si.getVersion(); 210 } 211 } else if (OperationInfo.TYPE_NAME.equals(nxItem.getArtifactType())) { 212 OperationInfo oi = snap.getOperation(nxItem.getId()); 213 if (oi != null) { 214 version = oi.getVersion(); 215 } 216 } 217 218 if (version != null && !versions.contains(version)) { 219 versions.add(version); 220 } 221 } 222 return versions; 223 } 224 225 @Override 226 public void exportSnapshot(CoreSession session, String key, OutputStream out) throws IOException { 227 228 DistributionSnapshot snap = getSnapshot(key, session); 229 230 if (snap == null) { 231 throw new NuxeoException("Unable to find Snapshot " + key); 232 } 233 234 if (snap.isLive()) { 235 throw new NuxeoException("Can not export a live distribution snapshot : " + key); 236 } 237 238 RepositoryDistributionSnapshot docSnap = (RepositoryDistributionSnapshot) snap; 239 DocumentModel root = docSnap.getDoc(); 240 241 DocumentReader reader = new DocumentTreeReader(session, root); 242 DocumentWriter writer = new NuxeoArchiveWriter(out); 243 DocumentPipe pipe = new DocumentPipeImpl(10); 244 pipe.setReader(reader); 245 pipe.setWriter(writer); 246 pipe.run(); 247 reader.close(); 248 writer.close(); 249 } 250 251 @Override 252 public void importSnapshot(CoreSession session, InputStream is) throws IOException { 253 String importPath = persister.getDistributionRoot(session).getPathAsString(); 254 DocumentReader reader = new NuxeoArchiveReader(is); 255 DocumentWriter writer = new DocumentModelWriter(session, importPath); 256 DocumentPipe pipe = new DocumentPipeImpl(10); 257 pipe.setReader(reader); 258 pipe.setWriter(writer); 259 pipe.run(); 260 reader.close(); 261 writer.close(); 262 } 263 264 @Override 265 public void validateImportedSnapshot(CoreSession session, String name, String version, String pathSegment, 266 String title) { 267 268 DocumentModel container = persister.getDistributionRoot(session); 269 DocumentRef tmpRef = new PathRef(container.getPathAsString(), IMPORT_TMP); 270 271 DocumentModel tmp; 272 if (session.exists(tmpRef)) { 273 tmp = session.getChild(container.getRef(), IMPORT_TMP); 274 DocumentModel snapDoc = session.getChildren(tmp.getRef()).get(0); 275 snapDoc.setPropertyValue("nxdistribution:name", name); 276 snapDoc.setPropertyValue("nxdistribution:version", version); 277 snapDoc.setPropertyValue("nxdistribution:key", name + "-" + version); 278 snapDoc.setPropertyValue("dc:title", title); 279 snapDoc = session.saveDocument(snapDoc); 280 281 DocumentModel targetContainer = session.getParentDocument(tmp.getRef()); 282 283 session.move(snapDoc.getRef(), targetContainer.getRef(), pathSegment); 284 session.removeDocument(tmp.getRef()); 285 } 286 287 } 288 289 @Override 290 public DocumentModel importTmpSnapshot(CoreSession session, InputStream is) throws IOException { 291 DocumentModel container = persister.getDistributionRoot(session); 292 DocumentRef tmpRef = new PathRef(container.getPathAsString(), IMPORT_TMP); 293 294 DocumentModel tmp; 295 if (session.exists(tmpRef)) { 296 tmp = session.getChild(container.getRef(), IMPORT_TMP); 297 session.removeChildren(tmp.getRef()); 298 } else { 299 tmp = session.createDocumentModel(container.getPathAsString(), IMPORT_TMP, "Workspace"); 300 tmp.setPropertyValue("dc:title", "tmpImport"); 301 tmp = session.createDocument(tmp); 302 session.save(); 303 } 304 305 DocumentReader reader = new NuxeoArchiveReader(is); 306 DocumentWriter writer = new SnapshotWriter(session, tmp.getPathAsString()); 307 308 DocumentPipe pipe = new DocumentPipeImpl(10); 309 pipe.setReader(reader); 310 pipe.setWriter(writer); 311 pipe.run(); 312 reader.close(); 313 writer.close(); 314 315 return session.getChildren(tmp.getRef()).get(0); 316 } 317 318 @Override 319 public void initSeamContext(HttpServletRequest request) { 320 ((RuntimeSnapshot) getRuntimeSnapshot()).initSeamComponents(request); 321 } 322 323 @Override 324 public void addPersistentSnapshot(String key, DistributionSnapshot snapshot) { 325 // NOP 326 } 327 328 /** 329 * Custom Write to disable Validation Service 330 */ 331 protected static class SnapshotWriter extends DocumentModelWriter { 332 public SnapshotWriter(CoreSession session, String parentPath) { 333 super(session, parentPath); 334 } 335 336 @Override 337 protected void beforeCreateDocument(DocumentModel doc) { 338 doc.putContextData(CTX_MAP_KEY, TURN_OFF); 339 } 340 } 341 342}