/* * #%L * Gravia :: Resource * %% * Copyright (C) 2010 - 2014 JBoss by Red Hat * %% * Licensed 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. * #L% */ package org.jboss.gravia.resource.spi; import static org.jboss.gravia.resource.ContentNamespace.CAPABILITY_MAVEN_IDENTITY_ATTRIBUTE; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.jboss.gravia.resource.MavenCoordinates; import org.jboss.gravia.resource.Version; import org.jboss.gravia.resource.VersionRange; /** * A handler for attribute values. * * @author thomas.diesler@jboss.com * @since 06-Jul-2012 */ public final class AttributeValueHandler { public static enum Type { Boolean, Double, Float, Integer, Long, Maven, String, URL, Version, VersionRange } /** * Read attribute values according to * 132.5.6 Attribute Element */ public static AttributeValue readAttributeValue(String typespec, String valstr) { return readAttributeValue(null, typespec, valstr); } public static AttributeValue readAttributeValue(String keystr, String typespec, String valstr) { boolean listType = false; if (typespec != null && typespec.startsWith("List<") && typespec.endsWith(">")) { typespec = typespec.substring(5, typespec.length() - 1); listType = true; } Type type; if (typespec != null) { type = Type.valueOf(typespec); } else if (CAPABILITY_MAVEN_IDENTITY_ATTRIBUTE.equals(keystr)) { type = Type.Maven; } else { type = Type.String; } // Whitespace around the list and around commas must be trimmed valstr = valstr.trim(); Object value; switch (type) { case Boolean: if (listType) { List<Boolean> list = new ArrayList<>(); for (String val : split(valstr)) { list.add(Boolean.parseBoolean(val.trim())); } value = list; } else { value = Boolean.parseBoolean(valstr); } break; case Double: if (listType) { List<Double> list = new ArrayList<>(); for (String val : split(valstr)) { list.add(Double.parseDouble(val.trim())); } value = list; } else { value = Double.parseDouble(valstr); } break; case Float: if (listType) { List<Float> list = new ArrayList<>(); for (String val : split(valstr)) { list.add(Float.parseFloat(val.trim())); } value = list; } else { value = Float.parseFloat(valstr); } break; case Integer: if (listType) { List<Integer> list = new ArrayList<>(); for (String val : split(valstr)) { list.add(Integer.parseInt(val.trim())); } value = list; } else { value = Integer.parseInt(valstr); } break; case Long: if (listType) { List<Long> list = new ArrayList<>(); for (String val : split(valstr)) { list.add(Long.parseLong(val.trim())); } value = list; } else { value = Long.parseLong(valstr); } break; case Maven: if (listType) { List<MavenCoordinates> list = new ArrayList<>(); for (String val : split(valstr)) { list.add(MavenCoordinates.parse(val.trim())); } value = list; } else { value = MavenCoordinates.parse(valstr); } break; case String: if (listType) { List<String> list = new ArrayList<>(); for (String val : split(valstr)) { list.add(val.trim()); } value = list; } else { value = valstr; } break; case URL: if (listType) { List<URL> list = new ArrayList<>(); for (String val : split(valstr)) { list.add(toURL(val.trim())); } value = list; } else { value = toURL(valstr); } break; case Version: if (listType) { List<Version> list = new ArrayList<>(); for (String val : split(valstr)) { list.add(Version.parseVersion(val.trim())); } value = list; } else { value = Version.parseVersion(valstr); } break; case VersionRange: if (listType) { List<VersionRange> list = new ArrayList<>(); for (String val : split(valstr)) { list.add(new VersionRange(val.trim())); } value = list; } else { value = new VersionRange(valstr); } break; default: value = valstr; break; } return new AttributeValue(type, value); } private static URL toURL(String urlspec) { try { return new URL(urlspec); } catch (MalformedURLException ex) { throw new IllegalArgumentException(ex); } } private static List<String> split(String valstr) { boolean escape = false; StringBuffer tok = new StringBuffer(); List<String> result = new ArrayList<String>(); for (int i = 0; i < valstr.length(); i++) { char ch = valstr.charAt(i); if (ch == '\\' && !escape) { escape = true; continue; } if (escape && ch != '\\' && ch != ',' && ch != '"') { tok.append('\\'); escape = false; } if (ch == ',' && !escape) { result.add(tok.toString()); tok = new StringBuffer(); escape = false; continue; } tok.append(ch); escape = false; } if (tok.length() > 0) { result.add(tok.toString()); } return result; } public static class AttributeValue { private final Type type; private final Object value; private final boolean listType; public static AttributeValue parse(String external) { String typespec = external.substring(external.indexOf("type=") + 5, external.indexOf(',')); String valuestr = external.substring(external.indexOf("value=") + 6, external.length() - 1); return AttributeValueHandler.readAttributeValue(typespec, valuestr); } public static AttributeValue create(Object value) { Class<?> valueType = value.getClass(); boolean listType = List.class.isAssignableFrom(valueType); if (listType) { List<?> list = (List<?>) value; if (!list.isEmpty()) { // Use the type of the first element in the list valueType = list.get(0).getClass(); } else { // For an empty list it is not possible to infer it's component type valueType = String.class; } } Type type; if (MavenCoordinates.class == valueType) { type = Type.Maven; } else { String simpleName = valueType.getSimpleName(); type = Type.valueOf(simpleName); } return new AttributeValue(type, value); } private AttributeValue(Type type, Object value) { assert type != null : "Null type"; assert value != null : "Null value"; this.type = type; this.value = value; Class<? extends Object> valueClass = value.getClass(); this.listType = List.class.isAssignableFrom(valueClass); } public Type getType() { return type; } public Object getValue() { return value; } public String getValueString() { StringBuffer result = new StringBuffer(); if (listType) { for (Object val : (List<?>) value) { if (result.length() > 0) { result.append(", "); } result.append(escape(val)); } } else { result.append(value); } return result.toString(); } private String escape(Object val) { String valstr = val.toString(); if (type != Type.String) return valstr; StringBuffer result = new StringBuffer(); for (int i = 0; i < valstr.length(); i++) { char ch = valstr.charAt(i); if (ch == '\\' || ch == ',' || ch == '"') { result.append("\\" + ch); } else { result.append(ch); } } return result.toString(); } public boolean isListType() { return listType; } public String toExternalForm() { String typespec = listType ? "List<" + type + ">" : "" + type; String valstr = value.toString(); if (listType) { valstr = valstr.substring(1, valstr.length() -1); } return "[type=" + typespec + ", value=" + valstr + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((type == null) ? 0 : type.hashCode()); result = prime * result + ((value == null) ? 0 : value.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof AttributeValue)) return false; AttributeValue other = (AttributeValue) obj; return type.equals(other.type) && value.equals(other.value); } @Override public String toString() { return toExternalForm(); } } }