You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2021/01/28 17:21:49 UTC

[jackrabbit-filevault] branch bugfix/JCRVLT-499-fix-jcrpackagedefinition created (now 2b74469)

This is an automated email from the ASF dual-hosted git repository.

kwin pushed a change to branch bugfix/JCRVLT-499-fix-jcrpackagedefinition
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git.


      at 2b74469  JCRVLT-499 parse dates with timezone designator "Z" correctly

This branch includes the following new commits:

     new 2b74469  JCRVLT-499 parse dates with timezone designator "Z" correctly

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[jackrabbit-filevault] 01/01: JCRVLT-499 parse dates with timezone designator "Z" correctly

Posted by kw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch bugfix/JCRVLT-499-fix-jcrpackagedefinition
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git

commit 2b74469bf7cbc7e1bffbba4c48cabc041ee2ecce
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Thu Jan 28 18:21:32 2021 +0100

    JCRVLT-499 parse dates with timezone designator "Z" correctly
    
    rely on PackageProperties API for reading from package
    expose unwrapped package properties without type conversions
---
 .../vault/packaging/JcrPackageDefinition.java      |  89 +-------
 .../vault/packaging/PackageProperties.java         |  12 +
 .../packaging/impl/JcrPackageDefinitionImpl.java   | 244 +++++++++++----------
 .../impl/JcrPackageDefinitionMetaInf.java          |  55 +++++
 .../packaging/impl/PackagePropertiesImpl.java      |  19 ++
 .../jackrabbit/vault/packaging/package-info.java   |   2 +-
 .../impl/JcrPackageDefinitionImplTest.java         |  70 ++++++
 .../META-INF/vault/properties.xml                  |   8 +-
 8 files changed, 296 insertions(+), 203 deletions(-)

diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/JcrPackageDefinition.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/JcrPackageDefinition.java
index ea120b1..3c157e7 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/JcrPackageDefinition.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/JcrPackageDefinition.java
@@ -35,7 +35,7 @@ import org.osgi.annotation.versioning.ProviderType;
  * Specifies the interface of a package definition stored in the repository.
  */
 @ProviderType
-public interface JcrPackageDefinition {
+public interface JcrPackageDefinition extends PackageProperties {
 
     /**
      * Property name of the last unpacked date
@@ -189,13 +189,6 @@ public interface JcrPackageDefinition {
     Node getNode();
 
     /**
-     * Returns the package id
-     * @return the package id
-     */
-    @NotNull
-    PackageId getId();
-
-    /**
      * Writes the properties derived from the package id to the content
      * @param id the package id
      * @param autoSave if {@code true} the changes are saved automatically.
@@ -236,13 +229,6 @@ public interface JcrPackageDefinition {
     void dumpCoverage(@NotNull ProgressTrackerListener listener) throws RepositoryException;
 
     /**
-     * Returns the dependencies stored in this definition
-     * @return the dependencies
-     */
-    @NotNull
-    Dependency[] getDependencies();
-
-    /**
      * Sets the dependencies to this definition and stores it in a node representation.
      * @param dependencies the package dependencies
      * @param autoSave if {@code true} the modifications are saved automatically.
@@ -313,50 +299,6 @@ public interface JcrPackageDefinition {
     void setFilter(@Nullable WorkspaceFilter filter, boolean autoSave);
 
     /**
-     * Returns the last modified date
-     * @return the last modified date
-     */
-    @Nullable
-    Calendar getLastModified();
-
-    /**
-     * Returns the last modified user id
-     * @return the last modified user id
-     */
-    @Nullable
-    String getLastModifiedBy();
-
-    /**
-     * Returns the created date
-     * @return the created date
-     */
-    @Nullable
-    Calendar getCreated();
-
-    /**
-     * Returns the creator user id
-     * @return the creator
-     */
-    @Nullable
-    String getCreatedBy();
-
-    /**
-     * Returns the last wrapped date
-     * @return the last wrapped date
-     * @since 2.2.22
-     */
-    @Nullable
-    Calendar getLastWrapped();
-
-    /**
-     * Returns the wrapper user id
-     * @return the wrapper
-     * @since 2.2.22
-     */
-    @Nullable
-    String getLastWrappedBy();
-
-    /**
      * Returns the last unwrapped date
      * @return the last unwrapped date
      */
@@ -385,42 +327,17 @@ public interface JcrPackageDefinition {
     String getLastUnpackedBy();
 
     /**
-     * Returns {@code true} if this package needs a admin user to install it.
-     * @return the "requires root" flag
-     * @deprecated
-     */
-    @Deprecated
-    boolean requiresRoot();
-
-    /**
-     * Returns {@code true} if this package needs restart after installation.
-     * @return the "requires restart" flag.
-     */
-    boolean requiresRestart();
-
-    /**
      * Returns the access control handling defined in the definition, or {@code null}
      * if not defined.
      * @return the access control handling or {@code null}
      * @since 2.3.2
+     * @deprecated Use {@link PackageProperties#getACHandling} retrieved via {@link #getMetaInf()} and {@link MetaInf#getPackageProperties()}.
      */
     @Nullable
+    @Deprecated
     AccessControlHandling getAccessControlHandling();
 
     /**
-     * Returns the description of this package
-     * @return the description
-     */
-    @Nullable
-    String getDescription();
-
-    /**
-     * Returns the build count of this package
-     * @return the build count.
-     */
-    long getBuildCount();
-
-    /**
      * Returns the meta inf of this package
      * @return the meta inf
      * @throws RepositoryException if an error occurs.
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/PackageProperties.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/PackageProperties.java
index fa10e85..9c9c6d9 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/PackageProperties.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/PackageProperties.java
@@ -267,6 +267,12 @@ public interface PackageProperties {
     boolean requiresRoot();
 
     /**
+     * Returns {@code true} if this package requires a restart after installation.
+     * @return {@code true} if this package requires a restart after installation.
+     */
+    boolean requiresRestart();
+
+    /**
      * Returns an unmodifiable list of dependencies
      * @return list of dependencies
      */
@@ -317,4 +323,10 @@ public interface PackageProperties {
      * @return dependencies locations as map
      */
     @NotNull Map<PackageId, URI> getDependenciesLocations();
+
+    /**
+     * Returns the build count of this package
+     * @return the build count.
+     */
+    long getBuildCount();
 }
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageDefinitionImpl.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageDefinitionImpl.java
index ae05b63..48a6294 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageDefinitionImpl.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageDefinitionImpl.java
@@ -18,12 +18,15 @@
 package org.apache.jackrabbit.vault.packaging.impl;
 
 import java.io.IOException;
+import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
 import javax.jcr.Node;
@@ -40,8 +43,6 @@ import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener;
 import org.apache.jackrabbit.vault.fs.api.RepositoryAddress;
 import org.apache.jackrabbit.vault.fs.api.VaultFileSystem;
 import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
-import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
-import org.apache.jackrabbit.vault.fs.config.DefaultMetaInf;
 import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
 import org.apache.jackrabbit.vault.fs.config.MetaInf;
 import org.apache.jackrabbit.vault.fs.io.AbstractExporter;
@@ -52,6 +53,9 @@ import org.apache.jackrabbit.vault.packaging.Dependency;
 import org.apache.jackrabbit.vault.packaging.ExportPostProcessor;
 import org.apache.jackrabbit.vault.packaging.JcrPackageDefinition;
 import org.apache.jackrabbit.vault.packaging.PackageId;
+import org.apache.jackrabbit.vault.packaging.PackageProperties;
+import org.apache.jackrabbit.vault.packaging.PackageType;
+import org.apache.jackrabbit.vault.packaging.SubPackageHandling;
 import org.apache.jackrabbit.vault.packaging.VaultPackage;
 import org.apache.jackrabbit.vault.util.Constants;
 import org.apache.jackrabbit.vault.util.Text;
@@ -99,6 +103,7 @@ public class JcrPackageDefinitionImpl implements JcrPackageDefinition {
     /**
      * {@inheritDoc}
      */
+    @SuppressWarnings("deprecation")
     public PackageId getId() {
         String group = get(PN_GROUP);
         String name = get(PN_NAME);
@@ -198,9 +203,6 @@ public class JcrPackageDefinitionImpl implements JcrPackageDefinition {
         return mod.after(uw);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     public void unwrap(VaultPackage pack, boolean force)
             throws RepositoryException, IOException {
         unwrap(pack, force, true);
@@ -222,9 +224,6 @@ public class JcrPackageDefinitionImpl implements JcrPackageDefinition {
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     public void unwrap(Archive archive, boolean autoSave)
             throws RepositoryException, IOException {
         if (archive != null) {
@@ -237,7 +236,7 @@ public class JcrPackageDefinitionImpl implements JcrPackageDefinition {
                 JcrWorkspaceFilter.saveFilter(inf.getFilter(), defNode, false);
             }
             if (inf.getProperties() != null) {
-                writeProperties(inf.getProperties());
+                writeProperties(inf.getPackageProperties());
             }
         }
         defNode.setProperty("unwrapped", (Value) null);
@@ -354,69 +353,19 @@ public class JcrPackageDefinitionImpl implements JcrPackageDefinition {
     }
 
     /**
-     * Load the given properties from the content
-     * @param props the properties to load
-     */
-    private void loadProperties(Properties props) {
-        PackageId id = getId();
-        setProperty(props, VaultPackage.NAME_VERSION, id.getVersionString());
-        setProperty(props, VaultPackage.NAME_NAME, id.getName());
-        setProperty(props, VaultPackage.NAME_GROUP, id.getGroup());
-        setProperty(props, VaultPackage.NAME_BUILD_COUNT, get(PN_BUILD_COUNT));
-        setProperty(props, VaultPackage.NAME_DESCRIPTION, get(PN_DESCRIPTION));
-        setProperty(props, VaultPackage.NAME_REQUIRES_ROOT, get(PN_REQUIRES_ROOT));
-        setProperty(props, VaultPackage.NAME_REQUIRES_RESTART, get(PN_REQUIRES_RESTART));
-        setProperty(props, VaultPackage.NAME_LAST_MODIFIED, getCalendar(PN_LASTMODIFIED));
-        setProperty(props, VaultPackage.NAME_LAST_MODIFIED_BY, get(PN_LASTMODIFIED_BY));
-        setProperty(props, VaultPackage.NAME_LAST_WRAPPED, getCalendar(PN_LAST_WRAPPED));
-        setProperty(props, VaultPackage.NAME_LAST_WRAPPED_BY, get(PN_LAST_WRAPPED_BY));
-        setProperty(props, VaultPackage.NAME_CREATED, getCalendar(PN_CREATED));
-        setProperty(props, VaultPackage.NAME_CREATED_BY, get(PN_CREATED_BY));
-        setProperty(props, VaultPackage.NAME_DEPENDENCIES, Dependency.toString(getDependencies()));
-        setProperty(props, VaultPackage.NAME_AC_HANDLING, get(PN_AC_HANDLING));
-        setProperty(props, VaultPackage.NAME_CND_PATTERN, get(PN_CND_PATTERN));
-    }
-
-    /**
-     * internal method that adds or removes a property
-     * @param props the properties
-     * @param name the name of the properties
-     * @param value the value
-     */
-    private static void setProperty(Properties props, String name, String value) {
-        if (value == null) {
-            props.remove(name);
-        } else {
-            props.put(name, value);
-        }
-    }
-
-    /**
-     * internal method that adds or removes a property
-     * @param props the properties
-     * @param name the name of the properties
-     * @param value the value
-     */
-    private static void setProperty(Properties props, String name, Calendar value) {
-        if (value == null) {
-            props.remove(name);
-        } else {
-            props.put(name, ISO8601.format(value));
-        }
-    }
-
-    /**
      * Writes the given properties to the content.
      * @param props the properties
      */
-    private void writeProperties(Properties props) {
+    private void writeProperties(PackageProperties props) {
         try {
             // sanitize lastModBy property due to former bug that used the
             // lastMod value
+            final String lastModifiedBy;
             if (props.getProperty(VaultPackage.NAME_LAST_MODIFIED) != null
                     && props.getProperty(VaultPackage.NAME_LAST_MODIFIED).equals(props.getProperty(VaultPackage.NAME_LAST_MODIFIED_BY))) {
-                props = new Properties(props);
-                props.setProperty(VaultPackage.NAME_LAST_MODIFIED_BY, "unknown");
+                lastModifiedBy = "unknown";
+            } else {
+                lastModifiedBy = props.getLastModifiedBy();
             }
 
             // Note that the 'path', 'group' and 'name' properties are usually
@@ -424,10 +373,10 @@ public class JcrPackageDefinitionImpl implements JcrPackageDefinition {
             // however, if a definition is unwrapped at another location, eg
             // in package-share, it is convenient if the original properties
             // are available in the content.
-            defNode.setProperty(PN_VERSION, props.getProperty(VaultPackage.NAME_VERSION));
+            defNode.setProperty(PN_VERSION, props.getId().getVersionString());
             defNode.setProperty(PN_BUILD_COUNT, props.getProperty(VaultPackage.NAME_BUILD_COUNT));
-            defNode.setProperty(PN_NAME, props.getProperty(VaultPackage.NAME_NAME));
-            defNode.setProperty(PN_GROUP, props.getProperty(VaultPackage.NAME_GROUP));
+            defNode.setProperty(PN_NAME, props.getId().getName());
+            defNode.setProperty(PN_GROUP, props.getId().getGroup());
             String deps = props.getProperty(VaultPackage.NAME_DEPENDENCIES);
             if (defNode.hasProperty(PN_DEPENDENCIES)) {
                 defNode.getProperty(PN_DEPENDENCIES).remove();
@@ -441,15 +390,15 @@ public class JcrPackageDefinitionImpl implements JcrPackageDefinition {
                 }
                 defNode.setProperty(PN_DEPENDENCIES, ds.toArray(new String[ds.size()]));
             }
-            defNode.setProperty(PN_DESCRIPTION, props.getProperty(VaultPackage.NAME_DESCRIPTION));
-            defNode.setProperty(PN_REQUIRES_ROOT, Boolean.valueOf(props.getProperty(VaultPackage.NAME_REQUIRES_ROOT, "false")));
-            defNode.setProperty(PN_REQUIRES_RESTART, Boolean.valueOf(props.getProperty(VaultPackage.NAME_REQUIRES_RESTART, "false")));
-            defNode.setProperty(PN_LASTMODIFIED, getDate(props.getProperty(VaultPackage.NAME_LAST_MODIFIED)));
-            defNode.setProperty(PN_LASTMODIFIED_BY, props.getProperty(VaultPackage.NAME_LAST_MODIFIED_BY));
-            defNode.setProperty(PN_CREATED, getDate(props.getProperty(VaultPackage.NAME_CREATED)));
-            defNode.setProperty(PN_CREATED_BY, props.getProperty(VaultPackage.NAME_CREATED_BY));
-            defNode.setProperty(PN_LAST_WRAPPED, getDate(props.getProperty(VaultPackage.NAME_LAST_WRAPPED)));
-            defNode.setProperty(PN_LAST_WRAPPED_BY, props.getProperty(VaultPackage.NAME_LAST_WRAPPED_BY));
+            defNode.setProperty(PN_DESCRIPTION, props.getDescription());
+            defNode.setProperty(PN_REQUIRES_ROOT, props.requiresRoot());
+            defNode.setProperty(PN_REQUIRES_RESTART, props.requiresRestart());
+            defNode.setProperty(PN_LASTMODIFIED, props.getLastModified());
+            defNode.setProperty(PN_LASTMODIFIED_BY, lastModifiedBy);
+            defNode.setProperty(PN_CREATED, props.getCreated());
+            defNode.setProperty(PN_CREATED_BY, props.getCreatedBy());
+            defNode.setProperty(PN_LAST_WRAPPED, props.getLastWrapped());
+            defNode.setProperty(PN_LAST_WRAPPED_BY,props.getLastWrappedBy());
             defNode.setProperty(PN_AC_HANDLING, props.getProperty(VaultPackage.NAME_AC_HANDLING));
             defNode.setProperty(PN_CND_PATTERN, props.getProperty(VaultPackage.NAME_CND_PATTERN));
             defNode.setProperty(PN_DISABLE_INTERMEDIATE_SAVE, props.getProperty(VaultPackage.NAME_DISABLE_INTERMEDIATE_SAVE));
@@ -458,25 +407,6 @@ public class JcrPackageDefinitionImpl implements JcrPackageDefinition {
         }
     }
 
-    /**
-     * Internal method that converts a ISO date to a calendar.
-     * @param iso the iso8601 formatted date
-     * @return the calendar or {@code null}
-     */
-    private static Calendar getDate(String iso) {
-        if (iso == null) {
-            return null;
-        }
-        // check for missing : in timezone part
-        String tzd = iso.substring(iso.length() - 4);
-        if (tzd.indexOf(':') < 0) {
-            iso = iso.substring(0, iso.length() - 4);
-            iso += tzd.substring(0, 2);
-            iso += ":";
-            iso += tzd.substring(2);
-        }
-        return ISO8601.parse(iso);
-    }
 
     /**
      * {@inheritDoc}
@@ -777,15 +707,7 @@ public class JcrPackageDefinitionImpl implements JcrPackageDefinition {
      * {@inheritDoc}
      */
     public AccessControlHandling getAccessControlHandling() {
-        String acHandling = get(PN_AC_HANDLING);
-        try {
-            return acHandling == null
-                    ? null
-                    : AccessControlHandling.valueOf(acHandling.toUpperCase());
-        } catch (IllegalArgumentException e) {
-            log.warn("invalid access control handling in definition: {} of {}", acHandling, getId());
-            return null;
-        }
+        return getACHandling();
     }
 
     /**
@@ -808,19 +730,66 @@ public class JcrPackageDefinitionImpl implements JcrPackageDefinition {
         }
     }
 
+
     /**
-     * {@inheritDoc}
+     * Load the given properties from the content
+     * @param props the properties to load
      */
-    public MetaInf getMetaInf() throws RepositoryException {
-        DefaultMetaInf inf = new DefaultMetaInf();
-        inf.setFilter(JcrWorkspaceFilter.loadFilter(defNode));
-
-        // add properties
+    private Properties loadLegacyProperties() {
         Properties props = new Properties();
-        loadProperties(props);
-        inf.setProperties(props);
+        PackageId id = getId();
+        setProperty(props, VaultPackage.NAME_VERSION, id.getVersionString());
+        setProperty(props, VaultPackage.NAME_NAME, id.getName());
+        setProperty(props, VaultPackage.NAME_GROUP, id.getGroup());
+        setProperty(props, VaultPackage.NAME_BUILD_COUNT, get(PN_BUILD_COUNT));
+        setProperty(props, VaultPackage.NAME_DESCRIPTION, get(PN_DESCRIPTION));
+        setProperty(props, VaultPackage.NAME_REQUIRES_ROOT, get(PN_REQUIRES_ROOT));
+        setProperty(props, VaultPackage.NAME_REQUIRES_RESTART, get(PN_REQUIRES_RESTART));
+        setProperty(props, VaultPackage.NAME_LAST_MODIFIED, getCalendar(PN_LASTMODIFIED));
+        setProperty(props, VaultPackage.NAME_LAST_MODIFIED_BY, get(PN_LASTMODIFIED_BY));
+        setProperty(props, VaultPackage.NAME_LAST_WRAPPED, getCalendar(PN_LAST_WRAPPED));
+        setProperty(props, VaultPackage.NAME_LAST_WRAPPED_BY, get(PN_LAST_WRAPPED_BY));
+        setProperty(props, VaultPackage.NAME_CREATED, getCalendar(PN_CREATED));
+        setProperty(props, VaultPackage.NAME_CREATED_BY, get(PN_CREATED_BY));
+        setProperty(props, VaultPackage.NAME_DEPENDENCIES, Dependency.toString(getDependencies()));
+        setProperty(props, VaultPackage.NAME_AC_HANDLING, get(PN_AC_HANDLING));
+        setProperty(props, VaultPackage.NAME_CND_PATTERN, get(PN_CND_PATTERN));
+        return props;
+    }
 
-        return inf;
+    /**
+     * internal method that adds or removes a property
+     * @param props the properties
+     * @param name the name of the properties
+     * @param value the value
+     */
+    private static void setProperty(Properties props, String name, String value) {
+        if (value == null) {
+            props.remove(name);
+        } else {
+            props.put(name, value);
+        }
+    }
+
+    /**
+     * internal method that adds or removes a property
+     * @param props the properties
+     * @param name the name of the properties
+     * @param value the value
+     */
+    private static void setProperty(Properties props, String name, Calendar value) {
+        if (value == null) {
+            props.remove(name);
+        } else {
+            props.put(name, ISO8601.format(value));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public MetaInf getMetaInf() throws RepositoryException {
+        return new JcrPackageDefinitionMetaInf(defNode, this, loadLegacyProperties());
     }
 
     /**
@@ -981,4 +950,53 @@ public class JcrPackageDefinitionImpl implements JcrPackageDefinition {
             }
         }
     }
+
+    @Override
+    public Map<String, String> getExternalHooks() {
+        // not stored
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public AccessControlHandling getACHandling() {
+        String acHandling = get(PN_AC_HANDLING);
+        try {
+            return acHandling == null
+                    ? null
+                    : AccessControlHandling.valueOf(acHandling.toUpperCase());
+        } catch (IllegalArgumentException e) {
+            log.warn("invalid access control handling in definition: {} of {}", acHandling, getId());
+            return null;
+        }
+    }
+
+    @Override
+    public SubPackageHandling getSubPackageHandling() {
+        // not stored
+        return null;
+    }
+
+    
+    @Override
+    public Calendar getDateProperty(String name) {
+        return getCalendar(name);
+    }
+
+    @Override
+    public String getProperty(String name) {
+        return get(name);
+    }
+
+    @Override
+    public @Nullable PackageType getPackageType() {
+        // not stored
+        return null;
+    }
+
+    @Override
+    public @NotNull Map<PackageId, URI> getDependenciesLocations() {
+        // not stored
+        return Collections.emptyMap();
+    }
+
 }
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageDefinitionMetaInf.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageDefinitionMetaInf.java
new file mode 100644
index 0000000..c3b371b
--- /dev/null
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageDefinitionMetaInf.java
@@ -0,0 +1,55 @@
+/*
+ * 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.util.Properties;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.vault.fs.config.DefaultMetaInf;
+import org.apache.jackrabbit.vault.packaging.PackageProperties;
+
+/**
+ * Only limited meta information like package properties and filters are exposed which are available
+ * from the underlying package definition node.
+ * Raw properties are exposed on a best effort basis, because the storage format is different from
+ * the one in {@code properties.xml}.
+ * Therefore it is recommended to use the high-level API exposed via {@link PackageProperties}.
+ */
+public class JcrPackageDefinitionMetaInf extends DefaultMetaInf  {
+
+    private final PackageProperties packageProperties;
+    private final Properties legacyProperties;
+
+    public JcrPackageDefinitionMetaInf(Node node, PackageProperties packageProperties, Properties legacyProperties) throws RepositoryException {
+        setFilter(JcrWorkspaceFilter.loadFilter(node));
+        this.packageProperties = packageProperties;
+        this.legacyProperties = legacyProperties;
+    }
+
+    @Override
+    public PackageProperties getPackageProperties() {
+        return packageProperties;
+    }
+
+    @Override
+    public Properties getProperties() {
+        return legacyProperties;
+    }
+}
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/PackagePropertiesImpl.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/PackagePropertiesImpl.java
index 59d92cc..33062c1 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/PackagePropertiesImpl.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/PackagePropertiesImpl.java
@@ -161,6 +161,14 @@ public abstract class PackagePropertiesImpl implements PackageProperties {
      * {@inheritDoc}
      */
     @Override
+    public boolean requiresRestart() {
+        return "true".equals(getProperty(NAME_REQUIRES_RESTART));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public Dependency[] getDependencies() {
         String deps = getProperty(NAME_DEPENDENCIES);
         if (deps == null) {
@@ -210,6 +218,7 @@ public abstract class PackagePropertiesImpl implements PackageProperties {
     @Override
     public Calendar getDateProperty(String name) {
         try {
+            // TODO: add timezone if not there?
             String p = getProperty(name);
             return p == null
                     ? null
@@ -271,6 +280,16 @@ public abstract class PackagePropertiesImpl implements PackageProperties {
         return hookClasses;
     }
 
+    @Override
+    public long getBuildCount() {
+        try {
+            return Long.parseLong(getProperty(NAME_BUILD_COUNT));
+        } catch (NumberFormatException e) {
+            log.warn("Invalid buildcount property, must be an integer");
+            return 0;
+        }
+    }
+
     protected abstract Properties getPropertiesMap();
 
 
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/package-info.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/package-info.java
index ef85b43..68b4700 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/package-info.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/package-info.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-@Version("2.10.0")
+@Version("2.11.0")
 package org.apache.jackrabbit.vault.packaging;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageDefinitionImplTest.java b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageDefinitionImplTest.java
new file mode 100644
index 0000000..3826833
--- /dev/null
+++ b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageDefinitionImplTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.IOException;
+
+import javax.jcr.ItemExistsException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.version.VersionException;
+
+import org.apache.jackrabbit.vault.fs.io.Archive;
+import org.apache.jackrabbit.vault.packaging.PackageProperties;
+import org.apache.jackrabbit.vault.packaging.integration.IntegrationTestBase;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+public class JcrPackageDefinitionImplTest extends IntegrationTestBase {
+
+    @Test
+    public void testUnwrapAndComparePackageProperties() throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException, RepositoryException, IOException {
+        // new node
+        Node node = admin.getRootNode().addNode("packagedefinitiontest");
+        JcrPackageDefinitionImpl packageDefinition = new JcrPackageDefinitionImpl(node);
+        try (Archive archive = getFileArchive("/test-packages/principalbased.zip")) {
+            archive.open(false);
+            packageDefinition.unwrap(archive, false);
+            // now compare the package properties
+            assertPackagePropertiesEquals(archive.getMetaInf().getPackageProperties(), packageDefinition);
+            
+            Assert.assertEquals("bar", archive.getMetaInf().getPackageProperties().getProperty("foo"));
+            // custom properties are not part of the unwrapped node
+            Assert.assertNull(packageDefinition.getProperty("foo"));
+        }
+    }
+
+    void assertPackagePropertiesEquals(PackageProperties expectedProperties, PackageProperties actualProperties) {
+        Assert.assertEquals("lastModified is different", expectedProperties.getLastModified(), actualProperties.getLastModified());
+        Assert.assertEquals("lastModifiedBy is different", expectedProperties.getLastModifiedBy(), actualProperties.getLastModifiedBy());
+        Assert.assertEquals("created is different", expectedProperties.getCreated(), actualProperties.getCreated());
+        Assert.assertEquals("createdBy is different", expectedProperties.getCreatedBy(), actualProperties.getCreatedBy());
+        Assert.assertEquals("lastWrapped is different", expectedProperties.getLastWrapped(), actualProperties.getLastWrapped());
+        Assert.assertEquals("lastWrappedBy is different", expectedProperties.getLastWrappedBy(), actualProperties.getLastWrappedBy());
+        Assert.assertEquals("description is different", expectedProperties.getDescription(), actualProperties.getDescription());
+        Assert.assertEquals("acHandling is different", expectedProperties.getACHandling(), actualProperties.getACHandling());
+        Assert.assertEquals("id (group, name or version) is different", expectedProperties.getId(), actualProperties.getId());
+        Assert.assertArrayEquals("dependencies are different", expectedProperties.getDependencies(), actualProperties.getDependencies());
+        Assert.assertEquals("requiresRestart is different", expectedProperties.requiresRestart(), actualProperties.requiresRestart());
+        Assert.assertEquals("requiresRoot is different", expectedProperties.requiresRoot(), actualProperties.requiresRoot());
+    }
+}
diff --git a/vault-core/src/test/resources/test-packages/principalbased.zip/META-INF/vault/properties.xml b/vault-core/src/test/resources/test-packages/principalbased.zip/META-INF/vault/properties.xml
index 7716d3a..d7aaea8 100644
--- a/vault-core/src/test/resources/test-packages/principalbased.zip/META-INF/vault/properties.xml
+++ b/vault-core/src/test/resources/test-packages/principalbased.zip/META-INF/vault/properties.xml
@@ -4,17 +4,19 @@
 <comment>FileVault Package Properties</comment>
 <entry key="createdBy">admin</entry>
 <entry key="name">principalbased_overwrite</entry>
-<entry key="lastModified">2019-07-23T10:20:20.089+02:00</entry>
+<entry key="lastModified">2019-07-23T10:20:20.089Z</entry>
 <entry key="lastModifiedBy">admin</entry>
 <entry key="created">2019-07-23T10:20:20.170+02:00</entry>
 <entry key="buildCount">1</entry>
-<entry key="version"/>
+<entry key="version">2</entry>
 <entry key="packageType">content</entry>
-<entry key="dependencies"/>
+<entry key="dependencies">depgroup:dep1:1,depgroup:dep2:2</entry>
 <entry key="packageFormatVersion">2</entry>
 <entry key="description"/>
 <entry key="lastWrapped">2019-07-23T10:20:20.089+02:00</entry>
 <entry key="group">integrationtesting</entry>
 <entry key="lastWrappedBy">admin</entry>
 <entry key="acHandling">OVERWRITE</entry>
+<entry key="requiresRoot">true</entry>
+<entry key="foo">bar</entry>
 </properties>