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    }