| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.jackrabbit.vault.packaging.impl; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.Calendar; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| import javax.jcr.Binary; |
| import javax.jcr.Node; |
| import javax.jcr.Property; |
| import javax.jcr.RepositoryException; |
| import javax.jcr.Session; |
| import javax.jcr.Value; |
| |
| import org.apache.commons.io.FileUtils; |
| import org.apache.commons.io.IOUtils; |
| import org.apache.jackrabbit.vault.fs.api.ImportMode; |
| import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener; |
| import org.apache.jackrabbit.vault.fs.io.AccessControlHandling; |
| import org.apache.jackrabbit.vault.fs.io.ImportOptions; |
| import org.apache.jackrabbit.vault.fs.io.MemoryArchive; |
| import org.apache.jackrabbit.vault.fs.io.ZipArchive; |
| import org.apache.jackrabbit.vault.packaging.CyclicDependencyException; |
| import org.apache.jackrabbit.vault.packaging.DependencyUtil; |
| import org.apache.jackrabbit.vault.packaging.ExportOptions; |
| import org.apache.jackrabbit.vault.packaging.JcrPackage; |
| import org.apache.jackrabbit.vault.packaging.JcrPackageDefinition; |
| import org.apache.jackrabbit.vault.packaging.JcrPackageManager; |
| import org.apache.jackrabbit.vault.packaging.PackageException; |
| import org.apache.jackrabbit.vault.packaging.PackageId; |
| import org.apache.jackrabbit.vault.packaging.SubPackageHandling; |
| import org.apache.jackrabbit.vault.packaging.VaultPackage; |
| import org.apache.jackrabbit.vault.packaging.Version; |
| import org.apache.jackrabbit.vault.util.JcrConstants; |
| import org.apache.jackrabbit.vault.util.Text; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * Implements a JcrPackage |
| */ |
| public class JcrPackageImpl implements JcrPackage { |
| |
| /** |
| * default logger |
| */ |
| private static final Logger log = LoggerFactory.getLogger(JcrPackageImpl.class); |
| |
| /** |
| * underlying node |
| */ |
| private Node node; |
| |
| /** |
| * underlying package |
| */ |
| private ZipVaultPackage pack; |
| |
| /** |
| * underlying definition |
| */ |
| private JcrPackageDefinitionImpl def; |
| |
| public JcrPackageImpl(Node node) throws RepositoryException { |
| this.node = node; |
| } |
| |
| protected JcrPackageImpl(Node node, ZipVaultPackage pack) throws RepositoryException { |
| this.node = node; |
| this.pack = pack; |
| } |
| |
| protected JcrPackageImpl(Node node, ZipVaultPackage pack, JcrPackageDefinitionImpl def) |
| throws RepositoryException { |
| this.node = node; |
| this.pack = pack; |
| this.def = def; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public JcrPackageDefinition getDefinition() throws RepositoryException { |
| if (def == null) { |
| if (isValid()) { |
| Node defNode = getDefNode(); |
| def = defNode == null |
| ? null |
| : new JcrPackageDefinitionImpl(defNode); |
| } |
| } |
| return def; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public int compareTo(JcrPackage o) { |
| try { |
| JcrPackageDefinition d1 = getDefinition(); |
| JcrPackageDefinition d2 = o.getDefinition(); |
| return d1.getId().compareTo(d2.getId()); |
| } catch (Exception e) { |
| log.error("error during compare: {}", e.toString()); |
| return 0; |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean isValid() { |
| try { |
| if (node != null) { |
| if (node.isNodeType(JcrConstants.NT_HIERARCHYNODE) && node.hasNode(JcrConstants.JCR_CONTENT)) { |
| if (node.getNode(JcrConstants.JCR_CONTENT).isNodeType(NT_VLT_PACKAGE)) { |
| return true; |
| } |
| } |
| } |
| } catch (RepositoryException e) { |
| log.warn("Error during evaluation of isValid()", e); |
| } |
| return false; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean isInstalled() throws RepositoryException { |
| JcrPackageDefinition def = getDefinition(); |
| return def != null && def.getLastUnpacked() != null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Node getNode() { |
| return node; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean isSealed() { |
| try { |
| if (!isValid()) { |
| return false; |
| } |
| if (getSize() == 0) { |
| return false; |
| } |
| if (getDefinition() == null) { |
| return true; |
| } |
| return !def.isModified(); |
| } catch (RepositoryException e) { |
| log.warn("Error during isSealed()", e); |
| return false; |
| } |
| |
| } |
| |
| /** |
| * Creates a new jcr vault package. |
| * |
| * @param parent the parent node |
| * @param pid the package id of the new package. |
| * @param pack the underlying zip package or null. |
| * @param autoSave if <code>true</code> the changes are persisted immediately |
| * @return the created jcr vault package. |
| * @throws RepositoryException if an repository error occurs |
| * @throws IOException if an I/O error occurs |
| * |
| * @since 2.3.0 |
| */ |
| public static JcrPackage createNew(Node parent, PackageId pid, VaultPackage pack, boolean autoSave) |
| throws RepositoryException, IOException { |
| Node node = parent.addNode(Text.getName(pid.getInstallationPath() + ".zip"), JcrConstants.NT_FILE); |
| Node content = node.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE); |
| content.addMixin(NT_VLT_PACKAGE); |
| Node defNode = content.addNode(NN_VLT_DEFINITION); |
| JcrPackageDefinition def = new JcrPackageDefinitionImpl(defNode); |
| def.set(JcrPackageDefinition.PN_NAME, pid.getName(), false); |
| def.set(JcrPackageDefinition.PN_GROUP, pid.getGroup(), false); |
| def.set(JcrPackageDefinition.PN_VERSION, pid.getVersionString(), false); |
| def.touch(null, false); |
| content.setProperty(JcrConstants.JCR_LASTMODIFIED, Calendar.getInstance()); |
| content.setProperty(JcrConstants.JCR_MIMETYPE, MIME_TYPE); |
| InputStream in = new ByteArrayInputStream(new byte[0]); |
| try { |
| if (pack != null && pack.getFile() != null) { |
| in = FileUtils.openInputStream(pack.getFile()); |
| } |
| // stay jcr 1.0 compatible |
| //noinspection deprecation |
| content.setProperty(JcrConstants.JCR_DATA, in); |
| if (pack != null) { |
| def.unwrap(pack, true, false); |
| } |
| if (autoSave) { |
| parent.save(); |
| } |
| } finally { |
| IOUtils.closeQuietly(in); |
| } |
| return new JcrPackageImpl(node, (ZipVaultPackage) pack); |
| } |
| /** |
| * Creates a new jcr vault package. |
| * |
| * @param parent the parent node |
| * @param pid the package id of the new package. |
| * @param bin the binary containing the zip |
| * @param archive the archive with the meta data |
| * @return the created jcr vault package. |
| * @throws RepositoryException if an repository error occurs |
| * @throws IOException if an I/O error occurs |
| * |
| * @since 3.1 |
| */ |
| public static JcrPackage createNew(Node parent, PackageId pid, Binary bin, MemoryArchive archive) |
| throws RepositoryException, IOException { |
| Node node = parent.addNode(Text.getName(pid.getInstallationPath() + ".zip"), JcrConstants.NT_FILE); |
| Node content = node.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE); |
| content.addMixin(NT_VLT_PACKAGE); |
| Node defNode = content.addNode(NN_VLT_DEFINITION); |
| JcrPackageDefinitionImpl def = new JcrPackageDefinitionImpl(defNode); |
| def.set(JcrPackageDefinition.PN_NAME, pid.getName(), false); |
| def.set(JcrPackageDefinition.PN_GROUP, pid.getGroup(), false); |
| def.set(JcrPackageDefinition.PN_VERSION, pid.getVersionString(), false); |
| def.touch(null, false); |
| content.setProperty(JcrConstants.JCR_LASTMODIFIED, Calendar.getInstance()); |
| content.setProperty(JcrConstants.JCR_MIMETYPE, MIME_TYPE); |
| content.setProperty(JcrConstants.JCR_DATA, bin); |
| def.unwrap(archive, false); |
| return new JcrPackageImpl(node); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean verifyId(boolean autoFix, boolean autoSave) throws RepositoryException { |
| // check if package id is correct |
| JcrPackageDefinition jDef = getDefinition(); |
| if (jDef == null) { |
| return true; |
| } |
| PackageId id = jDef.getId(); |
| PackageId cId = new PackageId(node.getPath()); |
| // compare installation paths since non-conform version numbers might |
| // lead to different pids (bug #35564) |
| if (id.getInstallationPath().equals(cId.getInstallationPath())) { |
| if (autoFix && id.isFromPath()) { |
| // if definition has no id set, fix anyways |
| jDef.setId(cId, autoSave); |
| } |
| return true; |
| } |
| if (autoFix) { |
| log.warn("Fixing non-matching id from {} to {}.", id, cId); |
| jDef.setId(cId, autoSave); |
| } |
| return false; |
| } |
| |
| |
| /** |
| * Tries to unwrap the definition of this package. |
| * @throws IOException if an I/O error occurs or if the underlying file is not a package |
| * @throws RepositoryException if a repository error occurs |
| */ |
| public void tryUnwrap() throws IOException, RepositoryException { |
| if (isValid()) { |
| return; |
| } |
| VaultPackage pack = getPackage(); |
| Node content = getContent(); |
| boolean ok = false; |
| try { |
| content.addMixin(NT_VLT_PACKAGE); |
| Node defNode = content.addNode(NN_VLT_DEFINITION); |
| JcrPackageDefinition def = new JcrPackageDefinitionImpl(defNode); |
| def.unwrap(pack, true, false); |
| node.save(); |
| ok = true; |
| } finally { |
| if (!ok) { |
| try { |
| node.refresh(false); |
| } catch (RepositoryException e) { |
| // ignore |
| } |
| } |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public VaultPackage getPackage() throws RepositoryException, IOException { |
| return getPackage(false); |
| } |
| |
| /** |
| * Creates a new package by creating the appropriate archive. |
| * |
| * This is basically a workaround to ensure that 'rewrap' has a zip file to work on. |
| * Ideally rewrap should not realy on the archive format. |
| * |
| * @param forceFileArchive if {@code true} a file archive is enforced |
| * @return the package |
| * |
| * @throws RepositoryException |
| * @throws IOException |
| */ |
| protected VaultPackage getPackage(boolean forceFileArchive) throws RepositoryException, IOException { |
| if (forceFileArchive && pack != null && !(pack.getArchive() instanceof ZipArchive)) { |
| pack.close(); |
| pack = null; |
| } |
| |
| if (pack == null) { |
| long size = -1; |
| try { |
| size = getData().getLength(); |
| } catch (RepositoryException e) { |
| // ignore |
| } |
| if (!forceFileArchive && size >= 0 && size < 1024*1024) { |
| MemoryArchive archive = new MemoryArchive(false); |
| InputStream in = getData().getStream(); |
| try { |
| archive.run(in); |
| } catch (Exception e) { |
| throw new IOException("Error while reading stream", e); |
| } finally { |
| in.close(); |
| } |
| pack = new ZipVaultPackage(archive, true); |
| } else { |
| File tmpFile = File.createTempFile("vaultpack", ".zip"); |
| FileOutputStream out = FileUtils.openOutputStream(tmpFile); |
| Binary bin = getData().getBinary(); |
| InputStream in = null; |
| try { |
| in = bin.getStream(); |
| IOUtils.copy(in, out); |
| } finally { |
| IOUtils.closeQuietly(in); |
| IOUtils.closeQuietly(out); |
| bin.dispose(); |
| } |
| pack = new ZipVaultPackage(tmpFile, true); |
| } |
| } |
| return pack; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void extract(ImportOptions opts) throws RepositoryException, PackageException, IOException { |
| extract(opts, false, false); |
| |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void install(ImportOptions opts) throws RepositoryException, PackageException, IOException { |
| extract(opts, true, false); |
| } |
| |
| /** |
| * internally extracts the package. |
| * |
| * @param options the import options |
| * @param createSnapshot <code>true</code> if a snapshot should be created |
| * @param replaceSnapshot <code>true</code> if a snapshot should be replaced |
| * @throws RepositoryException if a repository error occurs |
| * @throws PackageException if a package error occurs |
| * @throws IOException if an I/O error occurs |
| */ |
| private void extract(ImportOptions options, boolean createSnapshot, boolean replaceSnapshot) |
| throws RepositoryException, PackageException, IOException { |
| getPackage(); |
| // get a copy of the import options (bug 35164) |
| ImportOptions opts = options.copy(); |
| // check for disable intermediate saves (GRANITE-1047) |
| if (this.getDefinition().getBoolean(JcrPackageDefinition.PN_DISABLE_INTERMEDIATE_SAVE) ) { |
| // MAX_VALUE disables saving completely, therefore we have to use a lower value! |
| opts.setAutoSaveThreshold(Integer.MAX_VALUE - 1); |
| } |
| InstallContextImpl ctx = pack.prepareExtract(node.getSession(), opts); |
| JcrPackage snap = null; |
| if (!opts.isDryRun() && createSnapshot) { |
| ExportOptions eOpts = new ExportOptions(); |
| eOpts.setListener(opts.getListener()); |
| snap = snapshot(eOpts, replaceSnapshot, opts.getAccessControlHandling()); |
| } |
| List<String> subPackages = new ArrayList<String>(); |
| pack.extract(ctx, subPackages); |
| getDefinition(); |
| if (def != null && !opts.isDryRun()) { |
| def.touchLastUnpacked(null, true); |
| } |
| |
| // process sub packages |
| Session s = node.getSession(); |
| List<JcrPackageImpl> subPacks = new LinkedList<JcrPackageImpl>(); |
| for (String path: subPackages) { |
| if (s.nodeExists(path)) { |
| JcrPackageImpl p = new JcrPackageImpl(s.getNode(path)); |
| if (!p.isValid()) { |
| // check if package was included as pure .zip or .jar |
| try { |
| p.tryUnwrap(); |
| } catch (Exception e) { |
| log.info("Sub package {} not valid: " + e, path); |
| } |
| } |
| if (p.isValid()) { |
| // ensure that sub package is marked as not-installed. it might contain wrong data in vlt:definition (JCRVLT-114) |
| JcrPackageDefinitionImpl def = (JcrPackageDefinitionImpl) p.getDefinition(); |
| def.clearLastUnpacked(false); |
| |
| PackageId pId = def.getId(); |
| String pName = pId.getName(); |
| Version pVersion = pId.getVersion(); |
| |
| // get the list of packages available in the same group |
| JcrPackageManager pkgMgr = new JcrPackageManagerImpl(s); |
| List<JcrPackage> listPackages = pkgMgr.listPackages(pId.getGroup(), true); |
| |
| // keep some status variable if a more recent is found in the next loop |
| PackageId newerPackageId = null; |
| |
| // loop in the list of packages returned previously by package manager |
| for (JcrPackage listedPackage: listPackages) { |
| PackageId listedPackageId = listedPackage.getPackage().getId(); |
| if (listedPackageId.equals(pId)) { |
| continue; |
| } |
| // check that the listed package is actually from same name (so normally only version would differ) |
| // if that package is valid, installed, and the version is more recent than the one in our sub package |
| // then we can stop the loop here |
| if (pName.equals(listedPackageId.getName()) && listedPackage.isValid() && listedPackage.isInstalled() && listedPackageId.getVersion().compareTo(pVersion) > 0) { |
| newerPackageId = listedPackageId; |
| break; |
| } |
| } |
| // if a more recent version of that subpackage was found we don't need to add it to the list of sub packages to eventually extract later on. |
| if (newerPackageId != null) { |
| log.info("Skipping installation if subpackage '{}' due to newer installed version: '{}'", pId, newerPackageId); |
| } else { |
| subPacks.add(p); |
| } |
| } |
| } |
| } |
| |
| // don't extract sub packages if not recursive |
| if (!opts.isNonRecursive() && !subPacks.isEmpty()) { |
| try { |
| DependencyUtil.sortPackages(subPacks); |
| } catch (CyclicDependencyException e) { |
| if (opts.isStrict()) { |
| throw e; |
| } |
| } |
| List<String> subIds = new LinkedList<String>(); |
| SubPackageHandling sb = pack.getSubPackageHandling(); |
| for (JcrPackageImpl p: subPacks) { |
| boolean skip = false; |
| PackageId id = p.getPackage().getId(); |
| SubPackageHandling.Option option = sb.getOption(id); |
| String msg; |
| if (option == SubPackageHandling.Option.ADD || option == SubPackageHandling.Option.IGNORE) { |
| msg = "skipping installation of subpackage " + id + " due to option " + option; |
| skip = true; |
| } else if (option == SubPackageHandling.Option.INSTALL) { |
| msg = "Starting installation of subpackage " + id; |
| } else { |
| msg = "Starting extraction of subpackage " + id; |
| } |
| if (options.isDryRun()) { |
| msg = "Dry run: " + msg; |
| } |
| if (options.getListener() != null) { |
| options.getListener().onMessage(ProgressTrackerListener.Mode.TEXT, msg, ""); |
| } else { |
| log.info(msg); |
| } |
| if (!skip) { |
| if (createSnapshot && option == SubPackageHandling.Option.INSTALL) { |
| p.extract(options, true, true); |
| subIds.add(id.toString()); |
| } else { |
| p.extract(options, false, true); |
| } |
| } |
| p.close(); |
| } |
| // register sub packages in snapshot for uninstall |
| if (snap != null) { |
| snap.getDefinition().getNode().setProperty(JcrPackageDefinition.PN_SUB_PACKAGES, subIds.toArray(new String[subIds.size()])); |
| snap.getDefinition().getNode().save(); |
| } |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public JcrPackage snapshot(ExportOptions opts, boolean replace) |
| throws RepositoryException, PackageException, IOException { |
| return snapshot(opts, replace, null); |
| } |
| |
| /** |
| * Internally creates the snapshot |
| * @param opts exports options when building the snapshot |
| * @param replace if <code>true</code> existing snapshot will be replaced |
| * @param acHandling user acHandling to use when snapshot is installed, i.e. package is uninstalled |
| * @return the package of the snapshot or <code>null</code> |
| * @throws RepositoryException if an error occurrs. |
| * @throws PackageException if an error occurrs. |
| * @throws IOException if an error occurrs. |
| */ |
| private JcrPackage snapshot(ExportOptions opts, boolean replace, AccessControlHandling acHandling) |
| throws RepositoryException, PackageException, IOException { |
| PackageId id = getSnapshotId(); |
| Node packNode = getPackageNode(id); |
| if (packNode != null) { |
| if (!replace) { |
| log.warn("Refusing to recreate snapshot {}, already exists.", id); |
| return null; |
| } else { |
| packNode.remove(); |
| node.getSession().save(); |
| } |
| } |
| log.info("Creating snapshot for {}.", id); |
| JcrPackageManagerImpl packMgr = new JcrPackageManagerImpl(node.getSession()); |
| String path = id.getInstallationPath(); |
| String parentPath = Text.getRelativeParent(path, 1); |
| Node folder = packMgr.mkdir(parentPath, true); |
| JcrPackage snap = JcrPackageImpl.createNew(folder, id, null, true); |
| JcrPackageDefinitionImpl snapDef = (JcrPackageDefinitionImpl) snap.getDefinition(); |
| JcrPackageDefinitionImpl myDef = (JcrPackageDefinitionImpl) getDefinition(); |
| snapDef.setId(id, false); |
| snapDef.setFilter(myDef.getMetaInf().getFilter(), false); |
| snapDef.set(JcrPackageDefinition.PN_DESCRIPTION, "Snapshot of package " + myDef.getId().toString(), false); |
| if (acHandling == null) { |
| snapDef.set(JcrPackageDefinition.PN_AC_HANDLING, myDef.get(JcrPackageDefinition.PN_AC_HANDLING), false); |
| } else { |
| snapDef.set(JcrPackageDefinition.PN_AC_HANDLING, acHandling.name(), false); |
| } |
| if (opts.getListener() != null) { |
| opts.getListener().onMessage(ProgressTrackerListener.Mode.TEXT, "Creating snapshot for package " + myDef.getId(), ""); |
| } |
| packMgr.assemble(snap.getNode(), snapDef, opts.getListener()); |
| log.info("Creating snapshot for {} completed.", id); |
| return snap; |
| } |
| |
| /** |
| * Returns the package node of the given package id. |
| * @param id the package id |
| * @return the package node |
| * @throws RepositoryException if an error occurs |
| */ |
| private Node getPackageNode(PackageId id) throws RepositoryException { |
| if (node.getSession().nodeExists(id.getInstallationPath())) { |
| return node.getSession().getNode(id.getInstallationPath()); |
| } else if (node.getSession().nodeExists(id.getInstallationPath() + ".zip")) { |
| return node.getSession().getNode(id.getInstallationPath() + ".zip"); |
| } |
| return null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public JcrPackage getSnapshot() throws RepositoryException { |
| PackageId id = getSnapshotId(); |
| Node packNode = getPackageNode(id); |
| if (packNode != null) { |
| JcrPackageImpl snap = new JcrPackageImpl(packNode); |
| if (snap.isValid()) { |
| return snap; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the snapshot id of this package. |
| * @return the snapshot package id |
| * @throws RepositoryException if an error occurs |
| */ |
| private PackageId getSnapshotId() throws RepositoryException { |
| PackageId id = getDefinition().getId(); |
| String group = id.getGroup(); |
| if (group.length() == 0) { |
| group = ".snapshot"; |
| } else { |
| group += "/.snapshot"; |
| } |
| return new PackageId( |
| group, |
| id.getName(), |
| id.getVersion()); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void uninstall(ImportOptions opts) throws RepositoryException, PackageException, IOException { |
| JcrPackage snap = getSnapshot(); |
| if (snap == null) { |
| if (opts.isStrict()) { |
| throw new PackageException("Unable to uninstall package. No snapshot present."); |
| } |
| log.warn("Unable to revert package content {}. Snapshot missing.", getDefinition().getId()); |
| if (opts.getListener() != null) { |
| opts.getListener().onMessage(ProgressTrackerListener.Mode.TEXT, "Unable to revert package content. Snapshot missing.", ""); |
| } |
| |
| } else { |
| Session s = getNode().getSession(); |
| // check for recursive uninstall |
| if (!opts.isNonRecursive()) { |
| Node defNode = snap.getDefNode(); |
| LinkedList<PackageId> subPackages = new LinkedList<PackageId>(); |
| if (defNode.hasProperty(JcrPackageDefinition.PN_SUB_PACKAGES)) { |
| Value[] subIds = defNode.getProperty(JcrPackageDefinition.PN_SUB_PACKAGES).getValues(); |
| for (Value v : subIds) { |
| // reverse installation order |
| subPackages.addLast(PackageId.fromString(v.getString())); |
| } |
| } |
| if (subPackages.size() > 0) { |
| JcrPackageManagerImpl packMgr = new JcrPackageManagerImpl(s); |
| for (PackageId id : subPackages) { |
| JcrPackage pack = packMgr.open(id); |
| if (pack != null) { |
| if (pack.getSnapshot() == null) { |
| log.warn("Unable to uninstall sub package {}. Snapshot missing.", id); |
| } else { |
| pack.uninstall(opts); |
| } |
| } |
| } |
| |
| } |
| } |
| |
| if (opts.getListener() != null) { |
| opts.getListener().onMessage(ProgressTrackerListener.Mode.TEXT, "Uninstalling package from snapshot " + snap.getDefinition().getId(), ""); |
| } |
| // override import mode |
| opts.setImportMode(ImportMode.REPLACE); |
| snap.extract(opts); |
| snap.getNode().remove(); |
| s.save(); |
| } |
| |
| // revert installed flags on this package |
| JcrPackageDefinitionImpl def = (JcrPackageDefinitionImpl) getDefinition(); |
| def.clearLastUnpacked(true); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public long getSize() { |
| try { |
| assertValid(); |
| return getData().getLength(); |
| } catch (RepositoryException e) { |
| log.error("Error during getSize()", e); |
| return -1; |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void close() { |
| node = null; |
| if (pack != null) { |
| pack.close(); |
| pack = null; |
| } |
| } |
| |
| /** |
| * Returns the jcr:content node |
| * @return the jcr:content node |
| * @throws RepositoryException if an error occurrs |
| */ |
| private Node getContent() throws RepositoryException { |
| return node.getNode(JcrConstants.JCR_CONTENT); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Property getData() throws RepositoryException { |
| return getContent().getProperty(JcrConstants.JCR_DATA); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Node getDefNode() throws RepositoryException { |
| Node content = getContent(); |
| return content.hasNode(NN_VLT_DEFINITION) |
| ? content.getNode(NN_VLT_DEFINITION) |
| : null; |
| } |
| |
| /** |
| * Ensures that the package is valid. |
| * @throws RepositoryException if an error occurs |
| */ |
| private void assertValid() throws RepositoryException { |
| if (!isValid()) { |
| throw new IllegalArgumentException("not a valid package."); |
| } |
| } |
| } |