You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2012/10/25 14:51:15 UTC
svn commit: r1402132 - in
/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper:
SlingFileUploadHandler.java SlingPropertyValueHandler.java
Author: cziegeler
Date: Thu Oct 25 12:51:15 2012
New Revision: 1402132
URL: http://svn.apache.org/viewvc?rev=1402132&view=rev
Log:
SLING-2530 : Implement CRUD support
Modified:
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingFileUploadHandler.java
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java
Modified: sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingFileUploadHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingFileUploadHandler.java?rev=1402132&r1=1402131&r2=1402132&view=diff
==============================================================================
--- sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingFileUploadHandler.java (original)
+++ sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingFileUploadHandler.java Thu Oct 25 12:51:15 2012
@@ -18,7 +18,9 @@ package org.apache.sling.servlets.post.i
import java.io.IOException;
import java.util.Calendar;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
@@ -28,6 +30,7 @@ import javax.servlet.ServletContext;
import org.apache.jackrabbit.util.Text;
import org.apache.sling.api.request.RequestParameter;
+import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.servlets.post.Modification;
@@ -104,13 +107,128 @@ public class SlingFileUploadHandler {
* @param prop the assembled property info
* @throws RepositoryException if an error occurs
*/
- private void setFile(Node parent, RequestProperty prop, List<Modification> changes)
- throws RepositoryException {
- RequestParameter[] values = prop.getValues();
- for (RequestParameter requestParameter : values) {
- RequestParameter value = requestParameter;
+ private void setFile(final Resource parentResource, final Node parent, final RequestProperty prop, RequestParameter value, final List<Modification> changes, String name, final String contentType)
+ throws RepositoryException, PersistenceException {
+ // check type hint. if the type is ok and extends from nt:file,
+ // create an nt:file with that type. if it's invalid, drop it and let
+ // the parent node type decide.
+ boolean createNtFile = parent.isNodeType(NT_FOLDER);
+ String typeHint = prop.getTypeHint();
+ if (typeHint != null) {
+ try {
+ NodeTypeManager ntMgr = parent.getSession().getWorkspace().getNodeTypeManager();
+ NodeType nt = ntMgr.getNodeType(typeHint);
+ createNtFile = nt.isNodeType(NT_FILE);
+ } catch (RepositoryException e) {
+ // assuming type not valid.
+ typeHint = null;
+ }
+ }
+
+ // also create an nt:file if the name contains an extension
+ // the rationale is that if the file name is "important" we want
+ // an nt:file, and an image name with an extension is probably "important"
+ if(!createNtFile && name.indexOf('.') > 0) {
+ createNtFile = true;
+ }
+
+ // set empty type
+ if (typeHint == null) {
+ typeHint = createNtFile ? NT_FILE : NT_RESOURCE;
+ }
+
+ // create nt:file node if needed
+ Resource resParent;
+ if (createNtFile) {
+ // create nt:file
+ resParent = getOrCreateChildResource(parentResource, name, typeHint, changes);
+ name = JCR_CONTENT;
+ typeHint = NT_RESOURCE;
+ } else {
+ resParent = parentResource;
+ }
+
+ // create resource node
+ Resource newResource = getOrCreateChildResource(resParent, name, typeHint, changes);
+ Node res = newResource.adaptTo(Node.class);
+
+ // set properties
+ changes.add(Modification.onModified(
+ res.setProperty(JCR_LASTMODIFIED, Calendar.getInstance()).getPath()
+ ));
+ changes.add(Modification.onModified(
+ res.setProperty(JCR_MIMETYPE, contentType).getPath()
+ ));
+ try {
+ changes.add(Modification.onModified(
+ res.setProperty(JCR_DATA, value.getInputStream()).getPath()
+ ));
+ } catch (IOException e) {
+ throw new RepositoryException("Error while retrieving inputstream from parameter value.", e);
+ }
+ }
+
+ /**
+ * Uses the file(s) in the request parameter for creation of new nodes.
+ * if the parent node is a nt:folder a new nt:file is created. otherwise
+ * just a nt:resource. if the <code>name</code> is '*', the filename of
+ * the uploaded file is used.
+ *
+ * @param parent the parent node
+ * @param prop the assembled property info
+ * @throws RepositoryException if an error occurs
+ */
+ private void setFile(final Resource parentResource, final RequestProperty prop, final RequestParameter value, final List<Modification> changes, String name, final String contentType)
+ throws PersistenceException, RepositoryException {
+ String typeHint = prop.getTypeHint();
+ if ( typeHint == null ) {
+ typeHint = NT_FILE;
+ }
- // ignore if a plain form field or empty
+ // create properties
+ final Map<String, Object> props = new HashMap<String, Object>();
+ props.put("sling:resourceType", typeHint);
+ props.put(JCR_LASTMODIFIED, Calendar.getInstance());
+ props.put(JCR_MIMETYPE, contentType);
+ try {
+ props.put(JCR_DATA, value.getInputStream());
+ } catch (final IOException e) {
+ throw new PersistenceException("Error while retrieving inputstream from parameter value.", e);
+ }
+
+ // get or create resource
+ Resource result = parentResource.getChild(name);
+ if ( result != null ) {
+ final ModifiableValueMap vm = result.adaptTo(ModifiableValueMap.class);
+ if ( vm == null ) {
+ throw new PersistenceException("Resource at " + parentResource.getPath() + '/' + name + " is not modifiable.");
+ }
+ vm.putAll(props);
+ } else {
+ result = parentResource.getResourceResolver().create(parentResource, name, props);
+ }
+ for(final String key : props.keySet()) {
+ changes.add(Modification.onModified(result.getPath() + '/' + key));
+ }
+ }
+
+ private static final String MT_APP_OCTET = "application/octet-stream";
+
+ /**
+ * Uses the file(s) in the request parameter for creation of new nodes.
+ * if the parent node is a nt:folder a new nt:file is created. otherwise
+ * just a nt:resource. if the <code>name</code> is '*', the filename of
+ * the uploaded file is used.
+ *
+ * @param parent the parent node
+ * @param prop the assembled property info
+ * @throws RepositoryException if an error occurs
+ */
+ public void setFile(final Resource parent, final RequestProperty prop, final List<Modification> changes)
+ throws RepositoryException, PersistenceException {
+ for (final RequestParameter value : prop.getValues()) {
+
+ // ignore if a plain form field or empty
if (value.isFormField() || value.getSize() <= 0) {
continue;
}
@@ -125,48 +243,6 @@ public class SlingFileUploadHandler {
}
name = Text.escapeIllegalJcrChars(name);
- // check type hint. if the type is ok and extends from nt:file,
- // create an nt:file with that type. if it's invalid, drop it and let
- // the parent node type decide.
- boolean createNtFile = parent.isNodeType(NT_FOLDER);
- String typeHint = prop.getTypeHint();
- if (typeHint != null) {
- try {
- NodeTypeManager ntMgr = parent.getSession().getWorkspace().getNodeTypeManager();
- NodeType nt = ntMgr.getNodeType(typeHint);
- createNtFile = nt.isNodeType(NT_FILE);
- } catch (RepositoryException e) {
- // assuming type not valid.
- typeHint = null;
- }
- }
-
- // also create an nt:file if the name contains an extension
- // the rationale is that if the file name is "important" we want
- // an nt:file, and an image name with an extension is probably "important"
- if(!createNtFile && name.indexOf('.') > 0) {
- createNtFile = true;
- }
-
- // set empty type
- if (typeHint == null) {
- typeHint = createNtFile ? NT_FILE : NT_RESOURCE;
- }
-
- // create nt:file node if needed
- Node resParent;
- if (createNtFile) {
- // create nt:file
- resParent = getOrCreateChildNode(parent, name, typeHint, changes);
- name = JCR_CONTENT;
- typeHint = NT_RESOURCE;
- } else {
- resParent = parent;
- }
-
- // create resource node
- Node res = getOrCreateChildNode(resParent, name, typeHint, changes);
-
// get content type
String contentType = value.getContentType();
if (contentType != null) {
@@ -175,64 +251,37 @@ public class SlingFileUploadHandler {
contentType = contentType.substring(0, idx);
}
}
- if (contentType == null || contentType.equals("application/octet-stream")) {
+ if (contentType == null || contentType.equals(MT_APP_OCTET)) {
// try to find a better content type
ServletContext ctx = this.servletContext;
if (ctx != null) {
contentType = ctx.getMimeType(value.getFileName());
}
- if (contentType == null || contentType.equals("application/octet-stream")) {
- contentType = "application/octet-stream";
+ if (contentType == null || contentType.equals(MT_APP_OCTET)) {
+ contentType = MT_APP_OCTET;
}
}
- // set properties
- changes.add(Modification.onModified(
- res.setProperty(JCR_LASTMODIFIED, Calendar.getInstance()).getPath()
- ));
- changes.add(Modification.onModified(
- res.setProperty(JCR_MIMETYPE, contentType).getPath()
- ));
- try {
- changes.add(Modification.onModified(
- res.setProperty(JCR_DATA, value.getInputStream()).getPath()
- ));
- } catch (IOException e) {
- throw new RepositoryException("Error while retrieving inputstream from parameter value.", e);
+ final Node node = parent.adaptTo(Node.class);
+ if ( node == null ) {
+ this.setFile(parent, prop, value, changes, name, contentType);
+ } else {
+ this.setFile(parent, node, prop, value, changes, name, contentType);
}
- }
+ }
+
}
- /**
- * Uses the file(s) in the request parameter for creation of new nodes.
- * if the parent node is a nt:folder a new nt:file is created. otherwise
- * just a nt:resource. if the <code>name</code> is '*', the filename of
- * the uploaded file is used.
- *
- * @param parent the parent node
- * @param prop the assembled property info
- * @throws RepositoryException if an error occurs
- */
- public void setFile(Resource parent, RequestProperty prop, List<Modification> changes)
- throws RepositoryException, PersistenceException {
- final Node node = parent.adaptTo(Node.class);
- if ( node == null ) {
- // TODO
- throw new PersistenceException("Binary properties for resource '" + parent.getPath() + "' currently not supported.");
- }
- this.setFile(node, prop, changes);
- }
-
- private Node getOrCreateChildNode(Node parent, String name, String typeHint,
- List<Modification> changes) throws RepositoryException {
- Node result;
- if (parent.hasNode(name)) {
- Node existing = parent.getNode(name);
- if (!existing.isNodeType(typeHint)) {
+ private Resource getOrCreateChildResource(final Resource parent, final String name,
+ final String typeHint,
+ final List<Modification> changes)
+ throws PersistenceException, RepositoryException {
+ Resource result = parent.getChild(name);
+ if ( result != null ) {
+ final Node existing = result.adaptTo(Node.class);
+ if ( existing != null && !existing.isNodeType(typeHint)) {
existing.remove();
result = createWithChanges(parent, name, typeHint, changes);
- } else {
- result = existing;
}
} else {
result = createWithChanges(parent, name, typeHint, changes);
@@ -240,9 +289,20 @@ public class SlingFileUploadHandler {
return result;
}
- private Node createWithChanges(Node parent, String name, String typeHint,
- List<Modification> changes) throws RepositoryException {
- Node result = parent.addNode(name, typeHint);
+ private Resource createWithChanges(final Resource parent, final String name,
+ final String typeHint,
+ final List<Modification> changes)
+ throws PersistenceException {
+ Map<String, Object> properties = null;
+ if ( typeHint != null ) {
+ properties = new HashMap<String, Object>();
+ if ( parent.adaptTo(Node.class) != null ) {
+ properties.put("jcr:primaryType", typeHint);
+ } else {
+ properties.put("sling:resourceType", typeHint);
+ }
+ }
+ final Resource result = parent.getResourceResolver().create(parent, name, properties);
changes.add(Modification.onCreated(result.getPath()));
return result;
}
Modified: sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java?rev=1402132&r1=1402131&r2=1402132&view=diff
==============================================================================
--- sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java (original)
+++ sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java Thu Oct 25 12:51:15 2012
@@ -105,7 +105,7 @@ public class SlingPropertyValueHandler {
* @throws RepositoryException if a repository error occurs
*/
public void setProperty(final Resource parent, final RequestProperty prop)
- throws RepositoryException, PersistenceException {
+ throws RepositoryException, PersistenceException {
final Modifiable mod = new Modifiable();
mod.resource = parent;
mod.node = parent.adaptTo(Node.class);
@@ -124,22 +124,22 @@ public class SlingPropertyValueHandler {
final boolean isNew = (mod.node != null ? mod.node.isNew() : true);
try {
switch (AUTO_PROPS.get(name)) {
- case CREATED:
- if (isNew) {
- setCurrentDate(mod, name);
- }
- break;
- case CREATED_BY:
- if (isNew) {
- setCurrentUser(mod, name);
- }
- break;
- case MODIFIED:
+ case CREATED:
+ if (isNew) {
setCurrentDate(mod, name);
- break;
- case MODIFIED_BY:
+ }
+ break;
+ case CREATED_BY:
+ if (isNew) {
setCurrentUser(mod, name);
- break;
+ }
+ break;
+ case MODIFIED:
+ setCurrentDate(mod, name);
+ break;
+ case MODIFIED_BY:
+ setCurrentUser(mod, name);
+ break;
}
} catch (ConstraintViolationException e) {
}
@@ -156,7 +156,7 @@ public class SlingPropertyValueHandler {
* @throws RepositoryException if a repository error occurs
*/
private void setCurrentDate(Modifiable parent, String name)
- throws RepositoryException, PersistenceException {
+ throws RepositoryException, PersistenceException {
removePropertyIfExists(parent, name);
parent.valueMap.put(name, now);
changes.add(Modification.onModified(parent.resource.getPath() + '/' + name));
@@ -169,7 +169,7 @@ public class SlingPropertyValueHandler {
* @throws RepositoryException if a repository error occurs
*/
private void setCurrentUser(Modifiable parent, String name)
- throws RepositoryException, PersistenceException {
+ throws RepositoryException, PersistenceException {
removePropertyIfExists(parent, name);
final String user = parent.resource.getResourceResolver().getUserID();
parent.valueMap.put(name, user);
@@ -187,7 +187,7 @@ public class SlingPropertyValueHandler {
* @throws RepositoryException if a repository error occurs.
*/
private String removePropertyIfExists(final Modifiable parent, final String name)
- throws RepositoryException, PersistenceException {
+ throws RepositoryException, PersistenceException {
if (parent.valueMap.containsKey(name) ) {
if ( parent.node != null ) {
final Property prop = parent.node.getProperty(name);
@@ -212,7 +212,7 @@ public class SlingPropertyValueHandler {
* @throws RepositoryException if a repository error occurs.
*/
private void setPropertyAsIs(final Modifiable parent, final RequestProperty prop)
- throws RepositoryException, PersistenceException {
+ throws RepositoryException, PersistenceException {
String[] values = prop.getStringValues();
@@ -263,7 +263,7 @@ public class SlingPropertyValueHandler {
* Patches a multi-value property using add and remove operations per value.
*/
private String[] patch(final Modifiable parent, String name, String[] values)
- throws RepositoryException, PersistenceException {
+ throws RepositoryException, PersistenceException {
// we do not use a Set here, as we want to be very restrictive in our
// actions and avoid touching elements that are not modified through the
// add/remove patch operations; e.g. if the value "foo" occurs twice
@@ -391,7 +391,7 @@ public class SlingPropertyValueHandler {
* removes multi-value properties.
*/
private void clearProperty(final Modifiable parent, RequestProperty prop)
- throws RepositoryException, PersistenceException {
+ throws RepositoryException, PersistenceException {
if (parent.valueMap.containsKey(prop.getName())) {
if ( parent.node != null ) {
if (parent.node.getProperty(prop.getName()).getDefinition().isMultiple()) {
@@ -402,8 +402,8 @@ public class SlingPropertyValueHandler {
}
} else {
changes.add(Modification.onModified(
- parent.node.setProperty(prop.getName(), "").getPath()
- ));
+ parent.node.setProperty(prop.getName(), "").getPath()
+ ));
}
} else {
parent.valueMap.put(prop.getName(), "");
@@ -416,7 +416,7 @@ public class SlingPropertyValueHandler {
* Removes the property if it exists.
*/
private void removeProperty(final Modifiable parent, RequestProperty prop)
- throws RepositoryException, PersistenceException {
+ throws RepositoryException, PersistenceException {
final String removePath = removePropertyIfExists(parent, prop.getName());
if ( removePath != null ) {
changes.add(Modification.onDeleted(removePath));
@@ -427,8 +427,8 @@ public class SlingPropertyValueHandler {
* Removes the property if it exists and is single-valued.
*/
private void removeIfSingleValueProperty(final Modifiable parent,
- final RequestProperty prop)
- throws RepositoryException, PersistenceException {
+ final RequestProperty prop)
+ throws RepositoryException, PersistenceException {
if (parent.valueMap.containsKey(prop.getName())) {
if ( parent.node != null ) {
if (!parent.node.getProperty(prop.getName()).getDefinition().isMultiple()) {
@@ -455,7 +455,7 @@ public class SlingPropertyValueHandler {
* @return true only if parsing was successfull and the property was actually changed
*/
private boolean storeAsDate(final Modifiable parent, String name, String[] values, boolean multiValued, ValueFactory valFac)
- throws RepositoryException, PersistenceException {
+ throws RepositoryException, PersistenceException {
if (multiValued) {
final Value[] array = dateParser.parse(values, valFac);
if (array != null) {
@@ -494,7 +494,7 @@ public class SlingPropertyValueHandler {
* @return true only if parsing was successfull and the property was actually changed
*/
private boolean storeAsReference(final Modifiable parent, String name, String[] values, int type, boolean multiValued, ValueFactory valFac)
- throws RepositoryException, PersistenceException {
+ throws RepositoryException, PersistenceException {
if ( parent.node == null ) {
// TODO
throw new PersistenceException("Resource " + parent.resource.getPath() + " does not support reference properties.");
@@ -503,8 +503,8 @@ public class SlingPropertyValueHandler {
Value[] array = referenceParser.parse(values, valFac, isWeakReference(type));
if (array != null) {
changes.add(Modification.onModified(
- parent.node.setProperty(name, array).getPath()
- ));
+ parent.node.setProperty(name, array).getPath()
+ ));
return true;
}
} else {
@@ -512,8 +512,8 @@ public class SlingPropertyValueHandler {
Value v = referenceParser.parse(values[0], valFac, isWeakReference(type));
if (v != null) {
changes.add(Modification.onModified(
- parent.node.setProperty(name, v).getPath()
- ));
+ parent.node.setProperty(name, v).getPath()
+ ));
return true;
}
}
@@ -522,16 +522,15 @@ public class SlingPropertyValueHandler {
}
/**
- * Stores the property as string or via a strign value, but with an explicit
+ * Stores the property as string or via a string value, but with an explicit
* type. Both multi-value or single-value.
*/
private void store(final Modifiable parent,
- final String name,
- final String[] values,
- final int type,
- final boolean multiValued)
- throws RepositoryException, PersistenceException {
- // TODO
+ final String name,
+ final String[] values,
+ final int type,
+ final boolean multiValued)
+ throws RepositoryException, PersistenceException {
if ( parent.node != null ) {
Property p = null;