You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@abdera.apache.org by jm...@apache.org on 2007/11/26 20:13:37 UTC
svn commit: r598389 - in /incubator/abdera/java/trunk:
dependencies/i18n/src/main/java/org/apache/abdera/i18n/io/
dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/
dependencies/i18n/src/main/java/org/apache/abdera/i18n/lang/
dependencies/i18n...
Author: jmsnell
Date: Mon Nov 26 11:13:35 2007
New Revision: 598389
URL: http://svn.apache.org/viewvc?rev=598389&view=rev
Log:
Add in preliminary URI/IRI Template support to the IRI module. Current draft: http://bitworking.org/projects/URI-Templates/draft-gregorio-uritemplate-02.html
Replace all calls t\o StringBuffer with StringBuilder in the IRI module. I haven't tested this in JDK 1.4.2 to see what effect it has there, but this should help improve overall performance when running under JDK 1.5 or higher.
Added:
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/AbstractContext.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/CachingContext.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Context.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Evaluator.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/HashMapContext.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/ObjectContext.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Operation.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Template.java
incubator/abdera/java/trunk/dependencies/i18n/src/test/java/org/apache/abdera/i18n/test/iri/TestTemplate.java
incubator/abdera/java/trunk/examples/src/main/java/org/apache/abdera/examples/ext/URITemplates.java
Modified:
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/io/CharUtils.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Escaping.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/HttpScheme.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/IDNA.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/IRI.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Nameprep.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Punycode.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/lang/Lang.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/unicode/Normalizer.java
incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/unicode/UnicodeCharacterDatabase.java
incubator/abdera/java/trunk/dependencies/i18n/src/test/java/org/apache/abdera/i18n/test/iri/TestSuite.java
incubator/abdera/java/trunk/protocol/src/main/java/org/apache/abdera/protocol/util/EncodingUtil.java
Modified: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/io/CharUtils.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/io/CharUtils.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/io/CharUtils.java (original)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/io/CharUtils.java Mon Nov 26 11:13:35 2007
@@ -17,6 +17,7 @@
*/
package org.apache.abdera.i18n.io;
+import java.io.IOException;
import java.util.Arrays;
/**
@@ -118,11 +119,15 @@
return contains(n,sets);
}
- public static void append(StringBuffer buf, int c) {
- if (isSupplementary(c)) {
- buf.append(getHighSurrogate(c));
- buf.append(getLowSurrogate(c));
- } else buf.append((char)c);
+ public static void append(Appendable buf, int c) {
+ try {
+ if (isSupplementary(c)) {
+ buf.append(getHighSurrogate(c));
+ buf.append(getLowSurrogate(c));
+ } else buf.append((char)c);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
public static char getHighSurrogate(int c) {
@@ -176,7 +181,7 @@
return c;
}
- public static int charAt(StringBuffer s, int i) {
+ public static int charAt(CharSequence s, int i) {
char c = s.charAt(i);
if (c < 0xD800 || c > 0xDFFF) return c;
if (isHighSurrogate(c)) {
@@ -193,33 +198,49 @@
return c;
}
- public static void insert(StringBuffer s, int i, int c) {
- if (i > 0 && i < s.length()) {
- char ch = s.charAt(i);
- boolean low = isLowSurrogate(ch);
- if (low) {
- if (low && isHighSurrogate(s.charAt(i-1))) {
- i--;
- }
- }
+ public static void insert(CharSequence s, int i, int c) {
+ if (!(s instanceof StringBuilder) &&
+ !(s instanceof StringBuffer)) {
+ insert(new StringBuilder(s),i,c);
+ } else {
+ if (i > 0 && i < s.length()) {
+ char ch = s.charAt(i);
+ boolean low = isLowSurrogate(ch);
+ if (low) {
+ if (low && isHighSurrogate(s.charAt(i-1))) {
+ i--;
+ }
+ }
+ }
+ if (s instanceof StringBuffer)
+ ((StringBuffer)s).insert(i, toString(c));
+ else if (s instanceof StringBuilder)
+ ((StringBuilder)s).insert(i, toString(c));
}
- s.insert(i, toString(c));
}
- public static void setChar(StringBuffer s, int i, int c) {
- int l = 1;
- char ch = s.charAt(i);
- boolean high = isHighSurrogate(ch);
- boolean low = isLowSurrogate(ch);
- if (high || low) {
- if (high && (i+1) < s.length() && isLowSurrogate(s.charAt(i+1))) l++;
- else {
- if (low && i > 0 && isHighSurrogate(s.charAt(i-1))) {
- i--; l++;
+ public static void setChar(CharSequence s, int i, int c) {
+ if (!(s instanceof StringBuilder) &&
+ !(s instanceof StringBuffer)) {
+ setChar(new StringBuilder(s),i,c);
+ } else {
+ int l = 1;
+ char ch = s.charAt(i);
+ boolean high = isHighSurrogate(ch);
+ boolean low = isLowSurrogate(ch);
+ if (high || low) {
+ if (high && (i+1) < s.length() && isLowSurrogate(s.charAt(i+1))) l++;
+ else {
+ if (low && i > 0 && isHighSurrogate(s.charAt(i-1))) {
+ i--; l++;
+ }
}
}
+ if (s instanceof StringBuffer)
+ ((StringBuffer)s).replace(i, i+l, toString(c));
+ else if (s instanceof StringBuilder)
+ ((StringBuilder)s).replace(i, i+l, toString(c));
}
- s.replace(i, i+l, toString(c));
}
public static int size(int c) {
@@ -276,7 +297,7 @@
}
private static String wrap(String s, char c1, char c2) {
- StringBuffer buf = new StringBuffer(s);
+ StringBuilder buf = new StringBuilder(s);
if (buf.length() > 1) {
if (buf.charAt(0) != c1) buf.insert(0, c1);
if (buf.charAt(buf.length()-1) != c2) buf.append(c2);
@@ -463,6 +484,13 @@
}
}
),
+ UNRESERVED(
+ new Check() {
+ public boolean escape(int codepoint) {
+ return !isUnreserved(codepoint);
+ }
+ }
+ ),
SCHEMESPECIFICPART(
new Check() {
public boolean escape(int codepoint) {
@@ -491,6 +519,13 @@
}
}
),
+ PCT(
+ new Check() {
+ public boolean escape(int codepoint) {
+ return !CharUtils.isPctEnc(codepoint);
+ }
+ }
+ ),
STD3ASCIIRULES(
new Check() {
public boolean escape(int codepoint) {
@@ -546,7 +581,11 @@
}
public static boolean isUnreserved(int codepoint) {
- return isAlphaNum(codepoint) || isMark(codepoint);
+ return isAlphaNum(codepoint) ||
+ codepoint == '-' ||
+ codepoint == '.' ||
+ codepoint == '_' ||
+ codepoint == '~';
}
public static boolean isReserved(int codepoint) {
Modified: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Escaping.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Escaping.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Escaping.java (original)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Escaping.java Mon Nov 26 11:13:35 2007
@@ -18,6 +18,7 @@
package org.apache.abdera.i18n.iri;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
@@ -37,11 +38,15 @@
private Escaping() {}
- private static void encode(StringBuffer sb, byte... bytes) {
- for (byte c : bytes) {
- sb.append("%");
- sb.append(HEX[(c >> 4) & 0x0f]);
- sb.append(HEX[(c >> 0) & 0x0f]);
+ private static void encode(Appendable sb, byte... bytes) {
+ try {
+ for (byte c : bytes) {
+ sb.append("%");
+ sb.append(HEX[(c >> 4) & 0x0f]);
+ sb.append(HEX[(c >> 0) & 0x0f]);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
}
@@ -64,9 +69,9 @@
private static boolean check(int codepoint, Profile... profiles) {
for (Profile profile : profiles) {
- if (profile.check(codepoint)) return true;
+ if (!profile.check(codepoint)) return false;
}
- return false;
+ return true;
}
public static String encode(
@@ -75,7 +80,7 @@
Profile... profiles)
throws UnsupportedEncodingException {
if (s == null) return s;
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
char[] chars = s.toCharArray();
for (int n = 0; n < chars.length; n++) {
char c = (char) chars[n];
@@ -83,7 +88,7 @@
encode(sb,String.valueOf(c).getBytes(enc));
} else if (CharUtils.isHighSurrogate(c)) {
if (check(c,profiles)) {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
buf.append(c);
buf.append(chars[++n]);
byte[] b = buf.toString().getBytes(enc);
Modified: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/HttpScheme.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/HttpScheme.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/HttpScheme.java (original)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/HttpScheme.java Mon Nov 26 11:13:35 2007
@@ -35,7 +35,7 @@
@Override
public IRI normalize(IRI iri) {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
int port = (iri.getPort() == getDefaultPort()) ? -1 : iri.getPort();
String host = iri.getHost();
if (host != null) host = host.toLowerCase();
Modified: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/IDNA.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/IDNA.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/IDNA.java (original)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/IDNA.java Mon Nov 26 11:13:35 2007
@@ -98,7 +98,7 @@
if (regname == null) return null;
if (regname.length() == 0) return regname;
String[] labels = regname.split("\\\u002E");
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
for (String label : labels) {
label = Nameprep.prep(label);
char[] chars = label.toCharArray();
@@ -109,7 +109,7 @@
if (!CharUtils.inRange(chars,(char)0x000,(char)0x007F)) {
if (label.startsWith("xn--"))
throw new IOException("ToASCII violation");
- String pc = Punycode.encode(chars,null).insert(0, "xn--").toString();
+ String pc = "xn--" + Punycode.encode(chars,null);
chars = pc.toCharArray();
}
if (chars.length > 63)
@@ -127,7 +127,7 @@
if (regname == null) return null;
if (regname.length() == 0) return regname;
String[] labels = regname.split("\\\u002E");
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
for (String label : labels) {
char[] chars = label.toCharArray();
if (!CharUtils.inRange(chars,(char)0x000,(char)0x007F)) {
Modified: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/IRI.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/IRI.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/IRI.java (original)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/IRI.java Mon Nov 26 11:13:35 2007
@@ -85,7 +85,7 @@
this.path = path;
this.query = query;
this.fragment = fragment;
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
buildAuthority(buf,userinfo, host, port);
this.authority = (buf.length()!=0)?buf.toString():null;
init();
@@ -259,7 +259,7 @@
}
void buildAuthority(
- StringBuffer buf,
+ StringBuilder buf,
String aui,
String ah,
int port) {
@@ -278,7 +278,7 @@
private String buildASCIIAuthority() {
if (_scheme instanceof HttpScheme) {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
String aui = getASCIIUserInfo();
String ah = getASCIIHost();
int port = getPort();
@@ -324,7 +324,7 @@
String path,
String query,
String fragment) {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
if (authority != null) {
buf.append("//");
buf.append(authority);
@@ -494,7 +494,7 @@
if (path == null || path.length() == 0) return "/";
String[] segments = path.split("/");
if (segments.length < 2) return path;
- StringBuffer buf = new StringBuffer("/");
+ StringBuilder buf = new StringBuilder("/");
for (int n = 0; n < segments.length; n++) {
String segment = segments[n].intern();
if (segment == ".") {
@@ -529,7 +529,7 @@
return (!cpath.startsWith("/")) ? "/" + cpath : cpath;
}
if (bpath != null && cpath == null) return bpath;
- StringBuffer buf = new StringBuffer("");
+ StringBuilder buf = new StringBuilder("");
int n = bpath.lastIndexOf('/');
if (n > -1) buf.append(bpath.substring(0,n+1));
if (cpath.length() != 0) buf.append(cpath);
@@ -545,7 +545,7 @@
}
public String toString() {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
String scheme = getScheme();
if (scheme != null && scheme.length() != 0) {
buf.append(scheme);
@@ -557,7 +557,7 @@
}
public String toASCIIString() {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
String scheme = getScheme();
if (scheme != null && scheme.length() != 0) {
buf.append(scheme);
Modified: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Nameprep.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Nameprep.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Nameprep.java (original)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Nameprep.java Mon Nov 26 11:13:35 2007
@@ -36,7 +36,7 @@
public static String prep(String s, boolean allowunassigned) {
NameprepCodepointIterator r = null;
try {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
CodepointIterator ci = CodepointIterator.forCharSequence(s);
r = new NameprepCodepointIterator(ci,allowunassigned);
while(r.hasNext()) {
Modified: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Punycode.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Punycode.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Punycode.java (original)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/iri/Punycode.java Mon Nov 26 11:13:35 2007
@@ -79,11 +79,11 @@
return k + (base - tmin + 1) * delta / (delta + skew);
}
- public static StringBuffer encode(
+ public static String encode(
char[] chars,
boolean[] case_flags)
throws IOException {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
CodepointIterator ci = CodepointIterator.forCharArray(chars);
int n, delta, h, b, bias, m, q, k, t;
n = initial_n;
@@ -136,7 +136,7 @@
}
++delta; ++n;
}
- return buf;
+ return buf.toString();
}
public static String encode(String s) {
@@ -159,11 +159,11 @@
}
}
- public static StringBuffer decode(
+ public static String decode(
char[] chars,
boolean[] case_flags)
throws IOException {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
int n, out, i, bias, b, j, in, oldi, w, k, digit, t;
n = initial_n;
out = i = 0;
@@ -204,7 +204,7 @@
}
CharUtils.insert(buf, i++, n);
}
- return buf;
+ return buf.toString();
}
}
Modified: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/lang/Lang.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/lang/Lang.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/lang/Lang.java (original)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/lang/Lang.java Mon Nov 26 11:13:35 2007
@@ -89,7 +89,7 @@
}
public String toString() {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
for (String s: tags) {
if (buf.length() > 0) buf.append('\u002D');
buf.append(s);
Added: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/AbstractContext.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/AbstractContext.java?rev=598389&view=auto
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/AbstractContext.java (added)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/AbstractContext.java Mon Nov 26 11:13:35 2007
@@ -0,0 +1,45 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.i18n.templates;
+
+/**
+ * Abstract base for custom Context implementations
+ */
+public abstract class AbstractContext
+ implements Context {
+
+ protected boolean iri = false;
+ protected boolean normalizing = false;
+
+ public boolean isIri() {
+ return iri;
+ }
+
+ public void setIri(boolean isiri) {
+ this.iri = isiri;
+ }
+
+ public boolean isNormalizing() {
+ return normalizing;
+ }
+
+ public void setNormalizing(boolean normalizing) {
+ this.normalizing = normalizing;
+ }
+
+}
Added: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/CachingContext.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/CachingContext.java?rev=598389&view=auto
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/CachingContext.java (added)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/CachingContext.java Mon Nov 26 11:13:35 2007
@@ -0,0 +1,48 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.i18n.templates;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Abstract Context implementation that caches resolved values so that
+ * do not have to be resolved again
+ */
+@SuppressWarnings("unchecked")
+public abstract class CachingContext
+ extends AbstractContext {
+
+ private Map<String,Object> cache =
+ new HashMap<String,Object>();
+
+ public <T> T resolve(String var) {
+ T t = (T) cache.get(var);
+ if (t == null) {
+ t = (T)resolveActual(var);
+ if (t != null) cache.put(var,t);
+ }
+ return t;
+ }
+
+ protected abstract <T> T resolveActual(String var);
+
+ public void clear() {
+ cache.clear();
+ }
+}
Added: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Context.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Context.java?rev=598389&view=auto
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Context.java (added)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Context.java Mon Nov 26 11:13:35 2007
@@ -0,0 +1,61 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.i18n.templates;
+
+import java.io.Serializable;
+
+/**
+ * Used to resolve values for template variables
+ */
+public interface Context
+ extends Cloneable,
+ Serializable,
+ Iterable<String> {
+
+ /**
+ * Resolve a value for the specified variable. The method
+ * can return either a String, an Array or a Collection.
+ */
+ <T>T resolve(String var);
+
+ /**
+ * True if IRI expansion is enabled
+ */
+ boolean isIri();
+
+ /**
+ * True if IRI expansion is to be enabled
+ */
+ void setIri(boolean isiri);
+
+ /**
+ * True if replacement values are to be Unicode NFC normalized
+ */
+ boolean isNormalizing();
+
+ /**
+ * True if replacement values are to be Unicode NFC normalized
+ */
+ void setNormalizing(boolean normalizing);
+
+ /**
+ * Clear this context
+ */
+ void clear();
+
+}
Added: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Evaluator.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Evaluator.java?rev=598389&view=auto
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Evaluator.java (added)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Evaluator.java Mon Nov 26 11:13:35 2007
@@ -0,0 +1,78 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.i18n.templates;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Evaluates template tokens
+ */
+@SuppressWarnings("unchecked")
+final class Evaluator {
+
+ protected static final Pattern PATTERN =
+ Pattern.compile("(?:-([^\\|]+)\\|)?(?:([^\\|]+)\\|)?(.*)");
+
+ /**
+ * Returns a listing of variable names specified by the
+ * given template token
+ */
+ String[] getVariables(String token) {
+ Matcher matcher = PATTERN.matcher(token);
+ if (matcher.find()) {
+ String op = matcher.group(1);
+ String var = matcher.group(3);
+ return Operation.get(op).getVariables(var);
+ }
+ return new String[0];
+ }
+
+ /**
+ * Writes a plain-text description of the template token
+ */
+ void explain(
+ String token,
+ StringBuilder buf) {
+ Matcher matcher = PATTERN.matcher(token);
+ if (matcher.find()) {
+ String op = matcher.group(1);
+ String arg = matcher.group(2);
+ String var = matcher.group(3);
+ Operation.get(op).explain(var, arg, buf);
+ }
+ }
+
+ /**
+ * Evaluates the template token and returns the resolved value
+ */
+ String evaluate(
+ String token,
+ Context context) {
+ String value = null;
+ Matcher matcher = PATTERN.matcher(token);
+ if (matcher.find()) {
+ String op = matcher.group(1);
+ String arg = matcher.group(2);
+ String var = matcher.group(3);
+ value = Operation.get(op).evaluate(var, arg, context);
+ }
+ return value != null ? value : "";
+ }
+
+}
Added: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/HashMapContext.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/HashMapContext.java?rev=598389&view=auto
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/HashMapContext.java (added)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/HashMapContext.java Mon Nov 26 11:13:35 2007
@@ -0,0 +1,85 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.i18n.templates;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Context implementation based on a HashMap
+ */
+@SuppressWarnings("unchecked")
+public final class HashMapContext
+ extends HashMap<String,Object>
+ implements Context {
+
+ private static final long serialVersionUID = 2206000974505975049L;
+
+ private boolean isiri = false;
+ private boolean normalizing = false;
+
+ public HashMapContext() {}
+
+ public HashMapContext(Map<String,Object> map) {
+ super(map);
+ }
+
+ public <T> T resolve(String var) {
+ return (T)get(var);
+ }
+
+ public boolean isIri() {
+ return isiri;
+ }
+
+ public void setIri(boolean isiri) {
+ this.isiri = isiri;
+ }
+
+ public Iterator<String> iterator() {
+ return keySet().iterator();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + (isiri ? 1231 : 1237);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!super.equals(obj)) return false;
+ if (getClass() != obj.getClass()) return false;
+ final HashMapContext other = (HashMapContext) obj;
+ if (isiri != other.isiri) return false;
+ return true;
+ }
+
+ public boolean isNormalizing() {
+ return normalizing;
+ }
+
+ public void setNormalizing(boolean normalizing) {
+ this.normalizing = normalizing;
+ }
+
+}
Added: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/ObjectContext.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/ObjectContext.java?rev=598389&view=auto
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/ObjectContext.java (added)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/ObjectContext.java Mon Nov 26 11:13:35 2007
@@ -0,0 +1,129 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.i18n.templates;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+@SuppressWarnings("unchecked")
+public final class ObjectContext
+ extends CachingContext {
+
+ private static final long serialVersionUID = -1387599933658718221L;
+ private final Object target;
+ private final Map<String,AccessibleObject> accessors =
+ new HashMap<String,AccessibleObject>();
+
+ public ObjectContext(Object object) {
+ this(object,false);
+ }
+
+ public ObjectContext(Object object, boolean isiri) {
+ if (object == null) throw new IllegalArgumentException();
+ this.target = object;
+ setIri(isiri);
+ initMethods();
+ }
+
+ private void initMethods() {
+ Class _class = target.getClass();
+ if (_class.isAnnotation() ||
+ _class.isArray() ||
+ _class.isEnum() ||
+ _class.isPrimitive())
+ throw new IllegalArgumentException();
+ if (!_class.isInterface()) {
+ Field[] fields = _class.getFields();
+ for (Field field : fields) {
+ if (!Modifier.isPrivate(field.getModifiers())) {
+ accessors.put(field.getName().toLowerCase(), field);
+ }
+ }
+ }
+ Method[] methods = _class.getMethods();
+ for (Method method : methods) {
+ String name = method.getName();
+ if (!Modifier.isPrivate(method.getModifiers()) &&
+ method.getParameterTypes().length == 0 &&
+ !method.getReturnType().equals(Void.class) &&
+ !isReserved(name)) {
+ name = name.toLowerCase();
+ if (name.startsWith("get")) name = name.substring(3);
+ else if (name.startsWith("is")) name = name.substring(2);
+ accessors.put(name, method);
+ }
+ }
+ }
+
+ private boolean isReserved(String name) {
+ return (name.equals("toString") ||
+ name.equals("hashCode") ||
+ name.equals("notify") ||
+ name.equals("notifyAll") ||
+ name.equals("getClass") ||
+ name.equals("wait"));
+ }
+
+ @Override
+ protected <T> T resolveActual(String var) {
+ try {
+ var = var.toLowerCase();
+ AccessibleObject accessor = accessors.get(var);
+ if (accessor == null) return null;
+ if (accessor instanceof Method) {
+ Method method = (Method) accessor;
+ return (T)method.invoke(target);
+ } else if (accessor instanceof Field) {
+ Field field = (Field) accessor;
+ return (T)field.get(target);
+ } else return null;
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Iterator<String> iterator() {
+ return accessors.keySet().iterator();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((target == null) ? 0 : target.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ final ObjectContext other = (ObjectContext) obj;
+ if (target == null) {
+ if (other.target != null) return false;
+ } else if (!target.equals(other.target)) return false;
+ return true;
+ }
+
+}
Added: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Operation.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Operation.java?rev=598389&view=auto
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Operation.java (added)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Operation.java Mon Nov 26 11:13:35 2007
@@ -0,0 +1,378 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.i18n.templates;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.abdera.i18n.io.CharUtils;
+import org.apache.abdera.i18n.iri.Escaping;
+import org.apache.abdera.i18n.unicode.Normalizer;
+
+@SuppressWarnings("unchecked")
+public abstract class Operation
+ implements Serializable {
+
+ protected final String name;
+ protected final boolean multivar;
+
+ protected Operation(String name) {
+ this(name, false);
+ }
+
+ protected Operation(String name, boolean multivar) {
+ this.name = name;
+ this.multivar = multivar;
+ }
+
+ public final String name() {
+ return name;
+ }
+
+ public abstract String evaluate(String var, String arg, Context context);
+
+ public abstract void explain(String var, String arg, StringBuilder buf);
+
+ public String[] getVariables(String var) {
+ List<String> list = new ArrayList<String>();
+ if (!multivar) {
+ String name = tokenName(var);
+ if (!list.contains(name)) list.add(name);
+ } else {
+ String[] vardefs = var.split("\\+?\\s*,\\s*");
+ for (int n = 0; n < vardefs.length; n++) {
+ String vardef = vardefs[n];
+ String name = vardef.split("=",2)[0];
+ if (!list.contains(name)) list.add(name);
+ }
+ }
+ return list.toArray(new String[list.size()]);
+ }
+
+ private static Map<String,Operation> operations = getOperations();
+
+ private static Map<String,Operation> getOperations() {
+ Map<String,Operation> ops = new HashMap<String,Operation>();
+ ops.put("", new DefaultOperation());
+ ops.put("prefix", new PrefixOperation());
+ ops.put("append", new AppendOperation());
+ ops.put("join", new JoinOperation());
+ ops.put("listjoin", new ListJoinOperation());
+ ops.put("opt", new OptOperation());
+ ops.put("neg", new NegOperation());
+ return ops;
+ }
+
+ public static void register(Operation operation) {
+ operations.put(operation.name(),operation);
+ }
+
+ public static Operation get(String name) {
+ if (name == null) name = "";
+ Operation op = operations.get(name);
+ if (op != null) return op;
+ throw new UnsupportedOperationException(name);
+ }
+
+ private static String tokenName(String token) {
+ String[] vardef = token.split("=",2);
+ return vardef[0];
+ }
+
+ private static String evallist(String token, Context context, String sep) {
+ StringBuilder buf = new StringBuilder();
+ Object value = context.resolve(token);
+ if (value != null) {
+ if (value instanceof String) {
+ String val = (String) value;
+ if (val != null && val.length() > 0)
+ buf.append(encode(val,context.isIri(),context.isNormalizing()));
+ } else if (value.getClass().isArray()) {
+ Object[] values = (Object[])value;
+ for (Object obj : values) {
+ String val = toString(obj);
+ if (val != null && val.length() > 0) {
+ if (buf.length() > 0) buf.append(sep);
+ buf.append(encode(val,context.isIri(),context.isNormalizing()));
+ }
+ }
+ } else if (value instanceof Iterable) {
+ Iterable iterable = (Iterable)value;
+ for (Object obj : iterable) {
+ String val = toString(obj);
+ if (val != null && val.length() > 0) {
+ if (buf.length() > 0) buf.append(sep);
+ buf.append(encode(val,context.isIri(),context.isNormalizing()));
+ }
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ protected static String eval(String token, Context context) {
+ String[] vardef = token.split("=",2);
+ String var = vardef[0];
+ String def = vardef.length > 1 ? vardef[1] : null;
+ Object rep = context.resolve(var);
+ String val = toString(rep);
+ return val != null && val.length() > 0 ?
+ encode(rep.toString(),context.isIri(),context.isNormalizing()) :
+ def != null ?
+ def : null;
+ }
+
+ private static String toString(Object val) {
+ return val != null ? val.toString() : null;
+ }
+
+ protected static String eval(String token, String arg, Context context) {
+ String[] vardef = token.split("=",2);
+ String var = vardef[0];
+ String def = vardef.length > 1 ? vardef[1] : null;
+ Object rep = context.resolve(var);
+ if (rep != null) {
+ StringBuilder buf = new StringBuilder();
+ if (rep.getClass().isArray()) {
+ Object[] array = (Object[]) rep;
+ for (Object obj : array) {
+ String val = toString(obj);
+ if (val != null && val.length() > 0) {
+ if (buf.length() > 0) buf.append(arg);
+ buf.append(var);
+ buf.append("=");
+ buf.append(encode(val,context.isIri(),context.isNormalizing()));
+ }
+ }
+ } else if (rep instanceof Iterable) {
+ Iterable list = (Iterable)rep;
+ for (Object obj : list) {
+ String val = toString(obj);
+ if (val != null && val.length() > 0) {
+ if (buf.length() > 0) buf.append(arg);
+ buf.append(var);
+ buf.append("=");
+ buf.append(encode(val,context.isIri(),context.isNormalizing()));
+ }
+ }
+ } else {
+ String val = toString(rep);
+ if (val != null && val.length() > 0) {
+ buf.append(var);
+ buf.append("=");
+ buf.append(encode(val,context.isIri(),context.isNormalizing()));
+ }
+ }
+ return buf.toString();
+ } else if (def != null && def.length() > 0){
+ StringBuilder buf = new StringBuilder();
+ buf.append(var);
+ buf.append("=");
+ buf.append(def);
+ return buf.toString();
+ } else return null;
+ }
+
+ protected static boolean isdefined(String token, Context context) {
+ String[] vardef = token.split("=",2);
+ String var = vardef[0];
+ String def = vardef.length > 1 ? vardef[1] : null;
+ Object rep = context.resolve(var);
+ if (rep == null) rep = def;
+ if (rep == null) return false;
+ if (rep.getClass().isArray()) {
+ Object[] a = (Object[])rep;
+ return a.length > 0;
+ } else return true;
+ }
+
+ private static String encode(
+ String val,
+ boolean isiri,
+ boolean normalizing) {
+ try {
+ return Escaping.encode(
+ !normalizing ? val :
+ Normalizer.normalize(
+ val,
+ Normalizer.Form.C).toString(),
+ isiri ?
+ CharUtils.Profile.IUNRESERVED :
+ CharUtils.Profile.UNRESERVED,
+ CharUtils.Profile.PCT);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static final class DefaultOperation extends Operation {
+ private static final long serialVersionUID = -1279818778391836528L;
+ public DefaultOperation() { super(""); }
+ public String evaluate(String var, String arg, Context context) {
+ return eval(var, context);
+ }
+ public void explain(String var, String arg, StringBuilder buf) {
+ buf.append("Replaced with the value of '");
+ buf.append(var);
+ buf.append("'");
+ }
+ }
+
+ private static final class PrefixOperation extends Operation {
+ private static final long serialVersionUID = 2738115969196268525L;
+ public PrefixOperation() { super("prefix"); }
+ public String evaluate(String var, String arg, Context context) {
+ String value = eval(var,context);
+ return value == null || value.length() == 0 ? "" : arg != null ? arg + value : value;
+ }
+ public void explain(String var, String arg, StringBuilder buf) {
+ buf.append("If '");
+ buf.append(var);
+ buf.append("' is defined then prefix the value of '");
+ buf.append(var);
+ buf.append("' with '");
+ buf.append(arg);
+ buf.append("'");
+ }
+ }
+
+ private static final class AppendOperation extends Operation {
+ private static final long serialVersionUID = -2742793539643289075L;
+ public AppendOperation() { super("append"); }
+ public String evaluate(String var, String arg, Context context) {
+ String value = eval(var,context);
+ return value == null || value.length() == 0 ? "" : arg != null ? value + arg : value;
+ }
+ public void explain(String var, String arg, StringBuilder buf) {
+ buf.append("If '");
+ buf.append(var);
+ buf.append("' is defined then append '");
+ buf.append(arg);
+ buf.append("' to the value of '");
+ buf.append(var);
+ buf.append("'");
+ }
+ }
+
+ private static final class JoinOperation extends Operation {
+ private static final long serialVersionUID = -4102440981071994082L;
+ public JoinOperation() { super("join",true); }
+ public String evaluate(String var, String arg, Context context) {
+ StringBuilder buf = new StringBuilder();
+ String[] vardefs = var.split("\\+?\\s*,\\s*");
+ String val = null;
+ for (int n = 0; n < vardefs.length; n++) {
+ String vardef = vardefs[n];
+ val = eval(vardef,arg,context);
+ if (val != null && val.length() > 0) {
+ if (buf.length() > 0) buf.append(arg);
+ buf.append(val);
+ }
+ }
+ String value = buf.toString();
+ return value;
+ }
+ public void explain(String var, String arg, StringBuilder buf) {
+ buf.append("Join 'var=value' with '" + arg + "' for each variable in [");
+ String[] vars = getVariables(var);
+ boolean b = false;
+ for (String v : vars) {
+ if (b) buf.append(',');
+ else b = true;
+ buf.append("'");
+ buf.append(v);
+ buf.append("'");
+ }
+ buf.append("]");
+ }
+ }
+
+ private static final class ListJoinOperation extends Operation {
+ private static final long serialVersionUID = -8314383556644740425L;
+ public ListJoinOperation() { super("listjoin"); }
+ public String evaluate(String var, String arg, Context context) {
+ return evallist(var,context,arg);
+ }
+ public void explain(String var, String arg, StringBuilder buf) {
+ buf.append("Join the members of the list '");
+ buf.append(var);
+ buf.append("' together with '");
+ buf.append(arg);
+ buf.append("'");
+ }
+ }
+
+ private static final class OptOperation extends Operation {
+ private static final long serialVersionUID = 7808433764609641180L;
+ public OptOperation() { super("opt",true); }
+ public String evaluate(String var, String arg, Context context) {
+ String[] vardefs = var.split("\\s*,\\s*");
+ for (String v : vardefs) {
+ if (isdefined(v,context)) return arg;
+ }
+ return null;
+ }
+ public void explain(String var, String arg, StringBuilder buf) {
+ buf.append("If [");
+ String[] vars = getVariables(var);
+ boolean b = false;
+ for (String v : vars) {
+ if (b) buf.append(',');
+ else b = true;
+ buf.append("'");
+ buf.append(v);
+ buf.append("'");
+ }
+ buf.append("] is defined and a string, or a list with one or more members, then insert '");
+ buf.append(arg);
+ buf.append("'");
+ }
+ }
+
+ private static final class NegOperation extends Operation {
+ private static final long serialVersionUID = 1936380358902743528L;
+ public NegOperation() { super("neg",true); }
+ public String evaluate(String var, String arg, Context context) {
+ String[] vardefs = var.split("\\s*,\\s*");
+ for (String v : vardefs) {
+ if (!isdefined(v,context)) return arg;
+ }
+ return null;
+ }
+ public void explain(String var, String arg, StringBuilder buf) {
+ buf.append("If [");
+ String[] vars = getVariables(var);
+ boolean b = false;
+ for (String v : vars) {
+ if (b) buf.append(',');
+ else b = true;
+ buf.append("'");
+ buf.append(v);
+ buf.append("'");
+ }
+ buf.append("] is undefined, or a zero length list, then insert '");
+ buf.append(arg);
+ buf.append("'");
+ }
+ }
+
+}
Added: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Template.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Template.java?rev=598389&view=auto
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Template.java (added)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/templates/Template.java Mon Nov 26 11:13:35 2007
@@ -0,0 +1,283 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.i18n.templates;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Used to evaluate a URI Template.
+ * Instances are immutable, cloneable, serializable and threadsafe.
+ */
+@SuppressWarnings("unchecked")
+public final class Template
+ implements Iterable<String>,
+ Cloneable,
+ Serializable {
+
+ private static final long serialVersionUID = -613907262632631896L;
+
+ private static final Evaluator EVALUATOR = new Evaluator();
+ private static final Pattern VARIABLE = Pattern.compile("\\{[^{}]+\\}");
+ private static final String TOKEN_START = "\\{";
+ private static final String TOKEN_STOP = "\\}";
+
+ private final String pattern;
+ private final String[] tokens;
+ private final String[] variables;
+
+ /**
+ * @param pattern A URI Template
+ */
+ public Template(
+ String pattern) {
+ this.pattern = pattern;
+ this.tokens = initTokens();
+ this.variables = initVariables();
+ }
+
+ /**
+ * Return the URI Template pattern
+ */
+ public String getPattern() {
+ return pattern;
+ }
+
+ /**
+ * Iterate the template tokens
+ */
+ public Iterator<String> iterator() {
+ return Arrays.asList(tokens).iterator();
+ }
+
+ /**
+ * Return the array of template variables
+ */
+ private String[] initTokens() {
+ Matcher matcher = VARIABLE.matcher(pattern);
+ List<String> tokens = new ArrayList<String>();
+ while (matcher.find()) {
+ String token = matcher.group();
+ token = token.substring(1,token.length()-1);
+ if (!tokens.contains(token))
+ tokens.add(token);
+ }
+ return tokens.toArray(new String[tokens.size()]);
+ }
+
+ private String[] initVariables() {
+ List<String> list = new ArrayList<String>();
+ for (String token : this) {
+ String[] vars = EVALUATOR.getVariables(token);
+ for (String var : vars) {
+ if (!list.contains(var)) list.add(var);
+ }
+ }
+ return list.toArray(new String[list.size()]);
+ }
+
+ /**
+ * Return the array of template variables
+ */
+ public String[] getVariables() {
+ return variables;
+ }
+
+ /**
+ * Expand the URI Template using the specified Context.
+ * @param context The Context impl used to resolve variable values
+ * @return An expanded URI
+ */
+ public String expand(
+ Context context) {
+ String pattern = this.pattern;
+ for(String token : this) {
+ pattern = replace(
+ pattern,
+ token,
+ EVALUATOR.evaluate(
+ token,
+ context));
+ }
+ return pattern;
+ }
+
+ /**
+ * Expand the URI Template using the non-private fields and methods of
+ * the specified object to resolve the template tokens
+ */
+ public String expand(Object object) {
+ return expand(object,false);
+ }
+
+ /**
+ * Expand the template using the non-private fields and methods of
+ * the specified object to resolve the template tokens. If isiri
+ * is true, IRI escaping rules will be used.
+ */
+ public String expand(Object object, boolean isiri) {
+ return expand(
+ object instanceof Context ?
+ (Context)object :
+ object instanceof Map ?
+ new HashMapContext((Map)object) :
+ new ObjectContext(object,isiri));
+ }
+
+ private String replace(
+ String pattern,
+ String token,
+ String value) {
+ return pattern.replaceAll(
+ TOKEN_START + Pattern.quote(token) + TOKEN_STOP,
+ value);
+ }
+
+ /**
+ * Clone this Template instance
+ */
+ public Template clone() {
+ try {
+ return (Template)super.clone();
+ } catch (Throwable e) {
+ return new Template(pattern); // not going to happen, but just in case
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((pattern == null) ? 0 : pattern.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ final Template other = (Template) obj;
+ if (pattern == null) {
+ if (other.pattern != null) return false;
+ } else if (!pattern.equals(other.pattern)) return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("Template:");
+ buf.append('\n');
+ buf.append("\t"+pattern);
+ buf.append('\n');
+ buf.append('\n');
+ buf.append(" Variables:");
+ buf.append('\n');
+ String[] vars = getVariables();
+ for (String var : vars) {
+ buf.append('\t');
+ buf.append(var);
+ buf.append('\n');
+ }
+ buf.append('\n');
+ buf.append(" Tokens:");
+ buf.append('\n');
+ for (String token : this) {
+ buf.append('\t');
+ buf.append("{" + token + "} \n\t\t ");
+ EVALUATOR.explain(token, buf);
+ buf.append('\n');
+ }
+ buf.append('\n');
+ buf.append(" Example:");
+ buf.append('\n');
+
+ HashMapContext c = new HashMapContext();
+ for (String var : vars) {
+ c.put(var,"foo");
+ buf.append("\t" + var + " = " + "foo");
+ buf.append('\n');
+ }
+ buf.append('\n');
+ buf.append("\t" + expand(c));
+
+ buf.append('\n');
+ buf.append('\n');
+
+ c.clear();
+ for (int i = 0; i < vars.length;i++) {
+ String var = vars[i];
+ if (i % 2 == 1) {
+ c.put(var, "foo");
+ buf.append("\t" + var + " = " + "foo");
+ buf.append('\n');
+ } else {
+ buf.append("\t" + var + " = null");
+ buf.append('\n');
+ }
+ }
+ buf.append('\n');
+ buf.append("\t" + expand(c));
+
+ buf.append('\n');
+ buf.append('\n');
+
+ c.clear();
+ for (int i = 0; i < vars.length;i++) {
+ String var = vars[i];
+ if (i % 2 == 0) {
+ c.put(var, "foo");
+ buf.append("\t" + var + " = " + "foo");
+ buf.append('\n');
+ } else {
+ buf.append("\t" + var + " = null");
+ buf.append('\n');
+ }
+ }
+ buf.append('\n');
+ buf.append("\t" + expand(c));
+
+ return buf.toString();
+ }
+
+ public static String expand(String pattern, Context context) {
+ Template template = new Template(pattern);
+ return template.expand(context);
+ }
+
+ public static String expand(String pattern, Object object) {
+ return expand(pattern,object,false);
+ }
+
+ public static String expand(String pattern, Object object, boolean isiri) {
+ Template template = new Template(pattern);
+ return template.expand(object,isiri);
+ }
+
+ public static String explain(String pattern) {
+ Template template = new Template(pattern);
+ return template.toString();
+ }
+}
Modified: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/unicode/Normalizer.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/unicode/Normalizer.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/unicode/Normalizer.java (original)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/unicode/Normalizer.java Mon Nov 26 11:13:35 2007
@@ -65,41 +65,41 @@
/**
* Normalize the string using NFKC
*/
- public static StringBuffer normalize(String source) throws IOException {
+ public static String normalize(String source) throws IOException {
return normalize(source, Form.KC);
}
/**
* Normalize the string using the specified Form
*/
- public static StringBuffer normalize(
+ public static String normalize(
String source,
Form form)
throws IOException {
- return normalize(source, form, new StringBuffer());
+ return normalize(source, form, new StringBuilder());
}
/**
- * Normalize the string into the given StringBuffer using the given Form
+ * Normalize the string into the given StringBuilder using the given Form
*/
- public static StringBuffer normalize(
+ public static String normalize(
String source,
Form form,
- StringBuffer buf)
+ StringBuilder buf)
throws IOException {
if (source.length() != 0) {
decompose(source, form, buf);
compose(form, buf);
}
- return buf;
+ return buf.toString();
}
private static void decompose(
String source,
Form form,
- StringBuffer buf)
+ StringBuilder buf)
throws IOException {
- StringBuffer internal = new StringBuffer();
+ StringBuilder internal = new StringBuilder();
CodepointIterator ci = CodepointIterator.forCharSequence(source);
boolean canonical = form.isCanonical();
while (ci.hasNext()) {
@@ -117,7 +117,7 @@
}
private static int findInsertionPoint(
- StringBuffer buf, int c) {
+ StringBuilder buf, int c) {
int cc = UnicodeCharacterDatabase.getCanonicalClass(c);
int i = buf.length();
if (cc != 0) {
@@ -132,7 +132,7 @@
private static void compose(
Form form,
- StringBuffer buf)
+ StringBuilder buf)
throws IOException {
if (!form.isComposition()) return;
int pos = 0;
Modified: incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/unicode/UnicodeCharacterDatabase.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/unicode/UnicodeCharacterDatabase.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/unicode/UnicodeCharacterDatabase.java (original)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/main/java/org/apache/abdera/i18n/unicode/UnicodeCharacterDatabase.java Mon Nov 26 11:13:35 2007
@@ -2187,7 +2187,7 @@
public static void decompose(
int c,
boolean canonical,
- StringBuffer buf) {
+ StringBuilder buf) {
if (c >= 44032 && c <= 55203) {
int z = c - 0xAC00;
int t = z % 0x001C;
Modified: incubator/abdera/java/trunk/dependencies/i18n/src/test/java/org/apache/abdera/i18n/test/iri/TestSuite.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/test/java/org/apache/abdera/i18n/test/iri/TestSuite.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/test/java/org/apache/abdera/i18n/test/iri/TestSuite.java (original)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/test/java/org/apache/abdera/i18n/test/iri/TestSuite.java Mon Nov 26 11:13:35 2007
@@ -30,5 +30,6 @@
addTestSuite(TestNameprep.class);
addTestSuite(TestNFKC.class);
addTestSuite(TestPunycode.class);
+ addTestSuite(TestTemplate.class);
}
}
Added: incubator/abdera/java/trunk/dependencies/i18n/src/test/java/org/apache/abdera/i18n/test/iri/TestTemplate.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/i18n/src/test/java/org/apache/abdera/i18n/test/iri/TestTemplate.java?rev=598389&view=auto
==============================================================================
--- incubator/abdera/java/trunk/dependencies/i18n/src/test/java/org/apache/abdera/i18n/test/iri/TestTemplate.java (added)
+++ incubator/abdera/java/trunk/dependencies/i18n/src/test/java/org/apache/abdera/i18n/test/iri/TestTemplate.java Mon Nov 26 11:13:35 2007
@@ -0,0 +1,270 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.i18n.test.iri;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.abdera.i18n.templates.HashMapContext;
+import org.apache.abdera.i18n.templates.Template;
+
+public final class TestTemplate
+ extends TestCase {
+
+ public static void test1() throws Exception {
+ String t = "http://bitworking.org/news/{entry}";
+ String e = "http://bitworking.org/news/RESTLog_Specification";
+ HashMapContext c = new HashMapContext();
+ c.put("entry", "RESTLog_Specification");
+ eval(t,e,c);
+ }
+
+ public static void test2() throws Exception {
+ String t = "http://example.org/wiki/{entry=FrontPage}";
+ String e = "http://example.org/wiki/FrontPage";
+ HashMapContext c = new HashMapContext();
+ eval(t,e,c);
+ }
+
+ public static void test3() throws Exception {
+ String t = "http://bitworking.org/news/{-listjoin|/|entry}";
+ String e = "http://bitworking.org/news/240/Newsqueak";
+ HashMapContext c = new HashMapContext();
+ c.put("entry", new String[] {"240","Newsqueak"});
+ eval(t,e,c);
+ }
+
+ public static void test4() throws Exception {
+ String t = "http://technorati.com/search/{term}";
+ String e = "http://technorati.com/search/240%2FNewsqueak";
+ HashMapContext c = new HashMapContext();
+ c.put("term", "240/Newsqueak");
+ eval(t,e,c);
+ }
+
+ public static void test5() throws Exception {
+ String t = "http://example.org/{fruit=orange}/";
+ String e = "http://example.org/apple/";
+ String f = "http://example.org/orange/";
+ HashMapContext c = new HashMapContext();
+ c.put("fruit","apple");
+ eval(t,e,c);
+ c.remove("fruit");
+ eval(t,f,c);
+ }
+
+ public static void test6() throws Exception {
+ String t = "bar{-prefix|/|var}/";
+ String e = "bar/foo/";
+ HashMapContext c = new HashMapContext();
+ c.put("var","foo");
+ eval(t,e,c);
+ }
+
+ public static void test7() throws Exception {
+ String t = "bar/{-append|#home|var}";
+ String e = "bar/foo#home";
+ HashMapContext c = new HashMapContext();
+ c.put("var","foo");
+ eval(t,e,c);
+ }
+
+ public static void test8() throws Exception {
+ String t = "{-join|&|name,location,age}";
+ String e = "name=joe&location=NYC";
+ HashMapContext c = new HashMapContext();
+ c.put("name","joe");
+ c.put("location","NYC");
+ eval(t,e,c);
+ }
+
+ public static void test9() throws Exception {
+ String t = "{-listjoin|/|segments}";
+ String e = "a/b/c";
+ HashMapContext c = new HashMapContext();
+ c.put("segments",new String[] {"a","b","c"});
+ eval(t,e,c);
+ }
+
+ public static void test10() throws Exception {
+ String t = "{-opt|/|segments}";
+ String e = "/";
+ HashMapContext c = new HashMapContext();
+ c.put("segments",new String[] {"a","b","c"});
+ eval(t,e,c);
+ }
+
+ public static void test11() throws Exception {
+ String t = "{-neg|/|segments}";
+ String e = "";
+ HashMapContext c = new HashMapContext();
+ c.put("segments",new String[] {"a","b","c"});
+ eval(t,e,c);
+ }
+
+ public static void test12() throws Exception {
+ String t = "http://www.google.com/search?q={term}";
+ String e = "http://www.google.com/search?q=ben%26jerrys";
+ HashMapContext c = new HashMapContext();
+ c.put("term","ben&jerrys");
+ eval(t,e,c);
+ t = "http://www.google.com/search?q={term}";
+ e = "http://www.google.com/search?q=2%2B2%3D5";
+ c = new HashMapContext();
+ c.put("term","2+2=5");
+ eval(t,e,c);
+ t = "http://www.google.com/base/feeds/snippets/?{-join|&|author}";
+ e = "http://www.google.com/base/feeds/snippets/?author=test%40example.com";
+ c = new HashMapContext();
+ c.put("author","test@example.com");
+ eval(t,e,c);
+ }
+
+ public static void test13() throws Exception {
+ String t = "http://www.google.com/search?q={term}";
+ String e = "http://www.google.com/search?q=%C3%8E%C3%B1%C5%A3%C3%A9r%C3%B1%C3%A5%C5%A3%C3%AE%C3%B6%C3%B1%C3%A5%C4%BC%C3%AE%C5%BE%C3%A5%C5%A3%C3%AE%C3%B6%C3%B1";
+ HashMapContext c = new HashMapContext();
+ c.put("term",new String("Ãñţérñåţîöñåļîžåţîöñ".getBytes("UTF-8"),"UTF-8")); // not all java impl's are capable of handling this properly, so we have to force the conversion to UTF-8
+ eval(t,e,c);
+ }
+
+ public static void test14() throws Exception {
+ String t = "{-opt|/-/|categories}{-listjoin|/|categories}";
+ String e = "/-/A%7C-B/-C";
+ HashMapContext c = new HashMapContext();
+ c.put("categories", new String[] {"A|-B","-C"});
+ eval(t,e,c);
+ }
+
+ public static void test15() throws Exception {
+ String t = "http://www.google.com/notebook/feeds/{userID}{-prefix|/notebooks/|notebookID}{-opt|/-/|categories}{-listjoin|/|categories}?{-join|&|updated-min,updated-max,alt,start-index,max-results,entryID,orderby}";
+ String e = "http://www.google.com/notebook/feeds/a/notebooks/b?updated-min=c&max-results=d";
+ HashMapContext c = new HashMapContext();
+ c.put("userID", "a");
+ c.put("notebookID","b");
+ c.put("updated-min","c");
+ c.put("max-results", "d");
+ eval(t,e,c);
+ }
+
+ public static void test16() throws Exception {
+ String t = "http://www.google.com/search?q={term}";
+ String e = "http://www.google.com/search?q=Ãñţérñåţîöñåļîžåţîöñ";
+ HashMapContext c = new HashMapContext();
+ c.setIri(true);
+ c.put("term",new String("Ãñţérñåţîöñåļîžåţîöñ".getBytes("UTF-8"),"UTF-8")); // not all java impl's are capable of handling this properly, so we have to force the conversion to UTF-8
+ eval(t,e,c); // use the IriEvaluator so that pct-encoding is done correctly for IRI's
+ }
+
+ public static void test17() throws Exception {
+ String t = new String("bar{-prefix|/é/|var}/".getBytes("UTF-8"),"UTF-8");
+ String e = new String("bar/é/foo/".getBytes("UTF-8"),"UTF-8");
+ HashMapContext c = new HashMapContext();
+ c.setIri(true);
+ c.put("var","foo");
+ eval(t,e,c);
+ }
+
+ public static void test18() throws Exception {
+ String t = "http://www.google.com/notebook/feeds/{userID}{-prefix|/notebooks/|notebookID}{-opt|/-/|categories}{-listjoin|/|categories}?{-join|&|updated-min,updated-max,alt,start-index,max-results,entryID,orderby}";
+ Template template = new Template(t);
+ String[] variables = template.getVariables();
+ assertEquals(variables[0],"userID");
+ assertEquals(variables[1],"notebookID");
+ assertEquals(variables[2],"categories");
+ assertEquals(variables[3],"updated-min");
+ assertEquals(variables[4],"updated-max");
+ assertEquals(variables[5],"alt");
+ assertEquals(variables[6],"start-index");
+ assertEquals(variables[7],"max-results");
+ assertEquals(variables[8],"entryID");
+ assertEquals(variables[9],"orderby");
+ }
+
+ public static void test19() throws Exception {
+ String t = "http://www.google.com/notebook/feeds/{userID}{-prefix|/notebooks/|notebookID}{-opt|/-/|categories}{-listjoin|/|categories}?{-join|&|updated-min,updated-max,alt,start-index,max-results,entryID,orderby}";
+ Template template = new Template(t);
+ Template t2 = template.clone();
+ assertEquals(template,t2);
+ assertEquals(template.hashCode(),t2.hashCode());
+ }
+
+ public static void test20() throws Exception {
+ Map<String,Object> map = new HashMap<String,Object>();
+ map.put("a","foo");
+ map.put("b","bar");
+ map.put("data","10,20,30");
+ map.put("points", new String[] {"10","20", "30"});
+ map.put("list0", new String [0]);
+ map.put("str0","");
+ map.put("reserved",":/?#[]@!$&'()*+,;=");
+ map.put("u","\u2654\u2655");
+ map.put("a_b","baz");
+
+ Map<String,String> tests = new HashMap<String,String>();
+ tests.put("http://example.org/?q={a}","http://example.org/?q=foo");
+ tests.put("http://example.org/{foo}","http://example.org/");
+ tests.put("relative/{reserved}/","relative/%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D/");
+ tests.put("http://example.org/{foo=fred}","http://example.org/fred");
+ tests.put("http://example.org/{foo=%25}/","http://example.org/%25/");
+ tests.put("/{-prefix|#|foo}","/");
+ tests.put("./{-prefix|#|str0}","./");
+ tests.put("/{-append|/|a}{-opt|data|points}{-neg|@|a}{-prefix|#|b}","/foo/data#bar");
+ tests.put("http://example.org/q={u}","http://example.org/q=%E2%99%94%E2%99%95");
+ tests.put("http://example.org/?{-join|&|a,data}","http://example.org/?a=foo&data=10%2C20%2C30");
+ tests.put("http://example.org/?d={-listjoin|,|points}&{-join|&|a,b}","http://example.org/?d=10,20,30&a=foo&b=bar");
+ tests.put("http://example.org/?d={-listjoin|,|list0}&{-join|&|foo}","http://example.org/?d=&");
+ tests.put("http://example.org/?d={-listjoin|&d=|points}","http://example.org/?d=10&d=20&d=30");
+ tests.put("http://example.org/{a}{b}/{a_b}","http://example.org/foobar/baz");
+ tests.put("http://example.org/{a}{-prefix|/-/|a}/","http://example.org/foo/-/foo/");
+
+ for (String t : tests.keySet())
+ assertEquals(Template.expand(t,map),tests.get(t));
+ }
+
+ public static void test21() throws Exception {
+ String t = "http://example.org/{foo}/{bar}{-opt|/|categories}{-listjoin|/|categories}?{-join|&|baz,tag}";
+ String e = "http://example.org/abc/xyz/a/b?baz=true&tag=x&tag=y&tag=z";
+ assertEquals(Template.expand(t,new MyObject()),e);
+ }
+
+ public static class MyObject {
+ public String foo = "abc";
+ public String getBar() {
+ return "xyz";
+ }
+ public boolean isBaz() {
+ return true;
+ }
+ public String[] getCategories() {
+ return new String[] {"a","b"};
+ }
+ public List<String> getTag() {
+ return Arrays.asList(new String[] {"x","y","z"});
+ }
+ }
+
+ private static void eval(String t, String e, HashMapContext c) {
+ assertEquals(Template.expand(t,c), e);
+ }
+}
+
Added: incubator/abdera/java/trunk/examples/src/main/java/org/apache/abdera/examples/ext/URITemplates.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/examples/src/main/java/org/apache/abdera/examples/ext/URITemplates.java?rev=598389&view=auto
==============================================================================
--- incubator/abdera/java/trunk/examples/src/main/java/org/apache/abdera/examples/ext/URITemplates.java (added)
+++ incubator/abdera/java/trunk/examples/src/main/java/org/apache/abdera/examples/ext/URITemplates.java Mon Nov 26 11:13:35 2007
@@ -0,0 +1,124 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.examples.ext;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.abdera.i18n.templates.CachingContext;
+import org.apache.abdera.i18n.templates.HashMapContext;
+import org.apache.abdera.i18n.templates.Template;
+
+@SuppressWarnings("unchecked")
+public final class URITemplates {
+
+ private static final Template template =
+ new Template("http://example.org{-opt|/~|user}{user}{-opt|/-/|categories}{-listjoin|/|categories}{-opt|?|foo,bar}{-join|&|foo,bar}");
+
+ public static void main(String... args) throws Exception {
+
+ // two examples of resolving the template
+ exampleWithObject();
+ exampleIRIWithObject();
+ exampleWithMap();
+ exampleWithHashMapContext();
+ exampleWithCustomContext();
+
+ // explain the template
+ System.out.println(template);
+ }
+
+ // Using a Java object
+ private static void exampleWithObject() {
+ MyObject myObject = new MyObject();
+ System.out.println(template.expand(myObject));
+ }
+
+ // Using a Java object
+ private static void exampleIRIWithObject() {
+ MyObject myObject = new MyObject();
+ System.out.println(template.expand(myObject,true));
+ }
+
+ // Using a Map
+ private static void exampleWithMap() {
+ Map<String,Object> map = new HashMap();
+ map.put("user","james");
+ map.put("categories", new String[] {"a","b","c"});
+ map.put("foo", "abc");
+ map.put("bar", "xyz");
+ System.out.println(template.expand(map));
+ }
+
+ // Using a HashMap based context
+ private static void exampleWithHashMapContext() {
+ HashMapContext context = new HashMapContext();
+ context.put("user","james");
+ context.put("categories", new String[] {"a","b","c"});
+ context.put("foo", "abc");
+ context.put("bar", "xyz");
+ System.out.println(template.expand(context));
+ }
+
+ // Using a custom context implementation
+ private static void exampleWithCustomContext() {
+ CachingContext context = new CachingContext() {
+ private static final long serialVersionUID = 4896250661828139020L;
+ protected <T> T resolveActual(String var) {
+ if (var.equals("user")) return (T)"james";
+ else if (var.equals("categories")) return (T)new String[] {"a","b","c"};
+ else if (var.equals("foo")) return (T)"abc";
+ else if (var.equals("bar")) return (T)"xyz";
+ else return null;
+ }
+ public Iterator<String> iterator() {
+ return Arrays.asList(new String[] {"user","categories","foo","bar"}).iterator();
+ }
+ };
+ System.out.println(template.expand(context));
+ }
+
+ public static class MyObject {
+ public String user = "james";
+ public List getCategories() {
+ List<String> list =
+ new ArrayList<String>();
+ list.add("a");
+ list.add("b");
+ list.add("c");
+ return list;
+ }
+ public Foo[] getFoo() {
+ return new Foo[] {
+ new Foo(),
+ new Foo()
+ };
+ }
+ public String getBar() {
+ return "xyz";
+ }
+ }
+
+ private static class Foo {
+ public String toString() { return "abcæ"; }
+ }
+}
Modified: incubator/abdera/java/trunk/protocol/src/main/java/org/apache/abdera/protocol/util/EncodingUtil.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/protocol/src/main/java/org/apache/abdera/protocol/util/EncodingUtil.java?rev=598389&r1=598388&r2=598389&view=diff
==============================================================================
--- incubator/abdera/java/trunk/protocol/src/main/java/org/apache/abdera/protocol/util/EncodingUtil.java (original)
+++ incubator/abdera/java/trunk/protocol/src/main/java/org/apache/abdera/protocol/util/EncodingUtil.java Mon Nov 26 11:13:35 2007
@@ -80,10 +80,9 @@
if (lower) slug = slug.toLowerCase();
if (form != null) {
try {
- StringBuffer value =
+ slug =
Normalizer.normalize(
slug, form);
- slug = value.toString();
} catch (Exception e) {}
}
if (filler != null) {