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.Comparator; 028import java.util.HashMap; 029import java.util.List; 030import java.util.Map; 031 032import javax.servlet.http.HttpServletRequest; 033 034import org.apache.commons.logging.Log; 035import org.apache.commons.logging.LogFactory; 036import org.nuxeo.apidoc.api.BundleGroup; 037import org.nuxeo.apidoc.api.BundleInfo; 038import org.nuxeo.apidoc.api.ComponentInfo; 039import org.nuxeo.apidoc.api.ExtensionInfo; 040import org.nuxeo.apidoc.api.ExtensionPointInfo; 041import org.nuxeo.apidoc.api.NuxeoArtifact; 042import org.nuxeo.apidoc.api.OperationInfo; 043import org.nuxeo.apidoc.api.ServiceInfo; 044import org.nuxeo.apidoc.introspection.RuntimeSnapshot; 045import org.nuxeo.apidoc.repository.RepositoryDistributionSnapshot; 046import org.nuxeo.apidoc.repository.SnapshotPersister; 047import org.nuxeo.ecm.core.api.CoreSession; 048import org.nuxeo.ecm.core.api.DocumentModel; 049import org.nuxeo.ecm.core.api.DocumentRef; 050import org.nuxeo.ecm.core.api.NuxeoException; 051import org.nuxeo.ecm.core.api.PathRef; 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 062public class SnapshotManagerComponent extends DefaultComponent implements SnapshotManager { 063 064 protected volatile DistributionSnapshot runtimeSnapshot; 065 066 public static final String RUNTIME = "current"; 067 068 public static final String RUNTIME_ADM = "adm"; 069 070 protected static final String IMPORT_TMP = "tmpImport"; 071 072 protected static final Log log = LogFactory.getLog(SnapshotManagerComponent.class); 073 074 protected final SnapshotPersister persister = new SnapshotPersister(); 075 076 @Override 077 public DistributionSnapshot getRuntimeSnapshot() { 078 if (runtimeSnapshot == null) { 079 synchronized (this) { 080 if (runtimeSnapshot == null) { 081 runtimeSnapshot = RuntimeSnapshot.build(); 082 } 083 } 084 } 085 return runtimeSnapshot; 086 } 087 088 @Override 089 public DistributionSnapshot getSnapshot(String key, CoreSession session) { 090 if (key == null || RUNTIME.equals(key) || RUNTIME_ADM.equals(key)) { 091 return getRuntimeSnapshot(); 092 } 093 DistributionSnapshot snap = getPersistentSnapshots(session).get(key); 094 if (snap == null) { 095 DistributionSnapshot rtsnap = getRuntimeSnapshot(); 096 if (rtsnap.getKey().equals(key)) { 097 return rtsnap; 098 } 099 } 100 return snap; 101 } 102 103 @Override 104 public List<DistributionSnapshot> readPersistentSnapshots(CoreSession session) { 105 List<DistributionSnapshot> snaps = RepositoryDistributionSnapshot.readPersistentSnapshots(session); 106 return snaps; 107 } 108 109 @Override 110 public List<DistributionSnapshot> listPersistentSnapshots(CoreSession session) { 111 112 List<DistributionSnapshot> distribs = readPersistentSnapshots(session); 113 114 Collections.sort(distribs, new Comparator<DistributionSnapshot>() { 115 @Override 116 public int compare(DistributionSnapshot dist0, DistributionSnapshot 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 125 return distribs; 126 } 127 128 @Override 129 public Map<String, DistributionSnapshot> getPersistentSnapshots(CoreSession session) { 130 131 Map<String, DistributionSnapshot> persistentSnapshots = new HashMap<>(); 132 133 for (DistributionSnapshot snap : readPersistentSnapshots(session)) { 134 persistentSnapshots.put(snap.getKey(), snap); 135 } 136 137 return persistentSnapshots; 138 } 139 140 @Override 141 public List<String> getPersistentSnapshotNames(CoreSession session) { 142 List<String> names = new ArrayList<>(); 143 names.addAll(getPersistentSnapshots(session).keySet()); 144 return names; 145 } 146 147 @Override 148 public List<DistributionSnapshotDesc> getAvailableDistributions(CoreSession session) { 149 List<DistributionSnapshotDesc> names = new ArrayList<>(); 150 names.addAll(getPersistentSnapshots(session).values()); 151 names.add(0, getRuntimeSnapshot()); 152 return names; 153 } 154 155 @Override 156 public DistributionSnapshot persistRuntimeSnapshot(CoreSession session) { 157 return persistRuntimeSnapshot(session, null, null); 158 } 159 160 @Override 161 public DistributionSnapshot persistRuntimeSnapshot(CoreSession session, String name, Map<String, Serializable> properties) { 162 return persistRuntimeSnapshot(session, name, properties, null); 163 } 164 165 @Override 166 public DistributionSnapshot persistRuntimeSnapshot(CoreSession session, String name, Map<String, Serializable> properties, 167 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 = null; 276 277 if (session.exists(tmpRef)) { 278 tmp = session.getChild(container.getRef(), IMPORT_TMP); 279 DocumentModel snapDoc = session.getChildren(tmp.getRef()).get(0); 280 snapDoc.setPropertyValue("nxdistribution:name", name); 281 snapDoc.setPropertyValue("nxdistribution:version", version); 282 snapDoc.setPropertyValue("nxdistribution:key", name + "-" + version); 283 snapDoc.setPropertyValue("dc:title", title); 284 snapDoc = session.saveDocument(snapDoc); 285 286 DocumentModel targetContainer = session.getParentDocument(tmp.getRef()); 287 288 session.move(snapDoc.getRef(), targetContainer.getRef(), pathSegment); 289 session.removeDocument(tmp.getRef()); 290 } 291 292 } 293 294 @Override 295 public DocumentModel importTmpSnapshot(CoreSession session, InputStream is) throws IOException { 296 DocumentModel container = persister.getDistributionRoot(session); 297 DocumentRef tmpRef = new PathRef(container.getPathAsString(), IMPORT_TMP); 298 299 DocumentModel tmp = null; 300 301 if (session.exists(tmpRef)) { 302 tmp = session.getChild(container.getRef(), IMPORT_TMP); 303 session.removeChildren(tmp.getRef()); 304 } else { 305 tmp = session.createDocumentModel(container.getPathAsString(), IMPORT_TMP, "Workspace"); 306 tmp.setPropertyValue("dc:title", "tmpImport"); 307 tmp = session.createDocument(tmp); 308 session.save(); 309 } 310 311 DocumentReader reader = new NuxeoArchiveReader(is); 312 DocumentWriter writer = new DocumentModelWriter(session, tmp.getPathAsString()); 313 314 DocumentPipe pipe = new DocumentPipeImpl(10); 315 pipe.setReader(reader); 316 pipe.setWriter(writer); 317 pipe.run(); 318 reader.close(); 319 writer.close(); 320 321 return session.getChildren(tmp.getRef()).get(0); 322 } 323 324 @Override 325 public void initSeamContext(HttpServletRequest request) { 326 ((RuntimeSnapshot) getRuntimeSnapshot()).initSeamComponents(request); 327 } 328 329 @Override 330 public void addPersistentSnapshot(String key, DistributionSnapshot snapshot) { 331 // NOP 332 } 333 334}