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