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 2008/02/12 10:56:54 UTC
svn commit: r620736 - in
/incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax:
DateParser.java UjaxPostProcessor.java UjaxPostServlet.java
UjaxPropertyValueHandler.java
Author: cziegeler
Date: Tue Feb 12 01:56:49 2008
New Revision: 620736
URL: http://svn.apache.org/viewvc?rev=620736&view=rev
Log:
FIXED - issue SLING-231: ujax post servlet should respect several date formats for @TypeHint="Date"
https://issues.apache.org/jira/browse/SLING-231
Added:
incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/DateParser.java (with props)
Modified:
incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPostProcessor.java
incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPostServlet.java
incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPropertyValueHandler.java
Added: incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/DateParser.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/DateParser.java?rev=620736&view=auto
==============================================================================
--- incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/DateParser.java (added)
+++ incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/DateParser.java Tue Feb 12 01:56:49 2008
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.ujax;
+
+import java.text.SimpleDateFormat;
+import java.text.ParseException;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Calendar;
+
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Takes a string representation of a time-date string and tries for parse it
+ * using different formats.
+ */
+public class DateParser {
+
+ /**
+ * default log
+ */
+ private static final Logger log = LoggerFactory.getLogger(DateParser.class);
+
+ /**
+ * lits of formats
+ */
+ private final List<DateFormat> formats = new LinkedList<DateFormat>();
+
+ /**
+ * Registers a format string to the list of internally checked ones.
+ * Uses the {@link SimpleDateFormat}.
+ * @param format format as in {@link SimpleDateFormat}
+ * @throws IllegalArgumentException if the format is not valid.
+ */
+ public void register(String format) {
+ register(new SimpleDateFormat(format));
+ }
+
+ /**
+ * Registers a date format to the list of internally checked ones.
+ * @param format date format
+ */
+ public void register(DateFormat format) {
+ formats.add(format);
+ }
+
+ /**
+ * Parses the given source string and returns the respective calendar
+ * instance. If no format matches returns <code>null</code>.
+ * <p/>
+ * Note: method is synchronized because SimpleDateFormat is not.
+ *
+ * @param source date time source string
+ * @return calendar representation of the source or <code>null</code>
+ */
+ public synchronized Calendar parse(String source) {
+ for (DateFormat fmt: formats) {
+ try {
+ Date d = fmt.parse(source);
+ if (log.isDebugEnabled()) {
+ log.debug("Parsed " + source + " using " + fmt + " into " + d);
+ }
+ Calendar c = Calendar.getInstance();
+ c.setTime(d);
+ return c;
+ } catch (ParseException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Failed parsing " + source + " using " + fmt);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Parses the given source strings and returns the respective calendar
+ * instances. If no format matches for any of the sources
+ * returns <code>null</code>.
+ * <p/>
+ * Note: method is synchronized because SimpleDateFormat is not.
+ *
+ * @param sources date time source strings
+ * @return calendar representations of the source or <code>null</code>
+ */
+ public synchronized Calendar[] parse(String sources[]) {
+ Calendar ret[] = new Calendar[sources.length];
+ for (int i=0; i< sources.length; i++) {
+ if ((ret[i] = parse(sources[i])) == null) {
+ return null;
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Parses the given source strings and returns the respective jcr date value
+ * instances. If no format matches for any of the sources
+ * returns <code>null</code>.
+ * <p/>
+ * Note: method is synchronized because SimpleDateFormat is not.
+ *
+ * @param sources date time source strings
+ * @param factory the value factory
+ * @return jcr date value representations of the source or <code>null</code>
+ */
+ public synchronized Value[] parse(String sources[], ValueFactory factory) {
+ Value ret[] = new Value[sources.length];
+ for (int i=0; i< sources.length; i++) {
+ Calendar c = parse(sources[i]);
+ if (c == null) {
+ return null;
+ }
+ ret[i] = factory.createValue(c);
+ }
+ return ret;
+ }
+}
\ No newline at end of file
Propchange: incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/DateParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/DateParser.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Modified: incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPostProcessor.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPostProcessor.java?rev=620736&r1=620735&r2=620736&view=diff
==============================================================================
--- incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPostProcessor.java (original)
+++ incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPostProcessor.java Tue Feb 12 01:56:49 2008
@@ -64,6 +64,11 @@
private final NodeNameGenerator nodeNameGenerator;
/**
+ * utility class for parsing date strings
+ */
+ private final DateParser dateParser;
+
+ /**
* the sling http servlet request
*/
private final SlingHttpServletRequest request;
@@ -105,42 +110,44 @@
* @param session jcr session to operate on
* @param nodeNameGenerator the node name generator. use a servlet scoped one,
* so that it can hold states.
+ * @param dateParser helper for parsing date strings
*/
public UjaxPostProcessor(SlingHttpServletRequest request, Session session,
- NodeNameGenerator nodeNameGenerator) {
+ NodeNameGenerator nodeNameGenerator,
+ DateParser dateParser) {
this.request = request;
this.session = session;
// default to non-creating request (trailing DEFAULT_CREATE_SUFFIX)
isCreateRequest = false;
-
+
// calculate the paths
StringBuffer rootPathBuf = new StringBuffer();
String suffix;
Resource currentResource = request.getResource();
if (Resource.RESOURCE_TYPE_NON_EXISTING.equals(currentResource.getResourceType())) {
-
+
// no resource, treat the missing resource path as suffix
suffix = currentResource.getPath();
-
+
} else {
-
+
// resource for part of the path, use request suffix
suffix = request.getRequestPathInfo().getSuffix();
// and preset the path buffer with the resource path
rootPathBuf.append(currentResource.getPath());
-
+
}
// check for extensions or create suffix in the suffix
if (suffix != null) {
-
+
// cut off any selectors/extension from the suffix
int dotPos = suffix.indexOf('.');
if (dotPos > 0) {
suffix = suffix.substring(0, dotPos);
-
+
// otherwise check whether it is a create request (trailing /*)
} else if (suffix.endsWith(UjaxPostServlet.DEFAULT_CREATE_SUFFIX)) {
suffix = suffix.substring(0, suffix.length()
@@ -150,12 +157,13 @@
// append the remains of the suffix to the path buffer
rootPathBuf.append(suffix);
-
+
}
-
+
rootPath = rootPathBuf.toString();
this.nodeNameGenerator = nodeNameGenerator;
+ this.dateParser = dateParser;
propHandler = new UjaxPropertyValueHandler(this);
uploadHandler = new UjaxFileUploadHandler(this);
}
@@ -209,9 +217,8 @@
public String getLocation() {
if (currentPath == null) {
return externalizePath(rootPath);
- } else {
- return externalizePath(currentPath);
}
+ return externalizePath(currentPath);
}
/**
@@ -226,6 +233,14 @@
}
/**
+ * Returns the date parser
+ * @return date parser
+ */
+ public DateParser getDateParser() {
+ return dateParser;
+ }
+
+ /**
* Returns an external form of the given path prepeding the context path
* and appending a display extension.
* @param path the path to externalize
@@ -244,7 +259,7 @@
}
ret.append(ext);
}
-
+
return ret.toString();
}
@@ -300,9 +315,8 @@
public String resolvePath(String path) {
if (path.startsWith("/")) {
return path;
- } else {
- return rootPath + "/" + path;
}
+ return rootPath + "/" + path;
}
/**
@@ -482,7 +496,7 @@
if (path.equals("")) {
return (Node) session.getItem(parent);
}
-
+
// prepend parent path if path is relative
if (path.charAt(0) != '/') {
if (parent == null || !parent.startsWith("/")) {
@@ -492,55 +506,13 @@
if (!parent.endsWith("/")) {
path = "/" + path;
}
-
+
path = parent + path;
}
-
+
String[] pathelems = path.substring(1).split("/");
Node node = session.getRootNode();
-
- for (String name: pathelems) {
- if (node.hasNode(name)) {
- node = node.getNode(name);
- } else {
- node = node.addNode(name);
- changeLog.onCreated(node.getPath());
- }
- }
- return node;
- }
-
- /**
- * Deep gets or creates a node, parent-padding with default nodes nodes.
- * If the path is empty, the given parent node is returned.
- *
- * @param parent parent node for relative paths
- * @param path absolute path to node that needs to be deep-created
- * @return node at path
- * @throws RepositoryException if an error occurs
- * @throws IllegalArgumentException if the path is relative and parent
- * is <code>null</code>
- */
- private Node deepGetOrCreateNode(Node parent, String path)
- throws RepositoryException {
- if(log.isDebugEnabled()) {
- log.debug("Deep-creating Node '{}'", path);
- }
- if (path.equals("")) {
- return parent;
- }
- String[] pathelems;
- Node node;
- if (path.charAt(0) == '/') {
- pathelems = path.substring(1).split("/");
- node = session.getRootNode();
- } else {
- pathelems = path.split("/");
- node = parent;
- if (node == null) {
- throw new IllegalArgumentException("parent node must not be NULL for relative paths.");
- }
- }
+
for (String name: pathelems) {
if (node.hasNode(name)) {
node = node.getNode(name);
Modified: incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPostServlet.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPostServlet.java?rev=620736&r1=620735&r2=620736&view=diff
==============================================================================
--- incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPostServlet.java (original)
+++ incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPostServlet.java Tue Feb 12 01:56:49 2008
@@ -16,23 +16,18 @@
*/
package org.apache.sling.ujax;
+import java.io.IOException;
+
+import javax.jcr.Session;
+import javax.servlet.ServletException;
+
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
-import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
-import org.apache.sling.api.wrappers.SlingRequestPaths;
-import org.apache.sling.core.CoreConstants;
import org.apache.sling.jcr.resource.JcrResourceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.servlet.ServletException;
-
/**
* POST servlet that implements the ujax "protocol"
*/
@@ -126,6 +121,20 @@
*/
private final NodeNameGenerator nodeNameGenerator = new NodeNameGenerator();
+ /**
+ * utility class for parsing date strings
+ */
+ private final DateParser dateParser = new DateParser(); {
+ // TODO: maybe put initialization to OSGI activation ?
+ dateParser.register("EEE MMM dd yyyy HH:mm:ss 'GMT'Z");
+ dateParser.register("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
+ dateParser.register("yyyy-MM-dd'T'HH:mm:ss");
+ dateParser.register("yyyy-MM-dd");
+ dateParser.register("dd.MM.yyyy HH:mm:ss");
+ dateParser.register("dd.MM.yyyy");
+ }
+
+
@Override
protected void doPost(SlingHttpServletRequest request,
SlingHttpServletResponse response)
@@ -159,9 +168,9 @@
if (s == null) {
throw new ServletException("No JCR Session available");
}
-
+
// create the post context
- return new UjaxPostProcessor(request, s, nodeNameGenerator);
+ return new UjaxPostProcessor(request, s, nodeNameGenerator, dateParser);
}
/**
@@ -173,12 +182,12 @@
// redirect param has priority (but see below, magic star)
String result = ctx.getRequest().getParameter(RP_REDIRECT_TO);
if (result != null) {
-
+
// redirect to created/modified Resource
int star = result.indexOf('*');
if (star >= 0) {
StringBuffer buf = new StringBuffer();
-
+
// anything before the star
if (star > 0) {
buf.append(result.substring(0, star));
@@ -190,16 +199,16 @@
nodePath = ctx.getRootPath();
}
buf.append(JcrResourceUtil.getName(nodePath));
-
+
// anything after the star
if (star < result.length() - 1) {
buf.append(result.substring(star + 1));
}
-
+
// use the created path as the redirect result
result = buf.toString();
}
-
+
if (log.isDebugEnabled()) {
log.debug("Will redirect to " + result);
}
Modified: incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPropertyValueHandler.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPropertyValueHandler.java?rev=620736&r1=620735&r2=620736&view=diff
==============================================================================
--- incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPropertyValueHandler.java (original)
+++ incubator/sling/trunk/launchpad/launchpad-servlets/src/main/java/org/apache/sling/ujax/UjaxPropertyValueHandler.java Tue Feb 12 01:56:49 2008
@@ -25,6 +25,9 @@
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import org.apache.jackrabbit.value.ValueFactoryImpl;
/**
* Sets a Property on the given Node, in some cases with a specific type and
@@ -203,11 +206,33 @@
}
} else if (values.length == 1) {
removePropertyIfExists(parent, prop.getName());
+ if (type == PropertyType.DATE) {
+ // try conversion
+ Calendar c = ctx.getDateParser().parse(values[0]);
+ if (c != null) {
+ ctx.getChangeLog().onModified(
+ parent.setProperty(prop.getName(), c).getPath()
+ );
+ return;
+ }
+ // fall back to default behaviour
+ }
ctx.getChangeLog().onModified(
parent.setProperty(prop.getName(), values[0], type).getPath()
);
} else {
removePropertyIfExists(parent, prop.getName());
+ if (type == PropertyType.DATE) {
+ // try conversion
+ Value[] c = ctx.getDateParser().parse(values, ValueFactoryImpl.getInstance());
+ if (c != null) {
+ ctx.getChangeLog().onModified(
+ parent.setProperty(prop.getName(), c).getPath()
+ );
+ return;
+ }
+ // fall back to default behaviour
+ }
ctx.getChangeLog().onModified(
parent.setProperty(prop.getName(), values, type).getPath()
);