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.HashSet;
026    import java.util.Iterator;
027    import java.util.List;
028    import java.util.Map;
029    import java.util.Set;
030    import java.util.TreeMap;
031    import java.util.TreeSet;
032    
033    import org.apache.geronimo.kernel.repository.Artifact;
034    
035    /**
036     * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
037     */
038    public class AbstractNameQuery implements Serializable {
039        private static final long serialVersionUID = 7444620122607155678L;
040    
041        private final Artifact artifact;
042        private final Map name;
043        private final Set interfaceTypes;
044    
045        private final URI uri;
046    
047        public AbstractNameQuery(AbstractName abstractName) {
048            this(abstractName, null);
049        }
050    
051        public AbstractNameQuery(AbstractName abstractName, Set interfaceTypes) {
052            this.artifact = abstractName.getArtifact();
053            this.name = abstractName.getName();
054            this.interfaceTypes = interfaceTypes == null ? Collections.EMPTY_SET : interfaceTypes;
055            this.uri = createURI(artifact, name, this.interfaceTypes);
056        }
057    
058        public AbstractNameQuery(Artifact artifact, Map name) {
059            this.artifact = artifact;
060            this.name = name;
061            this.interfaceTypes = Collections.EMPTY_SET;
062            this.uri = createURI(artifact, name, interfaceTypes);
063        }
064    
065        public AbstractNameQuery(Artifact artifact, Map name, String interfaceType) {
066            this.artifact = artifact;
067            this.name = name;
068            if (interfaceType != null) {
069                this.interfaceTypes = Collections.singleton(interfaceType);
070            } else {
071                this.interfaceTypes = Collections.EMPTY_SET;
072            }
073            this.uri = createURI(artifact, name, interfaceTypes);
074        }
075    
076        public AbstractNameQuery(String interfaceType) {
077            this.artifact = null;
078            this.name = Collections.EMPTY_MAP;
079            this.interfaceTypes = Collections.singleton(interfaceType);
080            this.uri = createURI(artifact, name, interfaceTypes);
081        }
082    
083        public AbstractNameQuery(Artifact artifact, Map name, Set interfaceTypes) {
084            this.artifact = artifact;
085            this.name = name;
086            if (interfaceTypes == null) interfaceTypes = Collections.EMPTY_SET;
087            this.interfaceTypes = interfaceTypes;
088            this.uri = createURI(artifact, name, this.interfaceTypes);
089        }
090    
091        public AbstractNameQuery(URI uri) {
092            if (uri == null) throw new NullPointerException("uri is null");
093    
094            //
095            // Artifact
096            //
097            String artifactString = uri.getPath();
098            //this doesn't seem to happen
099    //        if (artifactString == null) throw new IllegalArgumentException("uri does not contain a path part used for the artifact");
100    
101            if (artifactString != null && artifactString.length() > 0) {
102                List artifactParts = split(artifactString, '/');
103                if (artifactParts.size() != 4) {
104                    throw new IllegalArgumentException("uri path must be in the form [groupId]/[artifactId]/[version]/[type] : " + artifactString);
105                }
106    
107                String groupId = (String) artifactParts.get(0);
108                if (groupId.length() == 0) groupId = null;
109    
110                String artifactId = (String) artifactParts.get(1);
111                if (artifactId.length() == 0) artifactId = null;
112    
113                String version = (String) artifactParts.get(2);
114                if (version.length() == 0) version = null;
115    
116                String type = (String) artifactParts.get(3);
117                if (type.length() == 0) type = null;
118    
119                artifact = new Artifact(groupId, artifactId, version, type);
120            } else {
121                artifact = null;
122            }
123    
124            //
125            // name map
126            //
127            name = new TreeMap();
128            String nameString = uri.getQuery();
129            List nameParts = split(nameString, ',');
130            for (Iterator iterator = nameParts.iterator(); iterator.hasNext();) {
131                String namePart = (String) iterator.next();
132                List keyValue = split(namePart, '=');
133                if (keyValue.size() != 2) {
134                    throw new IllegalArgumentException("uri query string must be in the form [vendorId]/artifactId/[version]/[type] : " + nameString);
135                }
136                String key = (String) keyValue.get(0);
137                String value = (String) keyValue.get(1);
138                if (name.containsKey(key)) {
139                    throw new IllegalArgumentException("uri query string contains the key '" + key + "' twice : " + nameString);
140                }
141                name.put(key, value);
142            }
143    //        if (name.isEmpty()) {
144    //            throw new IllegalArgumentException("name is empty: " + nameString);
145    //        }
146    
147            String interfaceString = uri.getFragment();
148            List interfaces = split(interfaceString, ',');
149            interfaceTypes = new HashSet(interfaces);
150    
151            //
152            // uri
153            //
154            this.uri = createURI(artifact, name, interfaceTypes);
155        }
156    
157        private static List split(String source, char delim) {
158            List parts = new ArrayList();
159            if (source != null && source.length() > 0) {
160                for (int index = source.indexOf(delim); index >= 0; index = source.indexOf(delim)) {
161                    String part = source.substring(0, index);
162                    source = source.substring(index + 1);
163                    parts.add(part);
164                }
165                parts.add(source);
166            }
167            return parts;
168        }
169    
170        private static URI createURI(Artifact artifact, Map name, Set interfaceTypes) {
171            StringBuffer queryString = new StringBuffer();
172            TreeMap treeMap = new TreeMap(name);
173            for (Iterator iterator = treeMap.entrySet().iterator(); iterator.hasNext();) {
174                Map.Entry entry = (Map.Entry) iterator.next();
175                String key = (String) entry.getKey();
176                String value = (String) entry.getValue();
177                queryString.append(key).append('=').append(value);
178                if (iterator.hasNext()) {
179                    queryString.append(',');
180                }
181            }
182            StringBuffer fragmentString = new StringBuffer();
183            TreeSet treeSet = new TreeSet(interfaceTypes);
184            for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
185                String interfaceType = (String) iterator.next();
186                fragmentString.append(interfaceType);
187                if (iterator.hasNext()) {
188                    fragmentString.append(',');
189                }
190            }
191            try {
192                return new URI(null, null, artifact == null? null: artifact.toString(), queryString.toString(), fragmentString.toString());
193            } catch (URISyntaxException e) {
194                IllegalArgumentException illegalArgumentException = new IllegalArgumentException();
195                illegalArgumentException.initCause(e);
196                throw illegalArgumentException;
197            }
198        }
199    
200    
201        public Artifact getArtifact() {
202            return artifact;
203        }
204    
205        public Map getName() {
206            return name;
207        }
208    
209        public Set getInterfaceTypes() {
210            return interfaceTypes;
211        }
212    
213        public String toString() {
214            return uri.toString();
215        }
216    
217        public URI toURI() {
218            return uri;
219        }
220    
221        public boolean equals(Object o) {
222            if (this == o) return true;
223            if (o == null || getClass() != o.getClass()) return false;
224    
225            final AbstractNameQuery that = (AbstractNameQuery) o;
226    
227            if (artifact != null ? !artifact.equals(that.artifact) : that.artifact != null) return false;
228            if (interfaceTypes != null ? !interfaceTypes.equals(that.interfaceTypes) : that.interfaceTypes != null)
229                return false;
230            return !(name != null ? !name.equals(that.name) : that.name != null);
231    
232        }
233    
234        public int hashCode() {
235            int result;
236            result = (artifact != null ? artifact.hashCode() : 0);
237            result = 29 * result + (name != null ? name.hashCode() : 0);
238            result = 29 * result + (interfaceTypes != null ? interfaceTypes.hashCode() : 0);
239            return result;
240        }
241    
242    
243        public boolean matches(AbstractName info, Set targetInterfaceTypes) {
244            if (!info.getName().entrySet().containsAll(name.entrySet())) {
245                return false;
246            }
247            if (!targetInterfaceTypes.containsAll(interfaceTypes)) {
248                return false;
249            }
250            if (artifact == null) {
251                return true;
252            }
253            Artifact otherArtifact = info.getArtifact();
254            return artifact.matches(otherArtifact);
255        }
256    
257        /**
258         * N.B. parameter info is supposed to be more specific than this.
259         * This is the opposite of the meaning of Artifact.matches.
260         *
261         * @param info
262         * @return if info is a more specific version of this name query.
263         */
264        public boolean matches(AbstractNameQuery info) {
265            if (!info.getName().entrySet().containsAll(name.entrySet())) {
266                return false;
267            }
268            if (!info.getInterfaceTypes().containsAll(interfaceTypes)) {
269                return false;
270            }
271            if (artifact == null) {
272                return true;
273            }
274            Artifact otherArtifact = info.getArtifact();
275            return artifact.matches(otherArtifact);
276        }
277    }