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.util.ArrayList;
025import java.util.Collections;
026import java.util.Comparator;
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.automation.OperationException;
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 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            runtimeSnapshot = new RuntimeSnapshot();
080        }
081        return runtimeSnapshot;
082    }
083
084    @Override
085    public DistributionSnapshot getSnapshot(String key, CoreSession session) {
086        if (key == null || RUNTIME.equals(key) || RUNTIME_ADM.equals(key)) {
087            return getRuntimeSnapshot();
088        }
089        DistributionSnapshot snap = getPersistentSnapshots(session).get(key);
090        if (snap == null) {
091            DistributionSnapshot rtsnap = getRuntimeSnapshot();
092            if (rtsnap.getKey().equals(key)) {
093                return rtsnap;
094            }
095        }
096        return snap;
097    }
098
099    @Override
100    public List<DistributionSnapshot> readPersistentSnapshots(CoreSession session) {
101        List<DistributionSnapshot> snaps = RepositoryDistributionSnapshot.readPersistentSnapshots(session);
102        return snaps;
103    }
104
105    @Override
106    public List<DistributionSnapshot> listPersistentSnapshots(CoreSession session) {
107
108        List<DistributionSnapshot> distribs = readPersistentSnapshots(session);
109
110        Collections.sort(distribs, new Comparator<DistributionSnapshot>() {
111            @Override
112            public int compare(DistributionSnapshot dist0, DistributionSnapshot dist1) {
113                if (dist0.getVersion().equals(dist1.getVersion())) {
114                    return dist0.getName().compareTo(dist1.getName());
115                } else {
116                    return -dist0.getVersion().compareTo(dist1.getVersion());
117                }
118            }
119        });
120
121        return distribs;
122    }
123
124    @Override
125    public Map<String, DistributionSnapshot> getPersistentSnapshots(CoreSession session) {
126
127        Map<String, DistributionSnapshot> persistentSnapshots = new HashMap<String, DistributionSnapshot>();
128
129        for (DistributionSnapshot snap : readPersistentSnapshots(session)) {
130            persistentSnapshots.put(snap.getKey(), snap);
131        }
132
133        return persistentSnapshots;
134    }
135
136    @Override
137    public List<String> getPersistentSnapshotNames(CoreSession session) {
138        List<String> names = new ArrayList<String>();
139        names.addAll(getPersistentSnapshots(session).keySet());
140        return names;
141    }
142
143    @Override
144    public List<DistributionSnapshotDesc> getAvailableDistributions(CoreSession session) {
145        List<DistributionSnapshotDesc> names = new ArrayList<DistributionSnapshotDesc>();
146        names.addAll(getPersistentSnapshots(session).values());
147        names.add(0, getRuntimeSnapshot());
148        return names;
149    }
150
151    @Override
152    public DistributionSnapshot persistRuntimeSnapshot(CoreSession session) {
153        return persistRuntimeSnapshot(session, null);
154    }
155
156    @Override
157    public DistributionSnapshot persistRuntimeSnapshot(CoreSession session, String name) {
158        return persistRuntimeSnapshot(session, name, null);
159    }
160
161    @Override
162    public DistributionSnapshot persistRuntimeSnapshot(CoreSession session, String name, SnapshotFilter filter) {
163        DistributionSnapshot liveSnapshot = getRuntimeSnapshot();
164        DistributionSnapshot snap = persister.persist(liveSnapshot, session, name, filter);
165        addPersistentSnapshot(snap.getKey(), snap);
166        return snap;
167    }
168
169    @Override
170    public List<String> getAvailableVersions(CoreSession session, NuxeoArtifact nxItem) {
171        List<String> versions = new ArrayList<String>();
172
173        List<DistributionSnapshot> distribs = new ArrayList<DistributionSnapshot>();
174        distribs.addAll(getPersistentSnapshots(session).values());
175        distribs.add(getRuntimeSnapshot());
176
177        for (DistributionSnapshot snap : distribs) {
178
179            String version = null;
180            if (BundleGroup.TYPE_NAME.equals(nxItem.getArtifactType())) {
181                BundleGroup bg = snap.getBundleGroup(nxItem.getId());
182                if (bg != null) {
183                    version = bg.getVersion();
184                }
185            } else if (BundleInfo.TYPE_NAME.equals(nxItem.getArtifactType())) {
186                BundleInfo bi = snap.getBundle(nxItem.getId());
187                if (bi != null) {
188                    version = bi.getVersion();
189                }
190            } else if (ComponentInfo.TYPE_NAME.equals(nxItem.getArtifactType())) {
191                ComponentInfo ci = snap.getComponent(nxItem.getId());
192                if (ci != null) {
193                    version = ci.getVersion();
194                }
195            } else if (ExtensionInfo.TYPE_NAME.equals(nxItem.getArtifactType())) {
196                ExtensionInfo ei = snap.getContribution(nxItem.getId());
197                if (ei != null) {
198                    version = ei.getVersion();
199                }
200            } else if (ExtensionPointInfo.TYPE_NAME.equals(nxItem.getArtifactType())) {
201                ExtensionPointInfo epi = snap.getExtensionPoint(nxItem.getId());
202                if (epi != null) {
203                    version = epi.getVersion();
204                }
205            } else if (ServiceInfo.TYPE_NAME.equals(nxItem.getArtifactType())) {
206                ServiceInfo si = snap.getService(nxItem.getId());
207                if (si != null) {
208                    version = si.getVersion();
209                }
210            } else if (OperationInfo.TYPE_NAME.equals(nxItem.getArtifactType())) {
211                OperationInfo oi = snap.getOperation(nxItem.getId());
212                if (oi != null) {
213                    version = oi.getVersion();
214                }
215            }
216
217            if (version != null && !versions.contains(version)) {
218                versions.add(version);
219            }
220        }
221        return versions;
222    }
223
224    @Override
225    public void exportSnapshot(CoreSession session, String key, OutputStream out) throws IOException {
226
227        DistributionSnapshot snap = getSnapshot(key, session);
228
229        if (snap == null) {
230            throw new NuxeoException("Unable to find Snapshot " + key);
231        }
232
233        if (snap.isLive()) {
234            throw new NuxeoException("Can not export a live distribution snapshot : " + key);
235        }
236
237        RepositoryDistributionSnapshot docSnap = (RepositoryDistributionSnapshot) snap;
238        DocumentModel root = docSnap.getDoc();
239
240        DocumentReader reader = new DocumentTreeReader(session, root);
241        DocumentWriter writer = new NuxeoArchiveWriter(out);
242        DocumentPipe pipe = new DocumentPipeImpl(10);
243        pipe.setReader(reader);
244        pipe.setWriter(writer);
245        pipe.run();
246        reader.close();
247        writer.close();
248    }
249
250    @Override
251    public void importSnapshot(CoreSession session, InputStream is) throws IOException {
252        String importPath = persister.getDistributionRoot(session).getPathAsString();
253        DocumentReader reader = new NuxeoArchiveReader(is);
254        DocumentWriter writer = new DocumentModelWriter(session, importPath);
255        DocumentPipe pipe = new DocumentPipeImpl(10);
256        pipe.setReader(reader);
257        pipe.setWriter(writer);
258        pipe.run();
259        reader.close();
260        writer.close();
261    }
262
263    @Override
264    public void validateImportedSnapshot(CoreSession session, String name, String version, String pathSegment,
265            String title) {
266
267        DocumentModel container = persister.getDistributionRoot(session);
268        DocumentRef tmpRef = new PathRef(container.getPathAsString(), IMPORT_TMP);
269
270        DocumentModel tmp = null;
271
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 = null;
295
296        if (session.exists(tmpRef)) {
297            tmp = session.getChild(container.getRef(), IMPORT_TMP);
298            session.removeChildren(tmp.getRef());
299        } else {
300            tmp = session.createDocumentModel(container.getPathAsString(), IMPORT_TMP, "Workspace");
301            tmp.setPropertyValue("dc:title", "tmpImport");
302            tmp = session.createDocument(tmp);
303            session.save();
304        }
305
306        DocumentReader reader = new NuxeoArchiveReader(is);
307        DocumentWriter writer = new DocumentModelWriter(session, tmp.getPathAsString());
308
309        DocumentPipe pipe = new DocumentPipeImpl(10);
310        pipe.setReader(reader);
311        pipe.setWriter(writer);
312        pipe.run();
313        reader.close();
314        writer.close();
315
316        return session.getChildren(tmp.getRef()).get(0);
317    }
318
319    @Override
320    public void initSeamContext(HttpServletRequest request) {
321        ((RuntimeSnapshot) getRuntimeSnapshot()).initSeamComponents(request);
322    }
323
324    @Override
325    public void addPersistentSnapshot(String key, DistributionSnapshot snapshot) {
326        // NOP
327    }
328
329}