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