001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.gbean;
019
020 import java.io.Serializable;
021 import java.net.URI;
022 import java.net.URISyntaxException;
023 import java.util.ArrayList;
024 import java.util.Collections;
025 import java.util.Iterator;
026 import java.util.List;
027 import java.util.Map;
028 import java.util.TreeMap;
029 import javax.management.ObjectName;
030
031 import org.apache.geronimo.kernel.repository.Artifact;
032 import org.apache.geronimo.kernel.Jsr77Naming;
033
034 /**
035 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
036 */
037 public class AbstractName implements Serializable {
038 private static final long serialVersionUID = 3584199042821734754L;
039
040 private final Artifact artifact;
041 private final Map name;
042 private final ObjectName objectName;
043 private final URI uri;
044
045 public AbstractName(Artifact artifact, Map name) {
046 if (artifact == null) throw new NullPointerException("artifact is null");
047 if (name == null) throw new NullPointerException("name is null");
048 if (name.isEmpty()) throw new IllegalArgumentException("name is empty");
049
050 this.artifact = artifact;
051 this.name = name;
052
053 this.objectName = Jsr77Naming.createObjectName(name);
054
055 this.uri = createURI(artifact, name);
056 }
057
058 public AbstractName(Artifact artifact, Map name, ObjectName objectName) {
059 if (artifact == null) throw new NullPointerException("artifact is null");
060 if (name == null) throw new NullPointerException("name is null");
061 if (name.isEmpty()) throw new IllegalArgumentException("name is empty");
062 if (objectName == null) throw new NullPointerException("objectName is null");
063
064 this.artifact = artifact;
065 this.name = name;
066 this.objectName = objectName;
067
068 this.uri = createURI(artifact, name);
069 }
070
071 /**
072 * Contructs an AbstractName object from the given URI.
073 *
074 * The artifactId for the AbstractName is constructed from the URI path
075 * (everything up to the ? character) and is composed of four parts delimited by
076 * slashes. The artifactId is the only mandatory part, all slashes are mandatory.
077 *
078 * The name map for the AbstractName is constructed from key=value pairs.
079 * Each key=value pair is delimited by a ',' character and the key is separated
080 * from the value by the '=' character. Each key must be unique.
081 * At least one key=value pair must be specified in the query string.
082 *
083 * The URI has the following format:
084 * [vendorId]/artifactId/[version]/[type]?key=value[,key=value][,...]
085 *
086 * @param uri The URI to be used to generate an AbstractName.
087 */
088 public AbstractName(URI uri) {
089 if (uri == null) throw new NullPointerException("uri is null");
090
091 //
092 // Artifact
093 //
094 String artifactString = uri.getPath();
095 if (artifactString == null) throw new IllegalArgumentException("uri does not contain a path part used for the artifact");
096
097 List artifactParts = split(artifactString, '/');
098 if (artifactParts.size() != 4) {
099 throw new IllegalArgumentException("uri path must be in the form [vendorId]/artifactId/[version]/[type] : " + artifactString);
100 }
101
102 String groupId = (String) artifactParts.get(0);
103 if (groupId.length() == 0) groupId = null;
104
105 String artifactId = (String) artifactParts.get(1);
106 if (artifactId.length() == 0) artifactId = null;
107
108 String version = (String) artifactParts.get(2);
109 if (version.length() == 0) version = null;
110
111 String type = (String) artifactParts.get(3);
112 if (type.length() == 0) type = null;
113
114 artifact = new Artifact(groupId, artifactId, version, type);
115
116 //
117 // name map
118 //
119 name = new TreeMap();
120 String nameString = uri.getQuery();
121 if (nameString == null) {
122 throw new IllegalArgumentException("uri does not contain a query part used for the name map; uri: " + uri);
123 }
124
125 List nameParts = split(nameString, ',');
126 for (Iterator iterator = nameParts.iterator(); iterator.hasNext();) {
127 String namePart = (String) iterator.next();
128 List keyValue = split(namePart, '=');
129 if (keyValue.size() != 2) {
130 throw new IllegalArgumentException("uri query string must be in the form ?key=value[,key=value]*] : " + nameString);
131 }
132 String key = (String) keyValue.get(0);
133 String value = (String) keyValue.get(1);
134 if (name.containsKey(key)) {
135 throw new IllegalArgumentException("uri query string contains the key '"+ key + "' twice : " + nameString);
136 }
137 name.put(key, value);
138 }
139 if (name.isEmpty()) {
140 throw new IllegalArgumentException("name is empty: " + nameString);
141 }
142
143 //
144 // uri
145 //
146 this.uri = createURI(artifact, name);
147
148 //
149 // object name
150 //
151 this.objectName = Jsr77Naming.createObjectName(name);
152 }
153
154 private static URI createURI(Artifact artifact, Map name) {
155 StringBuffer queryString = new StringBuffer();
156 TreeMap treeMap = new TreeMap(name);
157 for (Iterator iterator = treeMap.entrySet().iterator(); iterator.hasNext();) {
158 Map.Entry entry = (Map.Entry) iterator.next();
159 String key = (String) entry.getKey();
160 String value = (String) entry.getValue();
161 queryString.append(key).append('=').append(value);
162 if (iterator.hasNext()) {
163 queryString.append(',');
164 }
165 }
166 try {
167 return new URI(null, null, artifact.toString(), queryString.toString(), null);
168 } catch (URISyntaxException e) {
169 IllegalArgumentException illegalArgumentException = new IllegalArgumentException();
170 illegalArgumentException.initCause(e);
171 throw illegalArgumentException;
172 }
173 }
174
175 // why not use String.split? Because String.split works using regular expressions
176 // and this should be way faster, but write a benchmark it out if you have time.
177 // Also this code is way simpler.
178 private static List split(String source, char delim) {
179 List parts = new ArrayList();
180 for (int index = source.indexOf(delim); index >= 0; index = source.indexOf(delim)) {
181 String part = source.substring(0, index);
182 source = source.substring(index + 1);
183 parts.add(part);
184 }
185 parts.add(source);
186 return parts;
187 }
188
189 public Artifact getArtifact() {
190 return artifact;
191 }
192
193 public Map getName() {
194 return Collections.unmodifiableMap(name);
195 }
196
197 public String getNameProperty(String key) {
198 return (String) name.get(key);
199 }
200
201 public ObjectName getObjectName() {
202 return objectName;
203 }
204
205 public URI toURI() {
206 return uri;
207 }
208
209 public String toString() {
210 return uri.toString();
211 }
212
213 public boolean equals(Object o) {
214 if (this == o) return true;
215 if (o == null || getClass() != o.getClass()) return false;
216
217 final AbstractName that = (AbstractName) o;
218
219 if (artifact != null ? !artifact.equals(that.artifact) : that.artifact != null) return false;
220 return !(name != null ? !name.equals(that.name) : that.name != null);
221
222 }
223
224 public int hashCode() {
225 int result;
226 result = (artifact != null ? artifact.hashCode() : 0);
227 result = 29 * result + (name != null ? name.hashCode() : 0);
228 return result;
229 }
230
231 }