Merge pull request #1 from apache/SLING-8243
Sling 8243 - support merge options
diff --git a/pom.xml b/pom.xml
index bab7bf3..b5172c7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@
</parent>
<artifactId>org.apache.sling.jcr.contentloader</artifactId>
- <version>2.3.1-SNAPSHOT</version>
+ <version>2.4.0-SNAPSHOT</version>
<name>Apache Sling Initial Content Loader</name>
<description>This bundle provides initial content installation through bundles.</description>
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/ContentCreator.java b/src/main/java/org/apache/sling/jcr/contentloader/ContentCreator.java
index a663c51..4c8a165 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/ContentCreator.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/ContentCreator.java
@@ -59,6 +59,14 @@
*/
void finishNode() throws RepositoryException;
+
+ /**
+ * Indicates that the import is finished
+ *
+ * @throws RepositoryException
+ */
+ void finish() throws RepositoryException;
+
/**
* Create a new property to the current node.
*
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java b/src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java
index 316d7d9..f66d680 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java
@@ -33,6 +33,16 @@
* @return true to overwrite nodes, false otherwise
*/
public abstract boolean isOverwrite();
+
+ /**
+ * Specifies whether imported nodes should merge with existing nodes.
+ * NOTE: this means the existing nodes that are not imported will be
+ * deleted.
+ * @return true to overwrite nodes, false otherwise
+ */
+ public boolean isMerge() {
+ return false;
+ }
/**
* Specifies whether imported properties should overwrite existing properties.
@@ -40,6 +50,16 @@
*/
public abstract boolean isPropertyOverwrite();
+ /**
+ * Specifies whether imported properties should merge with existing properties.
+ * NOTE: this means that properties that are not imported
+ * will be removed
+ * @return true to overwrite nodes, false otherwise
+ */
+ public boolean isPropertyMerge() {
+ return false;
+ }
+
/**
* Specifies whether versionable nodes is automatically checked in at the
* end of the import operation.
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoader.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoader.java
index 2d7be2c..84dbeb6 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoader.java
@@ -65,7 +65,7 @@
public BundleContentLoader(BundleHelper bundleHelper, ContentReaderWhiteboard contentReaderWhiteboard) {
super(contentReaderWhiteboard);
this.bundleHelper = bundleHelper;
- this.delayedBundles = new LinkedList<Bundle>();
+ this.delayedBundles = new LinkedList<>();
}
public void dispose() {
@@ -83,7 +83,7 @@
* @param bundle
* @throws RepositoryException
*/
- public void registerBundle(final Session metadataSession, final Bundle bundle, final boolean isUpdate) throws RepositoryException {
+ public void registerBundle(final Session metadataSession, final Bundle bundle, final boolean isUpdate) {
// if this is an update, we have to uninstall the old content first
if (isUpdate) {
@@ -136,11 +136,8 @@
final boolean contentAlreadyLoaded = ((Boolean) bundleContentInfo.get(ContentLoaderService.PROPERTY_CONTENT_LOADED)).booleanValue();
boolean isBundleUpdated = false;
Calendar lastLoadedAt = (Calendar) bundleContentInfo.get(ContentLoaderService.PROPERTY_CONTENT_LOADED_AT);
- if (lastLoadedAt != null) {
- // this assumes that the bundle has been installed or updated after the content has been loaded
- if (lastLoadedAt.getTimeInMillis() < bundle.getLastModified()) {
- isBundleUpdated = true;
- }
+ if (lastLoadedAt != null && lastLoadedAt.getTimeInMillis() < bundle.getLastModified()) {
+ isBundleUpdated = true;
}
if (!isUpdate && !isBundleUpdated && contentAlreadyLoaded) {
log.info("Content of bundle already loaded {}.", bundle.getSymbolicName());
@@ -210,8 +207,8 @@
*/
private List<String> installContent(final Session defaultSession, final Bundle bundle, final Iterator<PathEntry> pathIter, final boolean contentAlreadyLoaded) throws RepositoryException {
- final List<String> createdNodes = new ArrayList<String>();
- final Map<String, Session> createdSessions = new HashMap<String, Session>();
+ final List<String> createdNodes = new ArrayList<>();
+ final Map<String, Session> createdSessions = new HashMap<>();
log.debug("Installing initial content from bundle {}", bundle.getSymbolicName());
final DefaultContentCreator contentCreator = new DefaultContentCreator(this.bundleHelper);
@@ -307,7 +304,7 @@
// init content creator
contentCreator.init(configuration, getContentReaders(), createdNodes, null);
- final Map<String, Node> processedEntries = new HashMap<String, Node>();
+ final Map<String, Node> processedEntries = new HashMap<>();
Enumeration<String> entries = bundle.getEntryPaths(path);
if (entries == null) {
@@ -486,7 +483,7 @@
return contentCreator.getCreatedRootNode();
} catch (RepositoryException re) {
throw re;
- } catch (Throwable t) {
+ } catch (Exception t) {
throw new RepositoryException(t.getMessage(), t);
} finally {
IOUtils.closeQuietly(contentStream);
@@ -529,7 +526,7 @@
private void createFile(PathEntry configuration, Node parent, URL source, List<String> createdNodes, final DefaultContentCreator contentCreator) throws IOException, RepositoryException {
final String srcPath = source.getPath();
- int pos = srcPath.lastIndexOf("/");
+ int pos = srcPath.lastIndexOf('/');
final String name = getName(source.getPath());
final String path;
if (pos == -1) {
@@ -615,7 +612,7 @@
private void uninstallContent(final Session defaultSession, final Bundle bundle, final String[] uninstallPaths) {
- final Map<String, Session> createdSessions = new HashMap<String, Session>();
+ final Map<String, Session> createdSessions = new HashMap<>();
try {
log.debug("Uninstalling initial content from bundle {}", bundle.getSymbolicName());
@@ -678,7 +675,7 @@
public URL url;
- public ContentReader contentReader;
+ private ContentReader contentReader;
}
@@ -726,7 +723,7 @@
return descriptor.url;
} catch (RepositoryException re) {
throw re;
- } catch (Throwable t) {
+ } catch (Exception t) {
throw new RepositoryException(t.getMessage(), t);
}
}
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentLoaderService.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentLoaderService.java
index 29968a1..e6ee7b4 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentLoaderService.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentLoaderService.java
@@ -148,7 +148,7 @@
final boolean isUpdate;
isUpdate = this.updatedBundles.remove(bundle.getSymbolicName());
bundleContentLoader.registerBundle(session, bundle, isUpdate);
- } catch (Throwable t) {
+ } catch (Exception t) {
log.error(
"bundleChanged: Problem loading initial content of bundle "
+ bundle.getSymbolicName() + " ("
@@ -166,7 +166,7 @@
try {
session = this.getSession();
bundleContentLoader.unregisterBundle(session, bundle);
- } catch (Throwable t) {
+ } catch (Exception t) {
log.error(
"bundleChanged: Problem unloading initial content of bundle "
+ bundle.getSymbolicName() + " ("
@@ -175,6 +175,7 @@
this.ungetSession(session);
}
break;
+ default:
}
}
@@ -237,21 +238,9 @@
Bundle[] bundles = bundleContext.getBundles();
for (Bundle bundle : bundles) {
if ((bundle.getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED)) == 0) {
-
// load content for bundles which are neither INSTALLED nor
// UNINSTALLED
- try {
- bundleContentLoader.registerBundle(session, bundle, false);
- } catch (Throwable t) {
- log.error(
- "Problem loading initial content of bundle "
- + bundle.getSymbolicName() + " ("
- + bundle.getBundleId() + ")", t);
- } finally {
- if ( session.hasPendingChanges() ) {
- session.refresh(false);
- }
- }
+ loadBundle(bundle, session);
} else {
ignored++;
}
@@ -263,13 +252,28 @@
bundles.length, ignored
);
- } catch (Throwable t) {
+ } catch (Exception t) {
log.error("activate: Problem while loading initial content and"
+ " registering mappings for existing bundles", t);
} finally {
this.ungetSession(session);
}
}
+
+ private void loadBundle(Bundle bundle, Session session) throws RepositoryException {
+ try {
+ bundleContentLoader.registerBundle(session, bundle, false);
+ } catch (Exception t) {
+ log.error(
+ "Problem loading initial content of bundle "
+ + bundle.getSymbolicName() + " ("
+ + bundle.getBundleId() + ")", t);
+ } finally {
+ if ( session.hasPendingChanges() ) {
+ session.refresh(false);
+ }
+ }
+ }
/** Deactivates this component, called by SCR to take out of service */
@Deactivate
@@ -313,7 +317,7 @@
if ( session != null ) {
try {
session.logout();
- } catch (Throwable t) {
+ } catch (Exception t) {
log.error("Unable to log out of session: " + t.getMessage(), t);
}
}
@@ -395,7 +399,7 @@
bcNode.setProperty(PROPERTY_CONTENT_LOADED_BY, this.slingId);
bcNode.setProperty(PROPERTY_CONTENT_UNLOADED_AT, (String)null);
bcNode.setProperty(PROPERTY_CONTENT_UNLOADED_BY, (String)null);
- if ( createdNodes != null && createdNodes.size() > 0 ) {
+ if ( createdNodes != null && !createdNodes.isEmpty() ) {
bcNode.setProperty(PROPERTY_UNINSTALL_PATHS, createdNodes.toArray(new String[createdNodes.size()]));
}
session.save();
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReaderWhiteboard.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReaderWhiteboard.java
index ed24e66..3c6062e 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReaderWhiteboard.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReaderWhiteboard.java
@@ -63,7 +63,7 @@
}
}
- protected void unbindContentReader(final ContentReader operation, final Map<String, Object> properties) {
+ protected void unbindContentReader(final Map<String, Object> properties) {
final String[] extensions = PropertiesUtil.toStringArray(properties.get(ContentReader.PROPERTY_EXTENSIONS));
final String[] types = PropertiesUtil.toStringArray(properties.get(ContentReader.PROPERTY_TYPES));
if (readersByExtension != null && extensions != null) {
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
index 7ac6388..c95bd8c 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
@@ -23,22 +23,30 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Calendar;
+import java.util.Collections;
import java.util.Date;
+import java.util.Deque;
import java.util.HashMap;
-import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.Stack;
import java.util.StringTokenizer;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
import javax.jcr.Binary;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
@@ -67,23 +75,25 @@
*/
public class DefaultContentCreator implements ContentCreator {
+ private static final String JCR_LAST_MODIFIED = "jcr:lastModified";
+
final Logger log = LoggerFactory.getLogger(DefaultContentCreator.class);
private ImportOptions configuration;
- private final Stack<Node> parentNodeStack = new Stack<Node>();
+ private final Deque<Node> parentNodeStack = new ArrayDeque<>();
/**
* The list of versionables.
*/
- private final List<Node> versionables = new ArrayList<Node>();
+ private final List<Node> versionables = new ArrayList<>();
/**
* Delayed references during content loading for the reference property.
*/
- private final Map<String, List<String>> delayedReferences = new HashMap<String, List<String>>();
+ private final Map<String, List<String>> delayedReferences = new HashMap<>();
- private final Map<String, String[]> delayedMultipleReferences = new HashMap<String, String[]>();
+ private final Map<String, String[]> delayedMultipleReferences = new HashMap<>();
private String defaultName;
@@ -116,20 +126,25 @@
*/
private ContentImportListener importListener;
+ private Set<String> appliedSet = new LinkedHashSet<>();
+ private Set<String> importedNodes = new LinkedHashSet<>();
+
/**
* A one time use seed to randomize the user location.
*/
private static final long INSTANCE_SEED = System.currentTimeMillis();
/**
- * The number of levels folder used to store a user, could be a configuration option.
+ * The number of levels folder used to store a user, could be a configuration
+ * option.
*/
private static final int STORAGE_LEVELS = 3;
/**
* Constructor.
*
- * @param contentHelper Helper class to get the mime type of a file
+ * @param contentHelper
+ * Helper class to get the mime type of a file
*/
public DefaultContentCreator(ContentHelper contentHelper) {
this.contentHelper = contentHelper;
@@ -138,21 +153,23 @@
/**
* Initialize this component.
*
- * @param pathEntry The configuration for this import.
- * @param defaultContentReaders List of all content readers.
- * @param createdNodes Optional list to store new nodes (for uninstall)
+ * @param options
+ * The configuration for this import.
+ * @param defaultContentReaders
+ * List of all content readers.
+ * @param createdNodes
+ * Optional list to store new nodes (for uninstall)
*/
- public void init(final ImportOptions pathEntry, final Map<String, ContentReader> defaultContentReaders, final List<String> createdNodes, final ContentImportListener importListener) {
- this.configuration = pathEntry;
+ public void init(final ImportOptions options, final Map<String, ContentReader> defaultContentReaders,
+ final List<String> createdNodes, final ContentImportListener importListener) {
+ this.configuration = options;
// create list of allowed content readers
- this.contentReaders = new HashMap<String, ContentReader>();
- final Iterator<Map.Entry<String, ContentReader>> entryIter = defaultContentReaders.entrySet().iterator();
- while (entryIter.hasNext()) {
- final Map.Entry<String, ContentReader> current = entryIter.next();
- if (!configuration.isIgnoredImportProvider(current.getKey())) {
- contentReaders.put(current.getKey(), current.getValue());
+ this.contentReaders = new HashMap<>();
+ defaultContentReaders.forEach((key,value)->{
+ if (!configuration.isIgnoredImportProvider(key)) {
+ contentReaders.put(key, value);
}
- }
+ });
this.createdNodes = createdNodes;
this.importListener = importListener;
}
@@ -211,7 +228,8 @@
}
/**
- * @see org.apache.sling.jcr.contentloader.ContentCreator#createNode(java.lang.String, java.lang.String, java.lang.String[])
+ * @see org.apache.sling.jcr.contentloader.ContentCreator#createNode(java.lang.String,
+ * java.lang.String, java.lang.String[])
*/
public void createNode(String name, String primaryNodeType, String[] mixinNodeTypes) throws RepositoryException {
final Node parentNode = this.parentNodeStack.peek();
@@ -223,7 +241,8 @@
name = this.defaultName;
}
- // if we are in parent node import mode, we don't create the root top level node!
+ // if we are in parent node import mode, we don't create the root top level
+ // node!
if (!isParentImport || this.parentNodeStack.size() > 1) {
// if node already exists but should be overwritten, delete it
if (!this.ignoreOverwriteFlag && this.configuration.isOverwrite() && parentNode.hasNode(name)) {
@@ -262,7 +281,9 @@
}
}
}
-
+
+ importedNodes.add(node.getPath());
+
// check if node is versionable
final boolean addToVersionables = this.configuration.isCheckin() && node.isNodeType("mix:versionable");
if (addToVersionables) {
@@ -277,11 +298,14 @@
}
/**
- * @see org.apache.sling.jcr.contentloader.ContentCreator#createProperty(java.lang.String, int, java.lang.String)
+ * @see org.apache.sling.jcr.contentloader.ContentCreator#createProperty(java.lang.String,
+ * int, java.lang.String)
*/
public void createProperty(String name, int propertyType, String value) throws RepositoryException {
+ appliedSet.add(name);
final Node node = this.parentNodeStack.peek();
- // check if the property already exists and isPropertyOverwrite() is false, don't overwrite it in this case
+ // check if the property already exists and isPropertyOverwrite() is false,
+ // don't overwrite it in this case
if (node.hasProperty(name) && !this.configuration.isPropertyOverwrite() && !node.getProperty(name).isNew()) {
return;
}
@@ -300,11 +324,9 @@
} else if ("jcr:isCheckedOut".equals(name)) {
// don't try to write the property but record its state
// for later checkin if set to false
- final boolean checkedout = Boolean.valueOf(value);
- if (!checkedout) {
- if (!this.versionables.contains(node)) {
- this.versionables.add(node);
- }
+ final boolean checkedout = Boolean.parseBoolean(value);
+ if (!checkedout && !this.versionables.contains(node)) {
+ this.versionables.add(node);
}
} else if (propertyType == PropertyType.DATE) {
checkoutIfNecessary(node);
@@ -326,11 +348,14 @@
}
/**
- * @see org.apache.sling.jcr.contentloader.ContentCreator#createProperty(java.lang.String, int, java.lang.String[])
+ * @see org.apache.sling.jcr.contentloader.ContentCreator#createProperty(java.lang.String,
+ * int, java.lang.String[])
*/
public void createProperty(String name, int propertyType, String[] values) throws RepositoryException {
+ appliedSet.add(name);
final Node node = this.parentNodeStack.peek();
- // check if the property already exists and isPropertyOverwrite() is false, don't overwrite it in this case
+ // check if the property already exists and isPropertyOverwrite() is false,
+ // don't overwrite it in this case
if (node.hasProperty(name) && !this.configuration.isPropertyOverwrite() && !node.getProperty(name).isNew()) {
return;
}
@@ -342,7 +367,8 @@
for (int i = 0; i < values.length; i++) {
uuids[i] = getUUID(node.getSession(), propPath, getAbsPath(node, values[i]));
uuidOrPaths[i] = uuids[i] != null ? uuids[i] : getAbsPath(node, values[i]);
- if (uuids[i] == null) hasAll = false;
+ if (uuids[i] == null)
+ hasAll = false;
}
checkoutIfNecessary(node);
node.setProperty(name, uuids, propertyType);
@@ -354,7 +380,7 @@
}
} else if (propertyType == PropertyType.DATE) {
checkoutIfNecessary(node);
-
+
// This modification is to remove the colon in the JSON Timezone
ValueFactory valueFactory = node.getSession().getValueFactory();
Value[] jcrValues = new Value[values.length];
@@ -364,7 +390,7 @@
}
node.setProperty(name, jcrValues, propertyType);
-
+
if (this.importListener != null) {
this.importListener.onCreate(node.getProperty(name).getPath());
}
@@ -398,22 +424,24 @@
} else if (value instanceof Boolean) {
return factory.createValue((Boolean) value);
} else if (value instanceof InputStream) {
- Binary binary = factory.createBinary((InputStream)value);
- return factory.createValue(binary);
+ Binary binary = factory.createBinary((InputStream) value);
+ return factory.createValue(binary);
} else {
return factory.createValue(value.toString());
}
}
/**
- * @see org.apache.sling.jcr.contentloader.ContentCreator#createProperty(java.lang.String, java.lang.Object)
+ * @see org.apache.sling.jcr.contentloader.ContentCreator#createProperty(java.lang.String,
+ * java.lang.Object)
*/
public void createProperty(String name, Object value) throws RepositoryException {
createProperty(name, value, false);
}
/**
- * @see org.apache.sling.jcr.contentloader.ContentCreator#createProperty(java.lang.String, java.lang.Object[])
+ * @see org.apache.sling.jcr.contentloader.ContentCreator#createProperty(java.lang.String,
+ * java.lang.Object[])
*/
public void createProperty(String name, Object[] values) throws RepositoryException {
createProperty(name, values, false);
@@ -424,8 +452,30 @@
*/
public void finishNode() throws RepositoryException {
final Node node = this.parentNodeStack.pop();
+ cleanUpNode(node);
// resolve REFERENCE property values pointing to this node
resolveReferences(node);
+ node.getSession().save();
+ }
+
+ private void cleanUpNode(Node node) throws RepositoryException {
+ if (configuration.isPropertyMerge()) {
+ PropertyIterator it = node.getProperties();
+ while (it.hasNext()) {
+ Property prop= it.nextProperty();
+ String propertyName = prop.getName();
+ if (appliedSet.contains(propertyName)) {
+ continue;
+ }
+ if (!prop.getDefinition().isProtected()) {
+ if (importListener != null) {
+ importListener.onDelete(prop.getPath());
+ }
+ prop.remove();
+ log.trace(propertyName);
+ }
+ }
+ }
}
private void addNodeToCreatedList(Node node) throws RepositoryException {
@@ -462,21 +512,16 @@
}
} else {
// not existing yet, keep for delayed setting
- List<String> current = delayedReferences.get(referencePath);
- if (current == null) {
- current = new ArrayList<String>();
- delayedReferences.put(referencePath, current);
- }
+ List<String> current = delayedReferences.computeIfAbsent(referencePath, k -> new ArrayList<>());
current.add(propPath);
}
-
// no UUID found
return null;
}
private void resolveReferences(Node node) throws RepositoryException {
List<String> props = delayedReferences.remove(node.getPath());
- if (props == null || props.size() == 0) {
+ if (props == null || props.isEmpty()) {
return;
}
@@ -529,17 +574,16 @@
}
/**
- * Gets the name part of the <code>path</code>. The name is
- * the part of the path after the last slash (or the complete path if no
- * slash is contained).
+ * Gets the name part of the <code>path</code>. The name is the part of the path
+ * after the last slash (or the complete path if no slash is contained).
*
- * @param path The path from which to extract the name part.
+ * @param path
+ * The path from which to extract the name part.
* @return The name part.
*/
private String getName(String path) {
int lastSlash = path.lastIndexOf('/');
- String name = (lastSlash < 0) ? path : path.substring(lastSlash + 1);
- return name;
+ return lastSlash < 0 ? path : path.substring(lastSlash + 1);
}
private Node getParentNode(Session session, String path) throws RepositoryException {
@@ -588,6 +632,7 @@
this.importListener.onModify(node.getProperty(name).getPath());
}
}
+ appliedSet.add(name);
}
private void createProperty(String name, Object[] values, boolean overwriteExisting) throws RepositoryException {
@@ -616,12 +661,15 @@
this.importListener.onModify(node.getProperty(name).getPath());
}
}
+ appliedSet.add(name);
}
/**
- * @see org.apache.sling.jcr.contentloader.ContentCreator#createFileAndResourceNode(java.lang.String, java.io.InputStream, java.lang.String, long)
+ * @see org.apache.sling.jcr.contentloader.ContentCreator#createFileAndResourceNode(java.lang.String,
+ * java.io.InputStream, java.lang.String, long)
*/
- public void createFileAndResourceNode(String name, InputStream data, String mimeType, long lastModified) throws RepositoryException {
+ public void createFileAndResourceNode(String name, InputStream data, String mimeType, long lastModified)
+ throws RepositoryException {
int lastSlash = name.lastIndexOf('/');
name = (lastSlash < 0) ? name : name.substring(lastSlash + 1);
final Node parentNode = this.parentNodeStack.peek();
@@ -632,13 +680,14 @@
Node contentNode = parentNode.getNode(name).getNode("jcr:content");
this.parentNodeStack.push(contentNode);
long nodeLastModified = 0L;
- if (contentNode.hasProperty("jcr:lastModified")) {
- nodeLastModified = contentNode.getProperty("jcr:lastModified").getDate().getTimeInMillis();
+ if (contentNode.hasProperty(JCR_LAST_MODIFIED)) {
+ nodeLastModified = contentNode.getProperty(JCR_LAST_MODIFIED).getDate().getTimeInMillis();
}
if (!this.configuration.isOverwrite() && nodeLastModified >= lastModified) {
return;
}
- log.info("Updating {} lastModified:{} New Content LastModified:{}", new Object[]{parentNode.getNode(name).getPath(), new Date(nodeLastModified), new Date(lastModified)});
+ log.debug("Updating {} lastModified:{} New Content LastModified:{}", parentNode.getNode(name).getPath(),
+ new Date(nodeLastModified), new Date(lastModified));
} else {
this.createNode(name, "nt:file", null);
this.createNode("jcr:content", "nt:resource", null);
@@ -648,7 +697,7 @@
if (mimeType == null) {
mimeType = contentHelper.getMimeType(name);
if (mimeType == null) {
- log.info("createFile: Cannot find content type for {}, using {}", name, DEFAULT_CONTENT_TYPE);
+ log.debug("createFile: Cannot find content type for {}, using {}", name, DEFAULT_CONTENT_TYPE);
mimeType = DEFAULT_CONTENT_TYPE;
}
}
@@ -658,12 +707,13 @@
lastModified = System.currentTimeMillis();
}
this.createProperty("jcr:mimeType", mimeType, true);
- this.createProperty("jcr:lastModified", lastModified, true);
+ this.createProperty(JCR_LAST_MODIFIED, lastModified, true);
this.createProperty("jcr:data", data, true);
}
/**
- * @see org.apache.sling.jcr.contentloader.ContentCreator#switchCurrentNode(java.lang.String, java.lang.String)
+ * @see org.apache.sling.jcr.contentloader.ContentCreator#switchCurrentNode(java.lang.String,
+ * java.lang.String)
*/
public boolean switchCurrentNode(String subPath, String newNodeType) throws RepositoryException {
if (subPath.startsWith("/")) {
@@ -690,10 +740,14 @@
return true;
}
- /* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.ContentCreator#createGroup(java.lang.String, java.lang.String[], java.util.Map)
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.sling.jcr.contentloader.ContentCreator#createGroup(java.lang.
+ * String, java.lang.String[], java.util.Map)
*/
- public void createGroup(final String name, String[] members, Map<String, Object> extraProperties) throws RepositoryException {
+ public void createGroup(final String name, String[] members, Map<String, Object> extraProperties)
+ throws RepositoryException {
final Node parentNode = this.parentNodeStack.peek();
Session session = parentNode.getSession();
@@ -701,23 +755,17 @@
UserManager userManager = AccessControlUtil.getUserManager(session);
Authorizable authorizable = userManager.getAuthorizable(name);
if (authorizable == null) {
- //principal does not exist yet, so create it
- Group group = userManager.createGroup(new Principal() {
- public String getName() {
- return name;
- }
- },
- hashPath(name)
- );
+ // principal does not exist yet, so create it
+ Group group = userManager.createGroup(() -> name, hashPath(name));
authorizable = group;
} else {
- //principal already exists, check to make sure it is the expected type
+ // principal already exists, check to make sure it is the expected type
if (!authorizable.isGroup()) {
throw new RepositoryException("A user already exists with the requested name: " + name);
}
- //group already exists so just update it below
+ // group already exists so just update it below
}
- //update the group members
+ // update the group members
if (members != null) {
Group group = (Group) authorizable;
for (String member : members) {
@@ -737,33 +785,29 @@
}
}
- /* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.ContentCreator#createUser(java.lang.String, java.lang.String, java.util.Map)
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.sling.jcr.contentloader.ContentCreator#createUser(java.lang.
+ * String, java.lang.String, java.util.Map)
*/
- public void createUser(final String name, String password, Map<String, Object> extraProperties) throws RepositoryException {
+ public void createUser(final String name, String password, Map<String, Object> extraProperties)
+ throws RepositoryException {
final Node parentNode = this.parentNodeStack.peek();
Session session = parentNode.getSession();
UserManager userManager = AccessControlUtil.getUserManager(session);
Authorizable authorizable = userManager.getAuthorizable(name);
if (authorizable == null) {
- //principal does not exist yet, so create it
- User user = userManager.createUser(name,
- password,
- new Principal() {
- public String getName() {
- return name;
- }
- },
- hashPath(name)
- );
+ // principal does not exist yet, so create it
+ User user = userManager.createUser(name, password, () -> name, hashPath(name));
authorizable = user;
} else {
- //principal already exists, check to make sure it is the expected type
+ // principal already exists, check to make sure it is the expected type
if (authorizable.isGroup()) {
throw new RepositoryException("A group already exists with the requested name: " + name);
}
- //user already exists so just update it below
+ // user already exists so just update it below
}
if (extraProperties != null) {
ValueFactory valueFactory = session.getValueFactory();
@@ -781,49 +825,58 @@
*/
protected String hashPath(String item) throws RepositoryException {
try {
- String hash = digest("sha1", (INSTANCE_SEED + item).getBytes("UTF-8"));
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < STORAGE_LEVELS; i++) {
- sb.append(hash, i * 2, (i * 2) + 2).append("/");
- }
- return sb.toString();
- } catch (NoSuchAlgorithmException e) {
- throw new RepositoryException("Unable to hash the path.", e);
- } catch (UnsupportedEncodingException e) {
+ final String hash = digest("sha1", (INSTANCE_SEED + item).getBytes("UTF-8"));
+ return IntStream.range(0, STORAGE_LEVELS)
+ .mapToObj(i -> hash.substring(i * 2, (i * 2) + 2))
+ .collect(Collectors.joining("/", "", "/"));
+ } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
throw new RepositoryException("Unable to hash the path.", e);
}
}
- /* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.ContentCreator#createAce(java.lang.String, java.lang.String, java.lang.String[], java.lang.String[])
- */
- public void createAce(String principalId, String[] grantedPrivilegeNames, String[] deniedPrivilegeNames, String order) throws RepositoryException {
- createAce(principalId, grantedPrivilegeNames, deniedPrivilegeNames, order, null, null, null);
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.apache.sling.jcr.contentloader.ContentCreator#createAce(java.lang.String,
+ * java.lang.String, java.lang.String[], java.lang.String[])
+ */
+ public void createAce(String principalId, String[] grantedPrivilegeNames, String[] deniedPrivilegeNames,
+ String order) throws RepositoryException {
+ createAce(principalId, grantedPrivilegeNames, deniedPrivilegeNames, order, null, null, null);
}
- /* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.ContentCreator#createAce(java.lang.String, java.lang.String[], java.lang.String[], java.lang.String, java.util.Map, java.util.Map, java.util.Set)
- */
- @Override
- public void createAce(String principalId, String[] grantedPrivilegeNames, String[] deniedPrivilegeNames, String order,
- Map<String, Value> restrictions, Map<String, Value[]> mvRestrictions, Set<String> removedRestrictionNames)
- throws RepositoryException {
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.apache.sling.jcr.contentloader.ContentCreator#createAce(java.lang.String,
+ * java.lang.String[], java.lang.String[], java.lang.String, java.util.Map,
+ * java.util.Map, java.util.Set)
+ */
+ @Override
+ public void createAce(String principalId, String[] grantedPrivilegeNames, String[] deniedPrivilegeNames,
+ String order, Map<String, Value> restrictions, Map<String, Value[]> mvRestrictions,
+ Set<String> removedRestrictionNames) throws RepositoryException {
final Node parentNode = this.parentNodeStack.peek();
Session session = parentNode.getSession();
-
+
PrincipalManager principalManager = AccessControlUtil.getPrincipalManager(session);
Principal principal = principalManager.getPrincipal(principalId);
if (principal == null) {
- // SLING-7268 - as pointed out in OAK-5496, we cannot successfully use PrincipalManager#getPrincipal in oak
- // without the session that created the principal getting saved first (and a subsequent index update).
- // Workaround by trying the UserManager#getAuthorizable API to locate the principal.
+ // SLING-7268 - as pointed out in OAK-5496, we cannot successfully use
+ // PrincipalManager#getPrincipal in oak
+ // without the session that created the principal getting saved first (and a
+ // subsequent index update).
+ // Workaround by trying the UserManager#getAuthorizable API to locate the
+ // principal.
UserManager userManager = AccessControlUtil.getUserManager(session);
final Authorizable authorizable = userManager.getAuthorizable(principalId);
if (authorizable != null) {
principal = authorizable.getPrincipal();
}
}
-
+
if (principal == null) {
throw new RepositoryException("No principal found for id: " + principalId);
}
@@ -833,20 +886,19 @@
AccessControlUtil.replaceAccessControlEntry(session, resourcePath, principal, grantedPrivilegeNames, deniedPrivilegeNames, null, order,
restrictions, mvRestrictions, removedRestrictionNames);
}
- }
+ }
-
- /* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.ContentCreator#getParent()
- */
- @Override
- public Node getParent() {
- final Node parentNode = this.parentNodeStack.peek();
- return parentNode;
- }
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.sling.jcr.contentloader.ContentCreator#getParent()
+ */
+ @Override
+ public Node getParent() {
+ return this.parentNodeStack.peek();
+ }
-
- /**
+ /**
* used for the md5
*/
private static final char[] hexTable = "0123456789abcdef".toCharArray();
@@ -854,17 +906,20 @@
/**
* Digest the plain string using the given algorithm.
*
- * @param algorithm The alogrithm for the digest. This algorithm must be
- * supported by the MessageDigest class.
- * @param data the data to digest with the given algorithm
+ * @param algorithm
+ * The alogrithm for the digest. This algorithm must be supported by
+ * the MessageDigest class.
+ * @param data
+ * the data to digest with the given algorithm
* @return The digested plain text String represented as Hex digits.
- * @throws java.security.NoSuchAlgorithmException if the desired algorithm is not supported by
- * the MessageDigest class.
+ * @throws java.security.NoSuchAlgorithmException
+ * if the desired algorithm is not supported by the MessageDigest
+ * class.
*/
public static String digest(String algorithm, byte[] data) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance(algorithm);
byte[] digest = md.digest(data);
- StringBuffer res = new StringBuffer(digest.length * 2);
+ StringBuilder res = new StringBuilder(digest.length * 2);
for (int i = 0; i < digest.length; i++) {
byte b = digest[i];
res.append(hexTable[(b >> 4) & 15]);
@@ -879,21 +934,16 @@
protected Node findVersionableAncestor(Node node) throws RepositoryException {
if (node == null) {
return null;
- } else if (isVersionable(node)) {
- return node;
- } else {
- try {
- node = node.getParent();
- return findVersionableAncestor(node);
- } catch (ItemNotFoundException e) {
- // top-level
- return null;
- }
}
- }
-
- protected boolean isVersionable(Node node) throws RepositoryException {
- return node.isNodeType("mix:versionable");
+ if (node.isNodeType("mix:versionable")) {
+ return node;
+ }
+ try {
+ return findVersionableAncestor(node.getParent());
+ } catch (ItemNotFoundException e) {
+ // top-level
+ return null;
+ }
}
/**
@@ -902,17 +952,75 @@
protected void checkoutIfNecessary(Node node) throws RepositoryException {
if (this.configuration.isAutoCheckout()) {
Node versionableNode = findVersionableAncestor(node);
- if (versionableNode != null) {
- if (!versionableNode.isCheckedOut()) {
- VersionManager versionManager = versionableNode.getSession().getWorkspace().getVersionManager();
- versionManager.checkout(versionableNode.getPath());
-
- if (this.importListener != null) {
- this.importListener.onCheckout(versionableNode.getPath());
- }
+ if (versionableNode != null && !versionableNode.isCheckedOut()) {
+ VersionManager versionManager = versionableNode.getSession().getWorkspace().getVersionManager();
+ versionManager.checkout(versionableNode.getPath());
+ if (this.importListener != null) {
+ this.importListener.onCheckout(versionableNode.getPath());
}
}
}
}
+ @Override
+ public void finish() throws RepositoryException {
+ if (this.configuration.isMerge()) {
+ Session session = this.createdRootNode.getSession();
+ importedNodes.stream().flatMap(n -> {
+ Set<String> iterable = getPeers(n,session);
+ return StreamSupport.stream(iterable.spliterator(), false);
+ }).filter(path -> !importedNodes.contains(path)).forEach(path -> removeNode(path,session));
+ importedNodes.stream().flatMap(n -> {
+ Set<String> iterable = getChildren(n,session);
+ return StreamSupport.stream(iterable.spliterator(), false);
+ }).filter(path -> !importedNodes.contains(path)).forEach(path -> removeNode(path,session));
+ }
+ }
+
+ private Set<String> getPeers(String path,Session session) {
+ try {
+ log.debug("finding peers for {}", path);
+ NodeIterator it = session.getNode(path).getParent().getNodes();
+ Set<String> peers = new LinkedHashSet<>();
+ while (it.hasNext()) {
+ String child = it.nextNode().getPath();
+ if (!child.equals(path)) {
+ peers.add(child);
+ }
+ }
+ return peers;
+ } catch (RepositoryException e) {
+ return Collections.emptySet();
+ }
+ }
+
+ private Set<String> getChildren(String path,Session session) {
+ try {
+ log.debug("finding children for {}", path);
+ NodeIterator it = session.getNode(path).getNodes();
+ Set<String> peers = new LinkedHashSet<>();
+ while (it.hasNext()) {
+ String child = it.nextNode().getPath();
+ peers.add(child);
+ }
+ return peers;
+ } catch (RepositoryException e) {
+ return Collections.emptySet();
+ }
+}
+
+ private void removeNode(String item, Session session) {
+ try {
+ if (this.importListener != null) {
+ this.importListener.onDelete(item);
+ }
+ log.debug("removing {}", item);
+ session.removeItem(item);
+ session.save();
+ } catch (RepositoryException e) {
+ log.warn("unable to remove node {}", item);
+ }
+
+ }
+
}
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentImporter.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentImporter.java
index e11495c..d13a18b 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentImporter.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentImporter.java
@@ -81,7 +81,7 @@
*/
@Override
public void importContent(Node parent, String filename, InputStream contentStream, ImportOptions importOptions, ContentImportListener importListener) throws RepositoryException, IOException {
-
+ logger.debug("initiate import of file name {}",filename);
// special treatment for system view imports
if (filename.endsWith(EXT_JCR_XML)) {
importJcrXml(parent, filename, contentStream, importOptions, importListener);
@@ -100,7 +100,7 @@
@Override
public void importContent(final Node parent, final String name, final String contentType, final InputStream contentStream, final ImportOptions importOptions, final ContentImportListener importListener) throws RepositoryException, IOException {
-
+ logger.debug("initiate import {} of type {}",name, contentType);
// special treatment for system view imports
if (ContentTypeUtil.TYPE_JCR_XML.equalsIgnoreCase(contentType)) {
importJcrXml(parent, name, contentStream, importOptions, importListener);
@@ -116,6 +116,7 @@
}
private void importContent(final DefaultContentCreator contentCreator, final ContentReader contentReader, final Node parent, final String name, final InputStream contentStream, final ImportOptions importOptions, final ContentImportListener importListener) throws RepositoryException, IOException {
+ logger.debug("initiate import of {}",name);
List<String> createdPaths = new ArrayList<>();
contentCreator.init(importOptions, getContentReaders(), createdPaths, importListener);
contentCreator.prepareParsing(parent, name);
@@ -139,10 +140,8 @@
logger.debug("import JCR XML: '{}'", name);
boolean replace = (importOptions == null) ? false : importOptions.isOverwrite();
final Node node = importJcrXml(parent, name, contentStream, replace);
- if (node != null) {
- if (importListener != null) {
- importListener.onCreate(node.getPath());
- }
+ if (node != null && importListener != null) {
+ importListener.onCreate(node.getPath());
}
}
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/JcrXmlImporter.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/JcrXmlImporter.java
index 0bc64fe..3551e35 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/JcrXmlImporter.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/JcrXmlImporter.java
@@ -37,9 +37,6 @@
private final Logger logger = LoggerFactory.getLogger(JcrXmlImporter.class);
- public JcrXmlImporter() {
- }
-
/**
* Import the XML file as JCR system or document view import. If the XML
* file is not a valid system or document view export/import file,
@@ -88,11 +85,11 @@
return (parent.hasNode(nodeName)) ? parent.getNode(nodeName) : null;
} catch (InvalidSerializedDataException isde) {
// the xml might not be System or Document View export, fall back to old-style XML reading
- logger.info("importJcrXml: XML does not seem to be system or document view; cause: {}", isde.toString());
+ logger.info("importJcrXml: XML does not seem to be system or document view; cause: {}", isde);
return null;
} catch (RepositoryException re) {
// any other repository related issue...
- logger.info("importJcrXml: Repository issue loading XML; cause: {}", re.toString());
+ logger.info("importJcrXml: Repository issue loading XML; cause: {}", re);
return null;
}
}
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java
index 4808aae..38898ae 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java
@@ -46,6 +46,18 @@
* should be overwritten or just initially added.
*/
public static final String OVERWRITE_PROPERTIES_DIRECTIVE = "overwriteProperties";
+
+ /**
+ * The overwriteProperties directive specifying if content properties
+ * should be overwritten or just initially added.
+ */
+ public static final String MERGE_PROPERTIES_DIRECTIVE = "mergeProperties";
+
+ /**
+ * The overwriteProperties directive specifying if content properties
+ * should be overwritten or just initially added.
+ */
+ public static final String MERGE_NODES_DIRECTIVE = "merge";
/** The uninstall directive specifying if content should be uninstalled. */
public static final String UNINSTALL_DIRECTIVE = "uninstall";
@@ -81,6 +93,10 @@
*/
public static final String IGNORE_CONTENT_READERS_DIRECTIVE = "ignoreImportProviders";
+ private final boolean propertyMerge;
+
+ private final boolean nodeMerge;
+
/** The path for the initial content. */
private final String path;
@@ -114,13 +130,13 @@
private long lastModified;
public static Iterator<PathEntry> getContentPaths(final Bundle bundle) {
- final List<PathEntry> entries = new ArrayList<PathEntry>();
- String bundleLastModifiedStamp = (String) bundle.getHeaders().get("Bnd-LastModified");
+ final List<PathEntry> entries = new ArrayList<>();
+ String bundleLastModifiedStamp = bundle.getHeaders().get("Bnd-LastModified");
long bundleLastModified = bundle.getLastModified(); // time last modified inside the container
if ( bundleLastModifiedStamp != null ) {
bundleLastModified = Math.min(bundleLastModified, Long.parseLong(bundleLastModifiedStamp));
}
- final String root = (String) bundle.getHeaders().get(CONTENT_HEADER);
+ final String root = bundle.getHeaders().get(CONTENT_HEADER);
if (root != null) {
final ManifestHeader header = ManifestHeader.parse(root);
for (final ManifestHeader.Entry entry : header.getEntries()) {
@@ -129,7 +145,7 @@
}
}
- if (entries.size() == 0) {
+ if (entries.isEmpty()) {
return null;
}
return entries.iterator();
@@ -141,6 +157,22 @@
// check for directives
+ // merge directive
+ final String mergeProperties = entry.getDirectiveValue(MERGE_PROPERTIES_DIRECTIVE);
+ if (mergeProperties != null) {
+ this.propertyMerge = Boolean.valueOf(mergeProperties);
+ } else {
+ this.propertyMerge = false;
+ }
+
+ // merge directive
+ final String mergeNodes = entry.getDirectiveValue(MERGE_NODES_DIRECTIVE);
+ if (mergeNodes != null) {
+ this.nodeMerge = Boolean.valueOf(mergeProperties);
+ } else {
+ this.nodeMerge = false;
+ }
+
// overwrite directive
final String overwriteValue = entry.getDirectiveValue(OVERWRITE_DIRECTIVE);
if (overwriteValue != null) {
@@ -157,6 +189,7 @@
this.overwriteProperties = false;
}
+
// uninstall directive
final String uninstallValue = entry.getDirectiveValue(UNINSTALL_DIRECTIVE);
if (uninstallValue != null) {
@@ -190,7 +223,7 @@
}
// expand directive
- this.ignoreContentReaders = new ArrayList<String>();
+ this.ignoreContentReaders = new ArrayList<>();
final String expandValue = entry.getDirectiveValue(IGNORE_CONTENT_READERS_DIRECTIVE);
if ( expandValue != null && expandValue.length() > 0 ) {
final StringTokenizer st = new StringTokenizer(expandValue, ",");
@@ -217,42 +250,42 @@
}
/* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.internal.ImportOptions#isOverwrite()
- */
+ * @see org.apache.sling.jcr.contentloader.internal.ImportOptions#isOverwrite()
+ */
public boolean isOverwrite() {
return this.overwrite;
}
/* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.ImportOptions#isPropertyOverwrite()
- */
- @Override
- public boolean isPropertyOverwrite() {
- return this.overwriteProperties;
- }
+ * @see org.apache.sling.jcr.contentloader.ImportOptions#isPropertyOverwrite()
+ */
- public boolean isUninstall() {
+ public boolean isPropertyOverwrite() {
+ return this.overwriteProperties;
+ }
+
+ public boolean isUninstall() {
return this.uninstall;
}
/* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.internal.ImportOptions#isCheckin()
- */
+ * @see org.apache.sling.jcr.contentloader.internal.ImportOptions#isCheckin()
+ */
public boolean isCheckin() {
return this.checkin;
}
/* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.ImportOptions#isAutoCheckout()
- */
- @Override
- public boolean isAutoCheckout() {
- return this.autoCheckout;
- }
+ * @see org.apache.sling.jcr.contentloader.ImportOptions#isAutoCheckout()
+ */
- /* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.internal.ImportOptions#isIgnoredImportProvider(java.lang.String)
- */
+ public boolean isAutoCheckout() {
+ return this.autoCheckout;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.sling.jcr.contentloader.internal.ImportOptions#isIgnoredImportProvider(java.lang.String)
+ */
public boolean isIgnoredImportProvider(String extension) {
if ( extension.startsWith(".") ) {
extension = extension.substring(1);
@@ -267,4 +300,14 @@
public String getWorkspace() {
return workspace;
}
+
+
+ public boolean isPropertyMerge() {
+ return this.propertyMerge;
+ }
+
+
+ public boolean isMerge() {
+ return this.nodeMerge;
+ }
}
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
index f004fcf..1379c8a 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
@@ -59,9 +59,9 @@
import org.osgi.service.component.annotations.Component;
/**
- * The <code>JsonReader</code> Parses a Json document on content load and creates the
- * corresponding node structure with properties. Will not update protected nodes and
- * properties like rep:Policy and children.
+ * The <code>JsonReader</code> Parses a Json document on content load and
+ * creates the corresponding node structure with properties. Will not update
+ * protected nodes and properties like rep:Policy and children.
*
* <pre>
* Nodes, Properties and in fact complete subtrees may be described in JSON files
@@ -107,15 +107,12 @@
*
* </pre>
*/
-@Component(service = ContentReader.class,
-property = {
- Constants.SERVICE_VENDOR + "=The Apache Software Foundation",
- ContentReader.PROPERTY_EXTENSIONS + "=json",
- ContentReader.PROPERTY_TYPES + "=application/json"
-})
+@Component(service = ContentReader.class, property = { Constants.SERVICE_VENDOR + "=The Apache Software Foundation",
+ ContentReader.PROPERTY_EXTENSIONS + "=json", ContentReader.PROPERTY_TYPES + "=application/json" })
public class JsonReader implements ContentReader {
- private static final Pattern jsonDate = Pattern.compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}[-+]{1}[0-9]{2}[:]{0,1}[0-9]{2}$");
+ private static final Pattern jsonDate = Pattern.compile(
+ "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}[-+]{1}[0-9]{2}[:]{0,1}[0-9]{2}$");
private static final String REFERENCE = "jcr:reference:";
private static final String PATH = "jcr:path:";
private static final String NAME = "jcr:name:";
@@ -135,21 +132,21 @@
private static final Set<String> ignoredPrincipalPropertyNames = new HashSet<>();
static {
- ignoredPrincipalPropertyNames.add("name");
- ignoredPrincipalPropertyNames.add("isgroup");
- ignoredPrincipalPropertyNames.add("members");
- ignoredPrincipalPropertyNames.add("dynamic");
- ignoredPrincipalPropertyNames.add("password");
+ ignoredPrincipalPropertyNames.add("name");
+ ignoredPrincipalPropertyNames.add("isgroup");
+ ignoredPrincipalPropertyNames.add("members");
+ ignoredPrincipalPropertyNames.add("dynamic");
+ ignoredPrincipalPropertyNames.add("password");
}
private static final String SECURITY_PRINCIPLES = "security:principals";
private static final String SECURITY_ACL = "security:acl";
/**
- * @see org.apache.sling.jcr.contentloader.ContentReader#parse(java.net.URL, org.apache.sling.jcr.contentloader.ContentCreator)
+ * @see org.apache.sling.jcr.contentloader.ContentReader#parse(java.net.URL,
+ * org.apache.sling.jcr.contentloader.ContentCreator)
*/
@Override
- public void parse(java.net.URL url, ContentCreator contentCreator)
- throws IOException, RepositoryException {
+ public void parse(java.net.URL url, ContentCreator contentCreator) throws IOException, RepositoryException {
InputStream ins = null;
try {
ins = url.openStream();
@@ -166,21 +163,22 @@
@Override
public void parse(InputStream ins, ContentCreator contentCreator) throws IOException, RepositoryException {
- try {
- String jsonString = toString(ins).trim();
- if (!jsonString.startsWith("{")) {
- jsonString = "{" + jsonString + "}";
- }
- Map<String, Object> config = new HashMap<>();
- config.put("org.apache.johnzon.supports-comments", true);
- JsonObject json = Json.createReaderFactory(config).createReader(new StringReader(tickToDoubleQuote(jsonString))).readObject();
+ String jsonString = toString(ins).trim();
+ if (!jsonString.startsWith("{")) {
+ jsonString = "{" + jsonString + "}";
+ }
+ Map<String, Object> config = new HashMap<>();
+ config.put("org.apache.johnzon.supports-comments", true);
+ try (javax.json.JsonReader reader = Json.createReaderFactory(config).createReader(new StringReader(tickToDoubleQuote(jsonString)))) {
+ JsonObject json = reader.readObject();
this.createNode(null, json, contentCreator);
+ contentCreator.finish();
} catch (JsonException je) {
throw (IOException) new IOException(je.getMessage()).initCause(je);
}
}
- protected boolean handleSecurity(String n, Object o, ContentCreator contentCreator) throws RepositoryException{
+ protected boolean handleSecurity(String n, Object o, ContentCreator contentCreator) throws RepositoryException {
if (SECURITY_PRINCIPLES.equals(n)) {
this.createPrincipals(o, contentCreator);
} else if (SECURITY_ACL.equals(n)) {
@@ -191,7 +189,7 @@
return true;
}
- protected void writeChildren(JsonObject obj, ContentCreator contentCreator) throws RepositoryException{
+ protected void writeChildren(JsonObject obj, ContentCreator contentCreator) throws RepositoryException {
// add properties and nodes
for (Map.Entry<String, JsonValue> entry : obj.entrySet()) {
final String n = entry.getKey();
@@ -232,51 +230,53 @@
if (value instanceof JsonArray) {
// multivalue
final JsonArray array = (JsonArray) value;
- if (array.size() > 0) {
+ if (!array.isEmpty()) {
final String values[] = new String[array.size()];
for (int i = 0; i < values.length; i++) {
- values[i] = unbox(array.get(i)).toString();
+ values[i] = unbox(array.get(i)).toString();
}
final int propertyType = getType(name, unbox(array.get(0)));
contentCreator.createProperty(getName(name), propertyType, values);
} else {
contentCreator.createProperty(getName(name), PropertyType.STRING, new String[0]);
}
-
} else if (value instanceof JsonValue) {
// single value
value = unbox(value);
- final int propertyType = getType(name, value);
- contentCreator.createProperty(getName(name), propertyType, value.toString());
+ if (value != null) {
+ contentCreator.createProperty(getName(name), getType(name, value), value.toString());
+ }
}
}
private Object unbox(Object o) {
if (o instanceof JsonValue) {
- switch (((JsonValue)o).getValueType()) {
- case FALSE:
- return false;
- case TRUE:
- return true;
- case NULL:
- return null;
- case NUMBER:
- if (((JsonNumber) o).isIntegral()) {
- return Long.valueOf(((JsonNumber) o).longValue());
- }
- else
- {
- return Double.valueOf(((JsonNumber)o).doubleValue());
- }
- case STRING:
- return ((JsonString) o).getString();
- default:
- return o;
+ switch (((JsonValue) o).getValueType()) {
+ case FALSE:
+ return false;
+ case TRUE:
+ return true;
+ case NULL:
+ return null;
+ case NUMBER:
+ if (((JsonNumber) o).isIntegral()) {
+ return Long.valueOf(((JsonNumber) o).longValue());
+ } else {
+ return Double.valueOf(((JsonNumber) o).doubleValue());
+ }
+ case STRING:
+ return ((JsonString) o).getString();
+ default:
+ return o;
}
}
return o;
}
+
private int getType(String name, Object object) {
+ if (object == null) {
+ return PropertyType.STRING;
+ }
if (object instanceof Double || object instanceof Float) {
return PropertyType.DOUBLE;
} else if (object instanceof Number) {
@@ -284,11 +284,16 @@
} else if (object instanceof Boolean) {
return PropertyType.BOOLEAN;
} else if (object instanceof String) {
- if (name.startsWith(REFERENCE)) return PropertyType.REFERENCE;
- if (name.startsWith(PATH)) return PropertyType.PATH;
- if (name.startsWith(NAME)) return PropertyType.NAME;
- if (name.startsWith(URI)) return PropertyType.URI;
- if (jsonDate.matcher((String) object).matches()) return PropertyType.DATE;
+ if (name.startsWith(REFERENCE))
+ return PropertyType.REFERENCE;
+ if (name.startsWith(PATH))
+ return PropertyType.PATH;
+ if (name.startsWith(NAME))
+ return PropertyType.NAME;
+ if (name.startsWith(URI))
+ return PropertyType.URI;
+ if (jsonDate.matcher((String) object).matches())
+ return PropertyType.DATE;
}
// fall back to default
@@ -296,10 +301,14 @@
}
private String getName(String name) {
- if (name.startsWith(REFERENCE)) return name.substring(REFERENCE.length());
- if (name.startsWith(PATH)) return name.substring(PATH.length());
- if (name.startsWith(NAME)) return name.substring(NAME.length());
- if (name.startsWith(URI)) return name.substring(URI.length());
+ if (name.startsWith(REFERENCE))
+ return name.substring(REFERENCE.length());
+ if (name.startsWith(PATH))
+ return name.substring(PATH.length());
+ if (name.startsWith(NAME))
+ return name.substring(NAME.length());
+ if (name.startsWith(URI))
+ return name.substring(URI.length());
return name;
}
@@ -326,7 +335,7 @@
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int rd;
- while ( (rd = ins.read(buf)) >= 0) {
+ while ((rd = ins.read(buf)) >= 0) {
bos.write(buf, 0, rd);
}
bos.close(); // just to comply with the contract
@@ -334,10 +343,8 @@
return new String(bos.toByteArray(), encoding);
}
-
/**
- * Create or update one or more user and/or groups
- * <code>
+ * Create or update one or more user and/or groups <code>
* {
* "security:principals" : [
* {
@@ -349,67 +356,70 @@
* ],
* }
* </code>
- * @param obj Object
- * @param contentCreator Content creator
- * @throws RepositoryException Repository exception
+ *
+ * @param obj
+ * Object
+ * @param contentCreator
+ * Content creator
+ * @throws RepositoryException
+ * Repository exception
*/
protected void createPrincipals(Object obj, ContentCreator contentCreator) throws RepositoryException {
- if (obj instanceof JsonObject) {
- //single principal
- createPrincipal((JsonObject)obj, contentCreator);
- } else if (obj instanceof JsonArray) {
- //array of principals
- JsonArray jsonArray = (JsonArray)obj;
- for (int i=0; i < jsonArray.size(); i++) {
- Object object = jsonArray.get(i);
- if (object instanceof JsonObject) {
- createPrincipal((JsonObject)object, contentCreator);
- } else {
- throw new JsonException("Unexpected data type in principals array: " + object.getClass().getName());
- }
- }
- }
+ if (obj instanceof JsonObject) {
+ // single principal
+ createPrincipal((JsonObject) obj, contentCreator);
+ } else if (obj instanceof JsonArray) {
+ // array of principals
+ JsonArray jsonArray = (JsonArray) obj;
+ for (int i = 0; i < jsonArray.size(); i++) {
+ Object object = jsonArray.get(i);
+ if (object instanceof JsonObject) {
+ createPrincipal((JsonObject) object, contentCreator);
+ } else {
+ throw new JsonException("Unexpected data type in principals array: " + object.getClass().getName());
+ }
+ }
+ }
}
/**
* Create or update a user or group
*/
private void createPrincipal(JsonObject json, ContentCreator contentCreator) throws RepositoryException {
- //create a principal
- String name = json.getString("name");
- boolean isGroup = json.getBoolean("isgroup", false);
+ // create a principal
+ String name = json.getString("name");
+ boolean isGroup = json.getBoolean("isgroup", false);
- //collect the extra property names to assign to the new principal
- Map<String, Object> extraProps = new LinkedHashMap<>();
- for(Map.Entry<String, JsonValue> entry : json.entrySet()) {
- String propName = entry.getKey();
- if (!ignoredPrincipalPropertyNames.contains(propName)) {
- Object value = unbox(entry.getValue());
- extraProps.put(propName, value);
- }
- }
+ // collect the extra property names to assign to the new principal
+ Map<String, Object> extraProps = new LinkedHashMap<>();
+ for (Map.Entry<String, JsonValue> entry : json.entrySet()) {
+ String propName = entry.getKey();
+ if (!ignoredPrincipalPropertyNames.contains(propName)) {
+ Object value = unbox(entry.getValue());
+ extraProps.put(propName, value);
+ }
+ }
- if (isGroup) {
- String [] members = null;
- JsonArray membersJSONArray = (JsonArray) json.get("members");
- if (membersJSONArray != null) {
- members = new String[membersJSONArray.size()];
- for (int i=0; i < members.length; i++) {
- members[i] = membersJSONArray.getString(i);
- }
- }
- contentCreator.createGroup(name, members, extraProps);
- } else {
- String password = json.getString("password");
- contentCreator.createUser(name, password, extraProps);
- }
+ if (isGroup) {
+ String[] members = null;
+ JsonArray membersJSONArray = (JsonArray) json.get("members");
+ if (membersJSONArray != null) {
+ members = new String[membersJSONArray.size()];
+ for (int i = 0; i < members.length; i++) {
+ members[i] = membersJSONArray.getString(i);
+ }
+ }
+ contentCreator.createGroup(name, members, extraProps);
+ } else {
+ String password = json.getString("password");
+ contentCreator.createUser(name, password, extraProps);
+ }
}
/**
- * Create or update one or more access control entries for the current
- * node.
+ * Create or update one or more access control entries for the current node.
*
- * <code>
+ * <code>
* {
* "security:acl" : [
* {
@@ -433,188 +443,193 @@
* </code>
*/
private void createAcl(Object obj, ContentCreator contentCreator) throws RepositoryException {
- if (obj instanceof JsonObject) {
- //single ace
- createAce((JsonObject)obj, contentCreator);
- } else if (obj instanceof JsonArray) {
- //array of aces
- JsonArray jsonArray = (JsonArray)obj;
- for (int i=0; i < jsonArray.size(); i++) {
- Object object = jsonArray.get(i);
- if (object instanceof JsonObject) {
- createAce((JsonObject)object, contentCreator);
- } else {
- throw new JsonException("Unexpected data type in acl array: " + object.getClass().getName());
- }
- }
- }
+ if (obj instanceof JsonObject) {
+ // single ace
+ createAce((JsonObject) obj, contentCreator);
+ } else if (obj instanceof JsonArray) {
+ // array of aces
+ JsonArray jsonArray = (JsonArray) obj;
+ for (int i = 0; i < jsonArray.size(); i++) {
+ Object object = jsonArray.get(i);
+ if (object instanceof JsonObject) {
+ createAce((JsonObject) object, contentCreator);
+ } else {
+ throw new JsonException("Unexpected data type in acl array: " + object.getClass().getName());
+ }
+ }
+ }
}
/**
* Create or update an access control entry
*/
private void createAce(JsonObject ace, ContentCreator contentCreator) throws RepositoryException {
- String principalID = ace.getString("principal");
+ String principalID = ace.getString("principal");
- String [] grantedPrivileges = null;
- JsonArray granted = (JsonArray) ace.get("granted");
- if (granted != null) {
- grantedPrivileges = new String[granted.size()];
- for (int a=0; a < grantedPrivileges.length; a++) {
- grantedPrivileges[a] = granted.getString(a);
- }
- }
+ String[] grantedPrivileges = null;
+ JsonArray granted = (JsonArray) ace.get("granted");
+ if (granted != null) {
+ grantedPrivileges = new String[granted.size()];
+ for (int a = 0; a < grantedPrivileges.length; a++) {
+ grantedPrivileges[a] = granted.getString(a);
+ }
+ }
- String [] deniedPrivileges = null;
- JsonArray denied = (JsonArray) ace.get("denied");
- if (denied != null) {
- deniedPrivileges = new String[denied.size()];
- for (int a=0; a < deniedPrivileges.length; a++) {
- deniedPrivileges[a] = denied.getString(a);
- }
- }
+ String[] deniedPrivileges = null;
+ JsonArray denied = (JsonArray) ace.get("denied");
+ if (denied != null) {
+ deniedPrivileges = new String[denied.size()];
+ for (int a = 0; a < deniedPrivileges.length; a++) {
+ deniedPrivileges[a] = denied.getString(a);
+ }
+ }
- String order = ace.getString("order", null);
-
- Map<String, Value> restrictionsMap = null;
- Map<String, Value[]> mvRestrictionsMap = null;
- Set<String> removedRestrictionNames = null;
- JsonObject restrictions = (JsonObject) ace.get("restrictions");
- if (restrictions != null) {
- //lazy initialized map for quick lookup when processing restrictions
- Map<String, RestrictionDefinition> supportedRestrictionsMap = new HashMap<>();
+ String order = ace.getString("order", null);
- Node parentNode = contentCreator.getParent();
+ Map<String, Value> restrictionsMap = null;
+ Map<String, Value[]> mvRestrictionsMap = null;
+ Set<String> removedRestrictionNames = null;
+ JsonObject restrictions = (JsonObject) ace.get("restrictions");
+ if (restrictions != null) {
+ // lazy initialized map for quick lookup when processing restrictions
+ Map<String, RestrictionDefinition> supportedRestrictionsMap = new HashMap<>();
- RestrictionProvider restrictionProvider = null;
- Bundle bundle = FrameworkUtil.getBundle(getClass());
- BundleContext bundleContext = bundle.getBundleContext();
- ServiceReference<RestrictionProvider> serviceReference = null;
- try {
- serviceReference = bundleContext.getServiceReference(RestrictionProvider.class);
- restrictionProvider = bundleContext.getService(serviceReference);
-
- if (restrictionProvider == null) {
- throw new JsonException("No restriction provider is available so unable to process restriction values");
- }
+ Node parentNode = contentCreator.getParent();
- // populate the map
- Set<RestrictionDefinition> supportedRestrictions = restrictionProvider.getSupportedRestrictions(parentNode.getPath());
- for (RestrictionDefinition restrictionDefinition : supportedRestrictions) {
- supportedRestrictionsMap.put(restrictionDefinition.getName(), restrictionDefinition);
- }
- } finally {
- if (serviceReference != null) {
- bundleContext.ungetService(serviceReference);
- }
- }
-
- restrictionsMap = new HashMap<>();
- mvRestrictionsMap = new HashMap<>();
- removedRestrictionNames = new HashSet<>();
+ RestrictionProvider restrictionProvider = null;
+ Bundle bundle = FrameworkUtil.getBundle(getClass());
+ BundleContext bundleContext = bundle.getBundleContext();
+ ServiceReference<RestrictionProvider> serviceReference = null;
+ try {
+ serviceReference = bundleContext.getServiceReference(RestrictionProvider.class);
+ restrictionProvider = bundleContext.getService(serviceReference);
- ValueFactory factory = parentNode.getSession().getValueFactory();
-
- Set<String> keySet = restrictions.keySet();
- for (String rname : keySet) {
- if (rname.endsWith("@Delete")) {
- //add the key to the 'remove' set. the value doesn't matter and is ignored.
- String rname2 = rname.substring(9, rname.length() - 7);
- removedRestrictionNames.add(rname2);
- } else {
- RestrictionDefinition rd = supportedRestrictionsMap.get(rname);
- if (rd == null) {
- //illegal restriction name?
- throw new JsonException("Invalid or not supported restriction name was supplied: " + rname);
- }
-
- boolean multival = rd.getRequiredType().isArray();
- int restrictionType = rd.getRequiredType().tag();
+ if (restrictionProvider == null) {
+ throw new JsonException(
+ "No restriction provider is available so unable to process restriction values");
+ }
- //read the requested restriction value and apply it
- JsonValue jsonValue = restrictions.get(rname);
+ // populate the map
+ Set<RestrictionDefinition> supportedRestrictions = restrictionProvider
+ .getSupportedRestrictions(parentNode.getPath());
+ for (RestrictionDefinition restrictionDefinition : supportedRestrictions) {
+ supportedRestrictionsMap.put(restrictionDefinition.getName(), restrictionDefinition);
+ }
+ } finally {
+ if (serviceReference != null) {
+ bundleContext.ungetService(serviceReference);
+ }
+ }
- if (multival) {
- if (jsonValue.getValueType() == ValueType.ARRAY) {
- JsonArray jsonArray = (JsonArray)jsonValue;
- int size = jsonArray.size();
- Value [] values = new Value[size];
- for (int i = 0; i < size; i++) {
- values[i] = toValue(factory, jsonArray.get(i), restrictionType);
- }
- mvRestrictionsMap.put(rname, values);
- } else {
- Value v = toValue(factory, jsonValue, restrictionType);
- mvRestrictionsMap.put(rname, new Value[] {v});
- }
- } else {
- if (jsonValue.getValueType() == ValueType.ARRAY) {
- JsonArray jsonArray = (JsonArray)jsonValue;
- int size = jsonArray.size();
- if (size == 1) {
- Value v = toValue(factory, jsonArray.get(0), restrictionType);
- restrictionsMap.put(rname, v);
- } else if (size > 1) {
- throw new JsonException("Unexpected multi value array data found for single-value restriction value for name: " + rname);
- }
- } else {
- Value v = toValue(factory, jsonValue, restrictionType);
- restrictionsMap.put(rname, v);
- }
- }
- }
- }
- }
+ restrictionsMap = new HashMap<>();
+ mvRestrictionsMap = new HashMap<>();
+ removedRestrictionNames = new HashSet<>();
- //do the work.
- if (restrictionsMap == null && mvRestrictionsMap == null && removedRestrictionNames == null) {
- contentCreator.createAce(principalID, grantedPrivileges, deniedPrivileges, order);
- } else {
- contentCreator.createAce(principalID, grantedPrivileges, deniedPrivileges, order, restrictionsMap, mvRestrictionsMap,
- removedRestrictionNames == null ? null : removedRestrictionNames);
- }
+ ValueFactory factory = parentNode.getSession().getValueFactory();
+
+ Set<String> keySet = restrictions.keySet();
+ for (String rname : keySet) {
+ if (rname.endsWith("@Delete")) {
+ // add the key to the 'remove' set. the value doesn't matter and is ignored.
+ String rname2 = rname.substring(9, rname.length() - 7);
+ removedRestrictionNames.add(rname2);
+ } else {
+ RestrictionDefinition rd = supportedRestrictionsMap.get(rname);
+ if (rd == null) {
+ // illegal restriction name?
+ throw new JsonException("Invalid or not supported restriction name was supplied: " + rname);
+ }
+
+ boolean multival = rd.getRequiredType().isArray();
+ int restrictionType = rd.getRequiredType().tag();
+
+ // read the requested restriction value and apply it
+ JsonValue jsonValue = restrictions.get(rname);
+
+ if (multival) {
+ if (jsonValue.getValueType() == ValueType.ARRAY) {
+ JsonArray jsonArray = (JsonArray) jsonValue;
+ int size = jsonArray.size();
+ Value[] values = new Value[size];
+ for (int i = 0; i < size; i++) {
+ values[i] = toValue(factory, jsonArray.get(i), restrictionType);
+ }
+ mvRestrictionsMap.put(rname, values);
+ } else {
+ Value v = toValue(factory, jsonValue, restrictionType);
+ mvRestrictionsMap.put(rname, new Value[] { v });
+ }
+ } else {
+ if (jsonValue.getValueType() == ValueType.ARRAY) {
+ JsonArray jsonArray = (JsonArray) jsonValue;
+ int size = jsonArray.size();
+ if (size == 1) {
+ Value v = toValue(factory, jsonArray.get(0), restrictionType);
+ restrictionsMap.put(rname, v);
+ } else if (size > 1) {
+ throw new JsonException(
+ "Unexpected multi value array data found for single-value restriction value for name: "
+ + rname);
+ }
+ } else {
+ Value v = toValue(factory, jsonValue, restrictionType);
+ restrictionsMap.put(rname, v);
+ }
+ }
+ }
+ }
+ }
+
+ // do the work.
+ if (restrictionsMap == null && mvRestrictionsMap == null && removedRestrictionNames == null) {
+ contentCreator.createAce(principalID, grantedPrivileges, deniedPrivileges, order);
+ } else {
+ contentCreator.createAce(principalID, grantedPrivileges, deniedPrivileges, order, restrictionsMap,
+ mvRestrictionsMap, removedRestrictionNames == null ? null : removedRestrictionNames);
+ }
}
-
+
/**
* Attempt to convert the JsonValue to the equivalent JCR Value object
*
- * @param factory the JCR value factory
- * @param jsonValue the JSON value to convert
- * @param restrictionType a hint for the expected property type of the value
+ * @param factory
+ * the JCR value factory
+ * @param jsonValue
+ * the JSON value to convert
+ * @param restrictionType
+ * a hint for the expected property type of the value
* @return the Value if converted or null otherwise
- * @throws ValueFormatException
+ * @throws ValueFormatException
*/
private Value toValue(ValueFactory factory, JsonValue jsonValue, int restrictionType) throws ValueFormatException {
- Value value = null;
- ValueType valueType = jsonValue.getValueType();
- switch (valueType) {
- case TRUE:
- value = factory.createValue(false);
- break;
- case FALSE:
- value = factory.createValue(false);
- break;
- case NUMBER:
- JsonNumber jsonNumber = (JsonNumber)jsonValue;
- if (jsonNumber.isIntegral()) {
- value = factory.createValue(jsonNumber.longValue());
- } else {
- value = factory.createValue(jsonNumber.doubleValue());
- }
- break;
- case STRING:
- value = factory.createValue(((JsonString)jsonValue).getString(), restrictionType);
- break;
- case NULL:
- value = null;
- break;
- case ARRAY:
- case OBJECT:
- default:
- //illegal JSON?
- break;
- }
-
- return value;
+ Value value = null;
+ ValueType valueType = jsonValue.getValueType();
+ switch (valueType) {
+ case TRUE:
+ value = factory.createValue(false);
+ break;
+ case FALSE:
+ value = factory.createValue(false);
+ break;
+ case NUMBER:
+ JsonNumber jsonNumber = (JsonNumber) jsonValue;
+ if (jsonNumber.isIntegral()) {
+ value = factory.createValue(jsonNumber.longValue());
+ } else {
+ value = factory.createValue(jsonNumber.doubleValue());
+ }
+ break;
+ case STRING:
+ value = factory.createValue(((JsonString) jsonValue).getString(), restrictionType);
+ break;
+ case NULL:
+ case ARRAY:
+ case OBJECT:
+ default:
+ // illegal JSON?
+ break;
+ }
+
+ return value;
}
}
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
index e773999..1fb0bd7 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
@@ -61,8 +61,8 @@
import org.xmlpull.v1.XmlPullParserException;
/**
- * This reader reads an xml file defining the content. The xml format should have this
- * format:
+ * This reader reads an xml file defining the content. The xml format should
+ * have this format:
*
* <pre>
* <node>
@@ -93,24 +93,22 @@
* </node>
* </pre>
*
- * If you want to include a binary file in your loaded content, you may specify it using a
- * {@link org.apache.sling.jcr.contentloader.internal.readers.XmlReader.FileDescription} <code><nt:file></code> element.
+ * If you want to include a binary file in your loaded content, you may specify
+ * it using a
+ * {@link org.apache.sling.jcr.contentloader.internal.readers.XmlReader.FileDescription}
+ * <code><nt:file></code> element.
*/
-@Component(service = ContentReader.class,
-property = {
- Constants.SERVICE_VENDOR + "=The Apache Software Foundation",
- ContentReader.PROPERTY_EXTENSIONS + "=xml",
- ContentReader.PROPERTY_TYPES + "=application/xml",
- ContentReader.PROPERTY_TYPES + "=text/xml"
-})
+@Component(service = ContentReader.class, property = { Constants.SERVICE_VENDOR + "=The Apache Software Foundation",
+ ContentReader.PROPERTY_EXTENSIONS + "=xml", ContentReader.PROPERTY_TYPES + "=application/xml",
+ ContentReader.PROPERTY_TYPES + "=text/xml" })
public class XmlReader implements ContentReader {
/*
* <node> <primaryNodeType>type</primaryNodeType> <mixinNodeTypes>
- * <mixinNodeType>mixtype1</mixinNodeType> <mixinNodeType>mixtype2</mixinNodeType>
- * </mixinNodeTypes> <properties> <property> <name>propName</name>
- * <value>propValue</value> <type>propType</type> </property> <!-- more
- * --> </properties> </node>
+ * <mixinNodeType>mixtype1</mixinNodeType>
+ * <mixinNodeType>mixtype2</mixinNodeType> </mixinNodeTypes> <properties>
+ * <property> <name>propName</name> <value>propValue</value>
+ * <type>propType</type> </property> <!-- more --> </properties> </node>
*/
/** default log */
@@ -154,34 +152,36 @@
// ---------- XML content access -------------------------------------------
-
/**
- * @see org.apache.sling.jcr.contentloader.ContentReader#parse(URL, org.apache.sling.jcr.contentloader.ContentCreator)
+ * @see org.apache.sling.jcr.contentloader.ContentReader#parse(URL,
+ * org.apache.sling.jcr.contentloader.ContentCreator)
*/
@Override
public synchronized void parse(final URL url, final ContentCreator creator)
- throws IOException, RepositoryException {
- BufferedInputStream bufferedInput = null;
- try {
- // We need to buffer input, so that we can reset the stream if we encounter an XSL stylesheet reference
- bufferedInput = new BufferedInputStream(url.openStream());
+ throws IOException, RepositoryException {
+
+ try (BufferedInputStream bufferedInput = new BufferedInputStream(url.openStream())) {
+ // We need to buffer input, so that we can reset the stream if we encounter an
+ // XSL stylesheet reference
parseInternal(bufferedInput, creator, url);
} catch (XmlPullParserException xppe) {
throw (IOException) new IOException(xppe.getMessage()).initCause(xppe);
- } finally {
- closeStream(bufferedInput);
}
}
- /* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.ContentReader#parse(java.io.InputStream, org.apache.sling.jcr.contentloader.ContentCreator)
- */
- @Override
- public void parse(InputStream ins, ContentCreator creator)
- throws IOException, RepositoryException {
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.apache.sling.jcr.contentloader.ContentReader#parse(java.io.InputStream,
+ * org.apache.sling.jcr.contentloader.ContentCreator)
+ */
+ @Override
+ public void parse(InputStream ins, ContentCreator creator) throws IOException, RepositoryException {
BufferedInputStream bufferedInput = null;
try {
- // We need to buffer input, so that we can reset the stream if we encounter an XSL stylesheet reference
+ // We need to buffer input, so that we can reset the stream if we encounter an
+ // XSL stylesheet reference
bufferedInput = new BufferedInputStream(ins);
URL xmlLocation = null;
parseInternal(bufferedInput, creator, xmlLocation);
@@ -190,15 +190,15 @@
} finally {
closeStream(bufferedInput);
}
- }
+ }
- private void parseInternal(final InputStream bufferedInput,
- final ContentCreator creator,
- final URL xmlLocation)
- throws XmlPullParserException, IOException, RepositoryException {
+ private void parseInternal(final InputStream bufferedInput, final ContentCreator creator, final URL xmlLocation)
+ throws XmlPullParserException, IOException, RepositoryException {
final StringBuilder contentBuffer = new StringBuilder();
- // Mark the beginning of the stream. We assume that if there's an XSL processing instruction,
- // it will occur in the first gulp - which makes sense, as processing instructions must be
+ // Mark the beginning of the stream. We assume that if there's an XSL processing
+ // instruction,
+ // it will occur in the first gulp - which makes sense, as processing
+ // instructions must be
// specified before the root element of an XML file.
bufferedInput.mark(bufferedInput.available());
// set the parser input, use null encoding to force detection with
@@ -213,17 +213,18 @@
PropertyDescription currentProperty = null;
String currentElement;
-
int eventType = this.xmlParser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.PROCESSING_INSTRUCTION) {
ProcessingInstruction pi = new ProcessingInstruction(this.xmlParser.getText());
// Look for a reference to an XSL stylesheet
- if (pi.getName().equals(XML_STYLESHEET_PROCESSING_INSTRUCTION) && xmlLocation != null ) {
- // Rewind the input stream to the beginning, so that it can be transformed with XSL
+ if (pi.getName().equals(XML_STYLESHEET_PROCESSING_INSTRUCTION) && xmlLocation != null) {
+ // Rewind the input stream to the beginning, so that it can be transformed with
+ // XSL
bufferedInput.reset();
// Pipe the XML input through the XSL transformer
- XslTransformerStream transformerStream = new XslTransformerStream(bufferedInput, pi.getAttribute(HREF_ATTRIBUTE), xmlLocation);
+ XslTransformerStream transformerStream = new XslTransformerStream(bufferedInput,
+ pi.getAttribute(HREF_ATTRIBUTE), xmlLocation);
// Start the transformer thread
transformerStream.startTransform();
// Re-run the XML parser, now with the transformed XML
@@ -243,11 +244,14 @@
} else if (ELEM_NODE.equals(currentElement)) {
currentNode = NodeDescription.create(currentNode, creator);
currentNode = NodeDescription.SHARED;
- } else if (ELEM_FILE_NAME.equals(currentElement) && ELEM_FILE_NAMESPACE.equals(this.xmlParser.getNamespace())) {
+ } else if (ELEM_FILE_NAME.equals(currentElement)
+ && ELEM_FILE_NAMESPACE.equals(this.xmlParser.getNamespace())) {
if (xmlLocation != null) {
int attributeCount = this.xmlParser.getAttributeCount();
if (attributeCount < 2 || attributeCount > 3) {
- throw new IOException("File element must have these attributes: url, mimeType and lastModified: " + xmlLocation);
+ throw new IOException(
+ "File element must have these attributes: url, mimeType and lastModified: "
+ + xmlLocation);
}
try {
AttributeMap attributes = AttributeMap.getInstance();
@@ -284,20 +288,23 @@
}
} else if (ELEM_VALUE.equals(qName)) {
- if ( currentProperty == null ) {
- throw new IOException("XML file does not seem to contain valid content xml. Unexpected " + ELEM_VALUE + " element in : " + xmlLocation);
+ if (currentProperty == null) {
+ throw new IOException("XML file does not seem to contain valid content xml. Unexpected "
+ + ELEM_VALUE + " element in : " + xmlLocation);
}
currentProperty.addValue(content);
} else if (ELEM_VALUES.equals(qName)) {
- if ( currentProperty == null ) {
- throw new IOException("XML file does not seem to contain valid content xml. Unexpected " + ELEM_VALUE + " element in : " + xmlLocation);
+ if (currentProperty == null) {
+ throw new IOException("XML file does not seem to contain valid content xml. Unexpected "
+ + ELEM_VALUE + " element in : " + xmlLocation);
}
currentProperty.isMultiValue = true;
} else if (ELEM_TYPE.equals(qName)) {
- if ( currentProperty == null ) {
- throw new IOException("XML file does not seem to contain valid content xml. Unexpected " + ELEM_VALUE + " element in : " + xmlLocation);
+ if (currentProperty == null) {
+ throw new IOException("XML file does not seem to contain valid content xml. Unexpected "
+ + ELEM_VALUE + " element in : " + xmlLocation);
}
currentProperty.type = content;
@@ -306,14 +313,16 @@
creator.finishNode();
} else if (ELEM_PRIMARY_NODE_TYPE.equals(qName)) {
- if ( currentNode == null ) {
- throw new IOException("Element is not allowed at this location: " + qName + " in " + xmlLocation);
+ if (currentNode == null) {
+ throw new IOException(
+ "Element is not allowed at this location: " + qName + " in " + xmlLocation);
}
currentNode.primaryNodeType = content;
} else if (ELEM_MIXIN_NODE_TYPE.equals(qName)) {
- if ( currentNode == null ) {
- throw new IOException("Element is not allowed at this location: " + qName + " in " + xmlLocation);
+ if (currentNode == null) {
+ throw new IOException(
+ "Element is not allowed at this location: " + qName + " in " + xmlLocation);
}
currentNode.addMixinType(content);
}
@@ -326,8 +335,9 @@
}
/**
- * Takes an XML input stream and pipes it through an XSL transformer.
- * Callers should call {@link #startTransform} before trying to use the stream, or the caller will wait indefinately for input.
+ * Takes an XML input stream and pipes it through an XSL transformer. Callers
+ * should call {@link #startTransform} before trying to use the stream, or the
+ * caller will wait indefinately for input.
*/
private static class XslTransformerStream extends PipedInputStream {
private InputStream inputXml;
@@ -338,8 +348,11 @@
/**
* Instantiate the XslTransformerStream.
- * @param inputXml XML to be transformed.
- * @param xslHref Path to an XSL stylesheet
+ *
+ * @param inputXml
+ * XML to be transformed.
+ * @param xslHref
+ * Path to an XSL stylesheet
* @param xmlLocation
* @throws IOException
*/
@@ -353,48 +366,48 @@
}
/**
- * Starts the XSL transformer in a new thread, so that it can pipe its output to our <code>PipedInputStream</code>.
+ * Starts the XSL transformer in a new thread, so that it can pipe its output to
+ * our <code>PipedInputStream</code>.
+ *
* @throws IOException
*/
public void startTransform() throws IOException {
final URL xslResource = new URL(xmlLocation, this.xslHref);
-/*
- if (xslResource == null) {
- throw new IOException("Could not find " + xslHref);
- }
-*/
+ /*
+ * if (xslResource == null) { throw new IOException("Could not find " +
+ * xslHref); }
+ */
- transformerThread = new Thread(
- new Runnable() {
- @Override
- public void run() {
- try {
- Source xml = new StreamSource(inputXml);
- Source xsl = new StreamSource(xslResource.toExternalForm());
- final StreamResult streamResult;
- final Templates templates = TransformerFactory.newInstance().newTemplates(xsl);
- streamResult = new StreamResult(pipedOut);
- templates.newTransformer().transform(xml, streamResult);
- } catch (TransformerConfigurationException e) {
- throw new RuntimeException("Error initializing XSL transformer", e);
- } catch (TransformerException e) {
- throw new RuntimeException("Error transforming", e);
- } finally {
- closeStream(pipedOut);
- }
- }
+ transformerThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Source xml = new StreamSource(inputXml);
+ Source xsl = new StreamSource(xslResource.toExternalForm());
+ final StreamResult streamResult;
+ final Templates templates = TransformerFactory.newInstance().newTemplates(xsl);
+ streamResult = new StreamResult(pipedOut);
+ templates.newTransformer().transform(xml, streamResult);
+ } catch (TransformerConfigurationException e) {
+ throw new RuntimeException("Error initializing XSL transformer", e);
+ } catch (TransformerException e) {
+ throw new RuntimeException("Error transforming", e);
+ } finally {
+ closeStream(pipedOut);
}
- , "XslTransformerThread");
+ }
+ }, "XslTransformerThread");
transformerThread.start();
}
-
}
/**
* Utility function to close a stream if it is still open.
- * @param closeable Stream to close
+ *
+ * @param closeable
+ * Stream to close
*/
private static void closeStream(Closeable closeable) {
if (closeable != null) {
@@ -413,9 +426,8 @@
public String primaryNodeType;
public List<String> mixinTypes;
- public static NodeDescription create(NodeDescription desc, ContentCreator creator)
- throws RepositoryException {
- if ( desc != null ) {
+ public static NodeDescription create(NodeDescription desc, ContentCreator creator) throws RepositoryException {
+ if (desc != null) {
creator.createNode(desc.name, desc.primaryNodeType, desc.getMixinTypes());
desc.clear();
}
@@ -423,15 +435,14 @@
}
public void addMixinType(String v) {
- if ( this.mixinTypes == null ) {
+ if (this.mixinTypes == null) {
this.mixinTypes = new ArrayList<>();
}
this.mixinTypes.add(v);
}
-
private String[] getMixinTypes() {
- if ( this.mixinTypes == null || this.mixinTypes.size() == 0) {
+ if (this.mixinTypes == null || this.mixinTypes.size() == 0) {
return null;
}
return mixinTypes.toArray(new String[this.mixinTypes.size()]);
@@ -440,7 +451,7 @@
private void clear() {
this.name = null;
this.primaryNodeType = null;
- if ( this.mixinTypes != null ) {
+ if (this.mixinTypes != null) {
this.mixinTypes.clear();
}
}
@@ -453,11 +464,11 @@
public static PropertyDescription create(PropertyDescription desc, ContentCreator creator)
throws RepositoryException {
int type = (desc.type == null ? PropertyType.STRING : PropertyType.valueFromName(desc.type));
- if ( desc.isMultiValue ) {
+ if (desc.isMultiValue) {
creator.createProperty(desc.name, type, desc.getPropertyValues());
} else {
String value = null;
- if ( desc.values != null && desc.values.size() == 1 ) {
+ if (desc.values != null && desc.values.size() == 1) {
value = desc.values.get(0);
}
creator.createProperty(desc.name, type, value);
@@ -472,14 +483,14 @@
public boolean isMultiValue;
public void addValue(String v) {
- if ( this.values == null ) {
+ if (this.values == null) {
this.values = new ArrayList<>();
}
this.values.add(v);
}
private String[] getPropertyValues() {
- if ( this.values == null || this.values.size() == 0) {
+ if (this.values == null || this.values.size() == 0) {
return null;
}
return values.toArray(new String[this.values.size()]);
@@ -488,7 +499,7 @@
private void clear() {
this.name = null;
this.type = null;
- if ( this.values != null ) {
+ if (this.values != null) {
this.values.clear();
}
this.isMultiValue = false;
@@ -497,8 +508,10 @@
/**
* Represents an XML processing instruction.<br />
- * A processing instruction like <code><?xml-stylesheet href="stylesheet.xsl" type="text/css"?></code>
- * will have <code>name</code> == <code>"xml-stylesheet"</code> and two attributes: <code>href</code> and <code>type</code>.
+ * A processing instruction like
+ * <code><?xml-stylesheet href="stylesheet.xsl" type="text/css"?></code>
+ * will have <code>name</code> == <code>"xml-stylesheet"</code> and two
+ * attributes: <code>href</code> and <code>type</code>.
*/
private static class ProcessingInstruction {
@@ -531,15 +544,21 @@
}
/**
- * Represents a reference to a file that is to be loaded into the repository. The file is referenced by an
- * XML element named <code><nt:file></code>, with the attributes <code>src</code>,
- * <code>mimeType</code> and <code>lastModified</code>. <br><br>Example:
+ * Represents a reference to a file that is to be loaded into the repository.
+ * The file is referenced by an XML element named <code><nt:file></code>,
+ * with the attributes <code>src</code>, <code>mimeType</code> and
+ * <code>lastModified</code>. <br>
+ * <br>
+ * Example:
+ *
* <pre>
* <nt:file src="../../image.png" mimeType="image/png" lastModified="1977-06-01T07:00:00+0100" />
* </pre>
- * The date format for <code>lastModified</code> is <code>yyyy-MM-dd'T'HH:mm:ssZ</code>.
- * The <code>lastModified</code> attribute is optional. If missing, the last modified date reported by the
- * filesystem will be used.
+ *
+ * The date format for <code>lastModified</code> is
+ * <code>yyyy-MM-dd'T'HH:mm:ssZ</code>. The <code>lastModified</code> attribute
+ * is optional. If missing, the last modified date reported by the filesystem
+ * will be used.
*/
protected static final class FileDescription {
@@ -575,17 +594,17 @@
public void create(ContentCreator creator) throws RepositoryException, IOException {
String[] parts = url.getPath().split("/");
String name = parts[parts.length - 1];
- InputStream stream = url.openStream();
- if (lastModified == null) {
- try {
- lastModified = new File(url.toURI()).lastModified();
- } catch (Throwable ignore) {
- // Could not get lastModified from file system, so we'll use current date
- lastModified = Calendar.getInstance().getTimeInMillis();
+ try (InputStream stream = url.openStream()) {
+ if (lastModified == null) {
+ try {
+ lastModified = new File(url.toURI()).lastModified();
+ } catch (Exception ignore) {
+ // Could not get lastModified from file system, so we'll use current date
+ lastModified = Calendar.getInstance().getTimeInMillis();
+ }
}
+ creator.createFileAndResourceNode(name, stream, mimeType, lastModified);
}
- creator.createFileAndResourceNode(name, stream, mimeType, lastModified);
- closeStream(stream);
creator.finishNode();
creator.finishNode();
this.clear();
@@ -619,17 +638,20 @@
*/
protected static class AttributeMap extends HashMap<String, String> {
- private static final long serialVersionUID = -6304058237706001104L;
- private static final AttributeMap instance = new AttributeMap();
+ private static final long serialVersionUID = -6304058237706001104L;
+ private static final AttributeMap instance = new AttributeMap();
public static AttributeMap getInstance() {
return instance;
}
/**
- * Puts values in an <code>AttributeMap</code> by extracting attributes from the <code>xmlParser</code>.
- * @param xmlParser <code>xmlParser</code> to extract attributes from. The parser must be
- * in {@link org.xmlpull.v1.XmlPullParser#START_TAG} state.
+ * Puts values in an <code>AttributeMap</code> by extracting attributes from the
+ * <code>xmlParser</code>.
+ *
+ * @param xmlParser
+ * <code>xmlParser</code> to extract attributes from. The parser must
+ * be in {@link org.xmlpull.v1.XmlPullParser#START_TAG} state.
*/
public void setValues(KXmlParser xmlParser) {
final int count = xmlParser.getAttributeCount();
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/ZipReader.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/ZipReader.java
index 549ecb5..56f8470 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/ZipReader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/ZipReader.java
@@ -64,9 +64,8 @@
@Override
public void parse(InputStream ins, ContentCreator creator)
throws IOException, RepositoryException {
- try {
+ try ( ZipInputStream zis = new ZipInputStream(ins)) {
creator.createNode(null, NT_FOLDER, null);
- final ZipInputStream zis = new ZipInputStream(ins);
ZipEntry entry;
do {
entry = zis.getNextEntry();
@@ -89,13 +88,6 @@
} while ( entry != null );
creator.finishNode();
- } finally {
- if (ins != null) {
- try {
- ins.close();
- } catch (IOException ignore) {
- }
- }
}
}
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/package-info.java b/src/main/java/org/apache/sling/jcr/contentloader/package-info.java
index 155fe79..7bb87b6 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/package-info.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/package-info.java
@@ -17,6 +17,6 @@
* under the License.
*/
-@org.osgi.annotation.versioning.Version("0.3.0")
+@org.osgi.annotation.versioning.Version("0.4.0")
package org.apache.sling.jcr.contentloader;
diff --git a/src/test/java/org/apache/sling/jcr/contentloader/internal/CreateNodeTest.java b/src/test/java/org/apache/sling/jcr/contentloader/internal/CreateNodeTest.java
index 15f4181..7bfd966 100644
--- a/src/test/java/org/apache/sling/jcr/contentloader/internal/CreateNodeTest.java
+++ b/src/test/java/org/apache/sling/jcr/contentloader/internal/CreateNodeTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.apache.sling.jcr.contentloader.internal.ImportOptionsFactory.*;
import java.util.HashMap;
import java.util.UUID;
@@ -51,7 +52,7 @@
final SlingRepository repo = RepositoryProvider.instance().getRepository();
session = repo.loginAdministrative(null);
contentCreator = new DefaultContentCreator(null);
- contentCreator.init(ImportOptionsFactory.createImportOptions(true, true, true, false, false),
+ contentCreator.init(createImportOptions(OVERWRITE_NODE | OVERWRITE_PROPERTIES | AUTO_CHECKOUT),
new HashMap<String, ContentReader>(), null, null);
testRoot = session.getRootNode().addNode(getClass().getSimpleName()).addNode(uniqueId());
}
diff --git a/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java b/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
index 4f56932..06d4ca0 100644
--- a/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
+++ b/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
@@ -37,6 +37,7 @@
import org.junit.rules.ExpectedException;
import static org.junit.Assert.*;
+import static org.apache.sling.jcr.contentloader.internal.ImportOptionsFactory.*;
public class DefaultContentCreatorTest {
@@ -56,7 +57,7 @@
final SlingRepository repo = RepositoryProvider.instance().getRepository();
session = repo.loginAdministrative(null);
contentCreator = new DefaultContentCreator(null);
- contentCreator.init(ImportOptionsFactory.createImportOptions(true, true, true, false, false),
+ contentCreator.init(createImportOptions(OVERWRITE_NODE|OVERWRITE_PROPERTIES|AUTO_CHECKOUT),
new HashMap<String, ContentReader>(), null, null);
parentNode = session.getRootNode().addNode(getClass().getSimpleName()).addNode(uniqueId());
}
@@ -74,7 +75,7 @@
public void willRewriteUndefinedPropertyType() throws RepositoryException {
parentNode = mockery.mock(Node.class);
prop = mockery.mock(Property.class);
- contentCreator.init(ImportOptionsFactory.createImportOptions(true, true, true, false, false),
+ contentCreator.init(createImportOptions(OVERWRITE_NODE|OVERWRITE_PROPERTIES|AUTO_CHECKOUT),
new HashMap<String, ContentReader>(), null, null);
contentCreator.prepareParsing(parentNode, null);
@@ -91,7 +92,7 @@
public void willNotRewriteUndefinedPropertyType() throws RepositoryException {
parentNode = mockery.mock(Node.class);
prop = mockery.mock(Property.class);
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, true, false, false),
+ contentCreator.init(createImportOptions(AUTO_CHECKOUT),
new HashMap<String, ContentReader>(), null, null);
contentCreator.prepareParsing(parentNode, null);
@@ -114,7 +115,7 @@
oneOf(parentNode).getProperty(propertyName); will(returnValue(prop));
oneOf(prop).isNew(); will(returnValue(false));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, null);
contentCreator.prepareParsing(parentNode, null);
//By calling this method we expect that it will returns on first if-statement
@@ -149,7 +150,7 @@
oneOf(listener).onCreate(with(any(String.class)));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, listener);
contentCreator.prepareParsing(parentNode,null);
contentCreator.createProperty(propertyName, PropertyType.REFERENCE, propertyValue);
@@ -165,7 +166,7 @@
oneOf(parentNode).hasProperty(with(any(String.class)));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, null);
contentCreator.prepareParsing(parentNode, null);
@@ -184,7 +185,7 @@
oneOf(parentNode).hasProperty(with(any(String.class)));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, null);
contentCreator.prepareParsing(parentNode, null);
@@ -211,7 +212,7 @@
oneOf(listener).onCreate(with(any(String.class)));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, listener);
contentCreator.prepareParsing(parentNode, null);
@@ -236,7 +237,7 @@
oneOf(listener).onCreate(with(any(String.class)));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, listener);
contentCreator.prepareParsing(parentNode, null);
@@ -248,7 +249,7 @@
@Test
public void createNodeWithoutNameAndTwoInStack() throws RepositoryException {
- contentCreator.init(ImportOptionsFactory.createImportOptions(true, true, true, false, false),
+ contentCreator.init(createImportOptions(OVERWRITE_NODE|OVERWRITE_PROPERTIES|AUTO_CHECKOUT),
new HashMap<String, ContentReader>(), null, null);
//Making parentNodeStack.size() == 1
contentCreator.prepareParsing(parentNode, DEFAULT_NAME);
@@ -262,9 +263,9 @@
@Test
public void createNodeWithoutProvidedNames() throws RepositoryException, NoSuchFieldException {
@SuppressWarnings("unchecked")
- Stack<Node> nodesStack = (Stack<Node>)PrivateAccessor.getField(contentCreator, "parentNodeStack");
+ Deque<Node> nodesStack = (Deque<Node>)PrivateAccessor.getField(contentCreator, "parentNodeStack");
- contentCreator.init(ImportOptionsFactory.createImportOptions(true, true, true, false, false),
+ contentCreator.init(createImportOptions(OVERWRITE_NODE|OVERWRITE_PROPERTIES|AUTO_CHECKOUT),
new HashMap<String, ContentReader>(), null, null);
contentCreator.prepareParsing(parentNode, null);
@@ -286,7 +287,7 @@
oneOf(listener).onCreate(with(any(String.class)));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(true, false, true, false, false),
+ contentCreator.init(createImportOptions(OVERWRITE_NODE |AUTO_CHECKOUT),
new HashMap<String, ContentReader>(), null, listener);
contentCreator.prepareParsing(parentNode, DEFAULT_NAME);
@@ -307,7 +308,7 @@
@SuppressWarnings("unchecked")
final List<Node> versionables = (List<Node>) PrivateAccessor.getField(contentCreator, "versionables");
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, true, false),
+ contentCreator.init(createImportOptions(CHECK_IN),
new HashMap<String, ContentReader>(), null, null);
contentCreator.prepareParsing(parentNode, DEFAULT_NAME);
@@ -329,7 +330,7 @@
oneOf(listener).onCreate(with(any(String.class)));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(true, false, true, false, false),
+ contentCreator.init(createImportOptions(OVERWRITE_NODE |AUTO_CHECKOUT),
new HashMap<String, ContentReader>(), createdNodes, listener);
contentCreator.prepareParsing(parentNode, DEFAULT_NAME);
@@ -348,7 +349,7 @@
public void propertyDoesntOverwritten() throws RepositoryException {
final String newPropertyName = uniqueId();
final String newPropertyValue = uniqueId();
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, null);
contentCreator.prepareParsing(parentNode, DEFAULT_NAME);
@@ -373,7 +374,7 @@
oneOf(listener).onCreate(with(any(String.class)));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, listener);
contentCreator.prepareParsing(parentNode, DEFAULT_NAME);
@@ -399,7 +400,7 @@
}});
parentNode.addMixin("mix:versionable");
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, true, false, false),
+ contentCreator.init(createImportOptions(AUTO_CHECKOUT),
new HashMap<String, ContentReader>(), null, listener);
contentCreator.prepareParsing(parentNode, null);
@@ -423,7 +424,7 @@
oneOf(listener).onCreate(with(any(String.class)));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, listener);
contentCreator.prepareParsing(parentNode, null);
@@ -437,7 +438,7 @@
public void createOtherProperty() throws RepositoryException {
final String propName = uniqueId();
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, null);
contentCreator.prepareParsing(parentNode, null);
@@ -461,7 +462,7 @@
exactly(3).of(listener).onCreate(with(any(String.class)));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, listener);
contentCreator.prepareParsing(parentNode, null);
@@ -487,7 +488,7 @@
exactly(2).of(listener).onCreate(with(any(String.class)));
}});
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, listener);
contentCreator.prepareParsing(parentNode, null);
@@ -507,7 +508,7 @@
final String propName = uniqueId();
final String underTestNodeName = uniqueId();
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, null);
contentCreator.prepareParsing(parentNode, null);
@@ -523,7 +524,7 @@
final String propName = uniqueId();
final String underTestNodeName = uniqueId();
- contentCreator.init(ImportOptionsFactory.createImportOptions(false, false, false, false, false),
+ contentCreator.init(createImportOptions(NO_OPTIONS),
new HashMap<String, ContentReader>(), null, null);
contentCreator.prepareParsing(parentNode, null);
diff --git a/src/test/java/org/apache/sling/jcr/contentloader/internal/ImportOptionsFactory.java b/src/test/java/org/apache/sling/jcr/contentloader/internal/ImportOptionsFactory.java
index e5dd081..abcec72 100644
--- a/src/test/java/org/apache/sling/jcr/contentloader/internal/ImportOptionsFactory.java
+++ b/src/test/java/org/apache/sling/jcr/contentloader/internal/ImportOptionsFactory.java
@@ -16,68 +16,62 @@
*/
package org.apache.sling.jcr.contentloader.internal;
-import org.apache.sling.jcr.contentloader.ContentReader;
import org.apache.sling.jcr.contentloader.ImportOptions;
-import java.util.Map;
-
public final class ImportOptionsFactory {
- public static ImportOptions createImportOptions(final boolean isOverwrite, final boolean isPropertyOverwrite,
- final boolean isAutoCheckout, final boolean isCheckin, final boolean isIgnoredImportProvider){
+
+ public static final int NO_OPTIONS = 0;
+
+ public static final int OVERWRITE_NODE = 0x1;
+
+ public static final int OVERWRITE_PROPERTIES = 0x1 << 1;
+
+ public static final int SYNCH_PROPERTIES = 0x1 << 2;
+
+ public static final int SYNCH_NODES = 0x1 << 3;
+
+ public static final int AUTO_CHECKOUT = 0x1 << 4;
+
+ public static final int IGNORE_IMPORT_PROVIDER = 0x1 << 5;
+
+ public static final int CHECK_IN = 0x1 << 6;
+
+
+ public static ImportOptions createImportOptions(int options){
return new ImportOptions() {
@Override
public boolean isOverwrite() {
- return isOverwrite;
+ return (options & OVERWRITE_NODE) > NO_OPTIONS;
}
@Override
public boolean isPropertyOverwrite() {
- return isPropertyOverwrite;
+ return (options & OVERWRITE_PROPERTIES) > NO_OPTIONS;
}
@Override
public boolean isAutoCheckout() {
- return isAutoCheckout;
+ return (options & AUTO_CHECKOUT) > NO_OPTIONS;
}
@Override
public boolean isCheckin() {
- return isCheckin;
+ return (options & CHECK_IN) > NO_OPTIONS;
}
@Override
public boolean isIgnoredImportProvider(String extension) {
- return isIgnoredImportProvider;
- }
- };
- }
-
- public static ImportOptions createImportOptsWithReaders(final boolean isOverwrite, final boolean isPropertyOverwrite,
- final boolean isAutoCheckout, final boolean isCheckin, final Map<String, ContentReader> defaultContentReaders){
- return new ImportOptions() {
- @Override
- public boolean isOverwrite() {
- return isOverwrite;
+ return (options & IGNORE_IMPORT_PROVIDER) > NO_OPTIONS;
}
@Override
- public boolean isPropertyOverwrite() {
- return isPropertyOverwrite;
+ public boolean isPropertyMerge() {
+ return (options & SYNCH_PROPERTIES) > NO_OPTIONS;
}
@Override
- public boolean isAutoCheckout() {
- return isAutoCheckout;
- }
-
- @Override
- public boolean isCheckin() {
- return isCheckin;
- }
-
- @Override
- public boolean isIgnoredImportProvider(String extension) {
- return defaultContentReaders.containsKey(extension);
+ public boolean isMerge() {
+ return (options & SYNCH_NODES) > NO_OPTIONS;
}
};
}
diff --git a/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java b/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java
index 91ffcd0..aa2f5df 100644
--- a/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java
+++ b/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java
@@ -50,328 +50,459 @@
this.jsonReader = new JsonReader();
}
- @org.junit.Before public void setUp() throws Exception {
+ @org.junit.Before
+ public void setUp() throws Exception {
setReader();
this.creator = this.mockery.mock(ContentCreator.class);
this.mySequence = this.mockery.sequence("my-sequence");
}
- @org.junit.After public void tearDown() throws Exception {
+ @org.junit.After
+ public void tearDown() throws Exception {
this.jsonReader = null;
}
- @org.junit.Test public void testEmptyObject() throws Exception {
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ @org.junit.Test
+ public void testEmptyObject() throws Exception {
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse("");
}
- @org.junit.Test public void testEmpty() throws IOException, RepositoryException {
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ @org.junit.Test
+ public void testEmpty() throws IOException, RepositoryException {
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse("{}");
}
- @org.junit.Test public void testDefaultPrimaryNodeTypeWithSurroundWhitespace() throws Exception {
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ @org.junit.Test
+ public void testDefaultPrimaryNodeTypeWithSurroundWhitespace() throws Exception {
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
String json = " { } ";
this.parse(json);
}
- @org.junit.Test public void testDefaultPrimaryNodeTypeWithoutEnclosingBracesWithSurroundWhitespace() throws Exception {
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ @org.junit.Test
+ public void testDefaultPrimaryNodeTypeWithoutEnclosingBracesWithSurroundWhitespace() throws Exception {
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
String json = " ";
this.parse(json);
}
- @org.junit.Test public void testExplicitePrimaryNodeType() throws Exception {
+ @org.junit.Test
+ public void testExplicitePrimaryNodeType() throws Exception {
final String type = "xyz:testType";
String json = "{ \"jcr:primaryType\": \"" + type + "\" }";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, type, null); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, type, null);
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testMixinNodeTypes1() throws Exception {
- final String[] mixins = new String[]{ "xyz:mix1" };
+ @org.junit.Test
+ public void testMixinNodeTypes1() throws Exception {
+ final String[] mixins = new String[] { "xyz:mix1" };
String json = "{ \"jcr:mixinTypes\": " + this.toJsonArray(mixins) + "}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, mixins); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, mixins);
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testMixinNodeTypes2() throws Exception {
- final String[] mixins = new String[]{ "xyz:mix1", "abc:mix2" };
+ @org.junit.Test
+ public void testMixinNodeTypes2() throws Exception {
+ final String[] mixins = new String[] { "xyz:mix1", "abc:mix2" };
String json = "{ \"jcr:mixinTypes\": " + this.toJsonArray(mixins) + "}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, mixins); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, mixins);
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testPropertiesEmpty() throws Exception {
+ @org.junit.Test
+ public void testPropertiesEmpty() throws Exception {
String json = "{ \"property\": \"\"}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).createProperty("property", PropertyType.UNDEFINED, ""); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createProperty("property", PropertyType.UNDEFINED, "");
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testPropertiesSingleValue() throws Exception {
+ @org.junit.Test
+ public void testPropertiesSingleValue() throws Exception {
String json = "{ \"p1\": \"v1\"}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).createProperty("p1", PropertyType.UNDEFINED, "v1"); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createProperty("p1", PropertyType.UNDEFINED, "v1");
+ inSequence(mySequence);
+
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testPropertiesSingleDateValue() throws Exception {
+ @org.junit.Test
+ public void testPropertiesSingleDateValue() throws Exception {
String json = "{ \"p1\": \"2009-09-24T16:32:57.948-07:00\"}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).createProperty("p1", PropertyType.DATE, "2009-09-24T16:32:57.948-07:00"); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createProperty("p1", PropertyType.DATE, "2009-09-24T16:32:57.948-07:00");
+ inSequence(mySequence);
+
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testPropertiesTwoSingleValue() throws Exception {
+ @org.junit.Test
+ public void testPropertiesTwoSingleValue() throws Exception {
String json = "{ \"p1\": \"v1\", \"p2\": \"v2\"}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).createProperty("p1", PropertyType.UNDEFINED, "v1"); inSequence(mySequence);
- allowing(creator).createProperty("p2", PropertyType.UNDEFINED, "v2"); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createProperty("p1", PropertyType.UNDEFINED, "v1");
+ inSequence(mySequence);
+ allowing(creator).createProperty("p2", PropertyType.UNDEFINED, "v2");
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testPropertiesMultiValue() throws Exception {
+ @org.junit.Test
+ public void testPropertiesMultiValue() throws Exception {
String json = "{ \"p1\": [\"v1\"]}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).createProperty("p1", PropertyType.UNDEFINED, new String[] {"v1"}); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createProperty("p1", PropertyType.UNDEFINED, new String[] { "v1" });
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testPropertiesMultiDateValue() throws Exception {
+ @org.junit.Test
+ public void testPropertiesMultiDateValue() throws Exception {
String json = "{ \"p1\": [\"2009-09-24T16:32:57.948-07:00\"]}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).createProperty("p1", PropertyType.DATE, new String[] {"2009-09-24T16:32:57.948-07:00"}); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createProperty("p1", PropertyType.DATE,
+ new String[] { "2009-09-24T16:32:57.948-07:00" });
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testPropertiesMultiValueEmpty() throws Exception {
+ @org.junit.Test
+ public void testPropertiesMultiValueEmpty() throws Exception {
String json = "{ \"p1\": []}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).createProperty("p1", PropertyType.STRING, new String[0]); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createProperty("p1", PropertyType.STRING, new String[0]);
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testChild() throws Exception {
- String json = "{ " +
- " \"c1\" : {}" +
- "}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).createNode("c1", null, null); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ @org.junit.Test
+ public void testChild() throws Exception {
+ String json = "{ " + " \"c1\" : {}" + "}";
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createNode("c1", null, null);
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testChildWithMixin() throws Exception {
- String json = "{ " +
- " \"c1\" : {" +
- "\"jcr:mixinTypes\" : [\"xyz:TestType\"]" +
- "}" +
- "}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).createNode("c1", null, new String[] {"xyz:TestType"}); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ @org.junit.Test
+ public void testChildWithMixin() throws Exception {
+ String json = "{ " + " \"c1\" : {" + "\"jcr:mixinTypes\" : [\"xyz:TestType\"]" + "}" + "}";
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createNode("c1", null, new String[] { "xyz:TestType" });
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testTwoChildren() throws Exception {
- String json = "{ " +
- " \"c1\" : {}," +
- " \"c2\" : {}" +
- "}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).createNode("c1", null, null); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- allowing(creator).createNode("c2", null, null); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ @org.junit.Test
+ public void testTwoChildren() throws Exception {
+ String json = "{ " + " \"c1\" : {}," + " \"c2\" : {}" + "}";
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createNode("c1", null, null);
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).createNode("c2", null, null);
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testChildWithProperty() throws Exception {
- String json = "{ " +
- " \"c1\" : {" +
- " \"c1p1\" : \"v1\"" +
- "}" +
- "}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
- allowing(creator).createNode("c1", null, null); inSequence(mySequence);
- allowing(creator).createProperty("c1p1", PropertyType.UNDEFINED, "v1");
- allowing(creator).finishNode(); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ @org.junit.Test
+ public void testChildWithProperty() throws Exception {
+ String json = "{ " + " \"c1\" : {" + " \"c1p1\" : \"v1\"" + "}" + "}";
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createNode("c1", null, null);
+ inSequence(mySequence);
+ allowing(creator).createProperty("c1p1", PropertyType.UNDEFINED, "v1");
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testCreateOnePrincipal() throws Exception {
- String json = "{\"security:principals\":{ " +
- " \"name\" : \"username2\"," +
- " \"password\" : \"pwd2\"" +
- " }}";
+ @org.junit.Test
+ public void testCreateOnePrincipal() throws Exception {
+ String json = "{\"security:principals\":{ " + " \"name\" : \"username2\"," + " \"password\" : \"pwd2\""
+ + " }}";
final LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
- map.put("foo","bar");
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null);
- allowing(creator).createUser("username2", "pwd2",new LinkedHashMap<String, Object>());
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ map.put("foo", "bar");
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ allowing(creator).createUser("username2", "pwd2", new LinkedHashMap<String, Object>());
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- @org.junit.Test public void testCreatePrincipals() throws Exception {
- String json = "{\"security:principals\":[ " +
- " { " +
- " \"name\" : \"username1\"," +
- " \"password\" : \"pwd1\"," +
- " \"foo\" : \"bar\"" +
- " }," +
- " { " +
- " \"name\" : \"username2\"," +
- " \"password\" : \"pwd2\"" +
- " }," +
- " { " +
- " \"name\" : \"group1\"," +
- " \"isgroup\" : true," +
- " \"members\" : [\"username1\",\"username2\"]" +
- " }]}";
+ @org.junit.Test
+ public void testCreatePrincipals() throws Exception {
+ String json = "{\"security:principals\":[ " + " { " + " \"name\" : \"username1\","
+ + " \"password\" : \"pwd1\"," + " \"foo\" : \"bar\"" + " }," + " { "
+ + " \"name\" : \"username2\"," + " \"password\" : \"pwd2\"" + " }," + " { "
+ + " \"name\" : \"group1\"," + " \"isgroup\" : true,"
+ + " \"members\" : [\"username1\",\"username2\"]" + " }]}";
final LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
- map.put("foo","bar");
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null);
- allowing(creator).createUser("username1", "pwd1", map);
- allowing(creator).createUser("username2", "pwd2",new LinkedHashMap<String, Object>());
- allowing(creator).createGroup("group1", new String[]{"username1","username2"}, new LinkedHashMap<String, Object>());
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ map.put("foo", "bar");
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ allowing(creator).createUser("username1", "pwd1", map);
+ allowing(creator).createUser("username2", "pwd2", new LinkedHashMap<String, Object>());
+ allowing(creator).createGroup("group1", new String[] { "username1", "username2" },
+ new LinkedHashMap<String, Object>());
+
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
-
- @org.junit.Test public void testCreateAcl() throws Exception {
- String json = " { " +
- "\"security:acl\" : [ " +
- " { " +
- " \"principal\" : \"username1\"," +
- " \"granted\" : [\"jcr:read\",\"jcr:write\"]," +
- " \"denied\" : []" +
- " }," +
- " {" +
- " \"principal\" : \"groupname1\"," +
- " \"granted\" : [\"jcr:read\",\"jcr:write\"]" +
- " }," +
- " {" +
- " \"principal\" : \"groupname2\"," +
- " \"granted\" : [\"jcr:read\"]," +
- " \"denied\" : [\"jcr:write\"]," +
- " \"order\" : \"first\"" +
- " }" +
- "]" +
- "}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
-
- allowing(creator).createAce("username1",new String[]{"jcr:read","jcr:write"},new String[]{}, null); inSequence(mySequence);
- allowing(creator).createAce("groupname1",new String[]{"jcr:read","jcr:write"},null, null); inSequence(mySequence);
- allowing(creator).createAce("groupname2",new String[]{"jcr:read"},new String[]{"jcr:write"}, "first"); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
- this.parse(json);
- }
-
- @org.junit.Test public void testCreateAclWithTickQuotes() throws Exception {
- String json = " { " +
- "'security:acl' : [ " +
- " { " +
- " 'principal' : 'username1'," +
- " 'granted' : ['jcr:read','jcr:write']," +
- " 'denied' : []" +
- " }," +
- " {" +
- " 'principal' : 'groupname1'," +
- " 'granted' : ['jcr:read','jcr:write']" +
- " }," +
- " {" +
- " 'principal' : \"\\\"'groupname2'\"," +
- " 'granted' : ['jcr:read']," +
- " 'denied' : ['jcr:write']," +
- " 'order' : 'first'" +
- " }" +
- "]" +
- "}";
- this.mockery.checking(new Expectations() {{
- allowing(creator).createNode(null, null, null); inSequence(mySequence);
-
- allowing(creator).createAce("username1",new String[]{"jcr:read","jcr:write"},new String[]{}, null); inSequence(mySequence);
- allowing(creator).createAce("groupname1",new String[]{"jcr:read","jcr:write"},null, null); inSequence(mySequence);
- allowing(creator).createAce("\"'groupname2'",new String[]{"jcr:read"},new String[]{"jcr:write"}, "first"); inSequence(mySequence);
- allowing(creator).finishNode(); inSequence(mySequence);
- }});
+ @org.junit.Test
+ public void testCreateAcl() throws Exception {
+ String json = " { " + "\"security:acl\" : [ " + " { " + " \"principal\" : \"username1\","
+ + " \"granted\" : [\"jcr:read\",\"jcr:write\"]," + " \"denied\" : []" + " }," + " {"
+ + " \"principal\" : \"groupname1\"," + " \"granted\" : [\"jcr:read\",\"jcr:write\"]" + " },"
+ + " {" + " \"principal\" : \"groupname2\"," + " \"granted\" : [\"jcr:read\"],"
+ + " \"denied\" : [\"jcr:write\"]," + " \"order\" : \"first\"" + " }" + "]" + "}";
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createAce("username1", new String[] { "jcr:read", "jcr:write" }, new String[] {},
+ null);
+ inSequence(mySequence);
+ allowing(creator).createAce("groupname1", new String[] { "jcr:read", "jcr:write" }, null, null);
+ inSequence(mySequence);
+ allowing(creator).createAce("groupname2", new String[] { "jcr:read" }, new String[] { "jcr:write" },
+ "first");
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
this.parse(json);
}
- //---------- internal helper ----------------------------------------------
+ @org.junit.Test
+ public void testCreateAclWithTickQuotes() throws Exception {
+ String json = " { " + "'security:acl' : [ " + " { " + " 'principal' : 'username1',"
+ + " 'granted' : ['jcr:read','jcr:write']," + " 'denied' : []" + " }," + " {"
+ + " 'principal' : 'groupname1'," + " 'granted' : ['jcr:read','jcr:write']" + " }," + " {"
+ + " 'principal' : \"\\\"'groupname2'\"," + " 'granted' : ['jcr:read'],"
+ + " 'denied' : ['jcr:write']," + " 'order' : 'first'" + " }" + "]" + "}";
+ this.mockery.checking(new Expectations() {
+ {
+ allowing(creator).createNode(null, null, null);
+ inSequence(mySequence);
+ allowing(creator).createAce("username1", new String[] { "jcr:read", "jcr:write" }, new String[] {},
+ null);
+ inSequence(mySequence);
+ allowing(creator).createAce("groupname1", new String[] { "jcr:read", "jcr:write" }, null, null);
+ inSequence(mySequence);
+ allowing(creator).createAce("\"'groupname2'", new String[] { "jcr:read" }, new String[] { "jcr:write" },
+ "first");
+ inSequence(mySequence);
+ allowing(creator).finishNode();
+ inSequence(mySequence);
+ allowing(creator).finish();
+ inSequence(mySequence);
+ }
+ });
+ this.parse(json);
+ }
+
+ // ---------- internal helper ----------------------------------------------
protected void parse(String json) throws IOException, RepositoryException {
String charSet = "ISO-8859-1";
@@ -382,13 +513,11 @@
protected String toJsonArray(String[] array) {
JsonArrayBuilder builder = Json.createArrayBuilder();
- for (String value : array)
- {
+ for (String value : array) {
builder.add(value);
}
StringWriter stringWriter = new StringWriter();
- try (JsonWriter writer = Json.createWriter(stringWriter))
- {
+ try (JsonWriter writer = Json.createWriter(stringWriter)) {
writer.writeArray(builder.build());
}
return stringWriter.toString();
diff --git a/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/OrderedJsonReaderTest.java b/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/OrderedJsonReaderTest.java
index 878a2c3..8eaf7f6 100644
--- a/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/OrderedJsonReaderTest.java
+++ b/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/OrderedJsonReaderTest.java
@@ -47,6 +47,7 @@
allowing(creator).createNode("c2", null, null); inSequence(mySequence);
allowing(creator).finishNode(); inSequence(mySequence);
allowing(creator).finishNode(); inSequence(mySequence);
+ allowing(creator).finish(); inSequence(mySequence);
}});
this.parse(json);
}
diff --git a/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java b/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java
index e4d9439..bdc76c1 100644
--- a/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java
+++ b/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java
@@ -44,11 +44,11 @@
private MockContentCreator creator;
/**
- * Test the XmlReader with an XSLT transform.
+ * Test the XmlReader with an XSLT transform.
*/
public void testXmlReader() throws Exception {
File file = new File("src/test/resources/reader/sample.xml");
- final URL testdata = file.toURI().toURL();
+ final URL testdata = file.toURI().toURL();
reader.parse(testdata, creator);
assertEquals("Did not create expected number of nodes", 1, creator.size());
}
@@ -69,11 +69,12 @@
// Expected
}
assertEquals("mimeType mismatch", "application/test", file.mimeType);
- assertEquals("lastModified mismatch", XmlReader.FileDescription.DATE_FORMAT.parse("1977-06-01T07:00:00+0100"), new Date(file.lastModified));
+ assertEquals("lastModified mismatch", XmlReader.FileDescription.DATE_FORMAT.parse("1977-06-01T07:00:00+0100"),
+ new Date(file.lastModified));
assertEquals("Could not read file", "This is a test file.", file.content);
}
-
+
public void testCreateFileWithNullLocation() throws Exception {
File input = new File("src/test/resources/reader/filesample.xml");
final FileInputStream ins = new FileInputStream(input);
@@ -93,7 +94,8 @@
long originalLastModified = file.lastModified();
assertEquals("Did not create expected number of files", 1, creator.filesCreated.size());
MockContentCreator.FileDescription fileDescription = creator.filesCreated.get(0);
- assertEquals("Did not pick up last modified date from file", originalLastModified, fileDescription.lastModified);
+ assertEquals("Did not pick up last modified date from file", originalLastModified,
+ fileDescription.lastModified);
}
@@ -105,7 +107,7 @@
}
@SuppressWarnings("serial")
- private static class MockContentCreator extends ArrayList<String> implements ContentCreator {
+ private static class MockContentCreator extends ArrayList<String> implements ContentCreator {
public static class FileDescription {
public InputStream data;
@@ -125,10 +127,11 @@
public List<FileDescription> filesCreated = new ArrayList<FileDescription>();
- public MockContentCreator() {
+ public MockContentCreator() {
}
- public void createNode(String name, String primaryNodeType, String[] mixinNodeTypes) throws RepositoryException {
+ public void createNode(String name, String primaryNodeType, String[] mixinNodeTypes)
+ throws RepositoryException {
this.add(name);
}
@@ -147,9 +150,10 @@
public void createProperty(String name, Object[] values) throws RepositoryException {
}
- public void createFileAndResourceNode(String name, InputStream data, String mimeType, long lastModified) throws RepositoryException {
+ public void createFileAndResourceNode(String name, InputStream data, String mimeType, long lastModified)
+ throws RepositoryException {
try {
- this.filesCreated.add(new FileDescription( data, mimeType, lastModified));
+ this.filesCreated.add(new FileDescription(data, mimeType, lastModified));
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -159,27 +163,37 @@
return true;
}
- public void createAce(String principal,
- String[] grantedPrivileges, String[] deniedPrivileges,
- String order)
- throws RepositoryException {
- }
+ public void createAce(String principal, String[] grantedPrivileges, String[] deniedPrivileges, String order)
+ throws RepositoryException {
+ }
- /* (non-Javadoc)
- * @see org.apache.sling.jcr.contentloader.ContentCreator#createAce(java.lang.String, java.lang.String[], java.lang.String[], java.lang.String, java.util.Map, java.util.Map, java.util.Set)
- */
- @Override
- public void createAce(String principal, String[] grantedPrivileges, String[] deniedPrivileges, String order,
- Map<String, Value> restrictions, Map<String, Value[]> mvRestrictions,
- Set<String> removedRestrictionNames) throws RepositoryException {
- }
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.apache.sling.jcr.contentloader.ContentCreator#createAce(java.lang.String,
+ * java.lang.String[], java.lang.String[], java.lang.String, java.util.Map,
+ * java.util.Map, java.util.Set)
+ */
+ @Override
+ public void createAce(String principal, String[] grantedPrivileges, String[] deniedPrivileges, String order,
+ Map<String, Value> restrictions, Map<String, Value[]> mvRestrictions,
+ Set<String> removedRestrictionNames) throws RepositoryException {
+ }
- public void createGroup(String name, String[] members,
- Map<String, Object> extraProperties) throws RepositoryException {
- }
+ public void createGroup(String name, String[] members, Map<String, Object> extraProperties)
+ throws RepositoryException {
+ }
- public void createUser(String name, String password,
- Map<String, Object> extraProperties) throws RepositoryException {
- }
+ public void createUser(String name, String password, Map<String, Object> extraProperties)
+ throws RepositoryException {
+ }
+
+ @Override
+ public void finish() throws RepositoryException {
+ // TODO Auto-generated method stub
+
+ }
+
}
}
diff --git a/src/test/java/org/apache/sling/jcr/contentloader/it/SLING7268InitialContentIT.java b/src/test/java/org/apache/sling/jcr/contentloader/it/SLING7268InitialContentIT.java
index ea4ba32..f7e0e57 100644
--- a/src/test/java/org/apache/sling/jcr/contentloader/it/SLING7268InitialContentIT.java
+++ b/src/test/java/org/apache/sling/jcr/contentloader/it/SLING7268InitialContentIT.java
@@ -57,6 +57,7 @@
/**
* test of a bundle that provides initial content that creates a user/group and defines an ace
* for those principals within the same transaction
+
*/
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)