View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.websocket.server.pathmap;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.List;
26  
27  import org.eclipse.jetty.util.annotation.ManagedAttribute;
28  import org.eclipse.jetty.util.annotation.ManagedObject;
29  import org.eclipse.jetty.util.component.ContainerLifeCycle;
30  import org.eclipse.jetty.util.component.Dumpable;
31  import org.eclipse.jetty.util.log.Log;
32  import org.eclipse.jetty.util.log.Logger;
33  import org.eclipse.jetty.websocket.server.pathmap.PathMappings.MappedResource;
34  
35  /**
36   * Path Mappings of PathSpec to Resource.
37   * <p>
38   * Sorted into search order upon entry into the Set
39   * 
40   * @param <E> the type of mapping endpoint
41   */
42  @ManagedObject("Path Mappings")
43  public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
44  {
45      @ManagedObject("Mapped Resource")
46      public static class MappedResource<E> implements Comparable<MappedResource<E>>
47      {
48          private final PathSpec pathSpec;
49          private final E resource;
50  
51          public MappedResource(PathSpec pathSpec, E resource)
52          {
53              this.pathSpec = pathSpec;
54              this.resource = resource;
55          }
56  
57          /**
58           * Comparison is based solely on the pathSpec
59           */
60          @Override
61          public int compareTo(MappedResource<E> other)
62          {
63              return this.pathSpec.compareTo(other.pathSpec);
64          }
65  
66          @Override
67          public boolean equals(Object obj)
68          {
69              if (this == obj)
70              {
71                  return true;
72              }
73              if (obj == null)
74              {
75                  return false;
76              }
77              if (getClass() != obj.getClass())
78              {
79                  return false;
80              }
81              MappedResource<?> other = (MappedResource<?>)obj;
82              if (pathSpec == null)
83              {
84                  if (other.pathSpec != null)
85                  {
86                      return false;
87                  }
88              }
89              else if (!pathSpec.equals(other.pathSpec))
90              {
91                  return false;
92              }
93              return true;
94          }
95  
96          @ManagedAttribute(value = "path spec", readonly = true)
97          public PathSpec getPathSpec()
98          {
99              return pathSpec;
100         }
101 
102         @ManagedAttribute(value = "resource", readonly = true)
103         public E getResource()
104         {
105             return resource;
106         }
107 
108         @Override
109         public int hashCode()
110         {
111             final int prime = 31;
112             int result = 1;
113             result = (prime * result) + ((pathSpec == null)?0:pathSpec.hashCode());
114             return result;
115         }
116 
117         @Override
118         public String toString()
119         {
120             return String.format("MappedResource[pathSpec=%s,resource=%s]",pathSpec,resource);
121         }
122     }
123 
124     private static final Logger LOG = Log.getLogger(PathMappings.class);
125     private List<MappedResource<E>> mappings = new ArrayList<MappedResource<E>>();
126     private MappedResource<E> defaultResource = null;
127 
128     @Override
129     public String dump()
130     {
131         return ContainerLifeCycle.dump(this);
132     }
133 
134     @Override
135     public void dump(Appendable out, String indent) throws IOException
136     {
137         ContainerLifeCycle.dump(out,indent,mappings);
138     }
139 
140     @ManagedAttribute(value = "mappings", readonly = true)
141     public List<MappedResource<E>> getMappings()
142     {
143         return mappings;
144     }
145     
146     public void reset()
147     {
148         mappings.clear();
149     }
150 
151     public MappedResource<E> getMatch(String path)
152     {
153         int len = mappings.size();
154         for (int i = 0; i < len; i++)
155         {
156             MappedResource<E> mr = mappings.get(i);
157             if (mr.getPathSpec().matches(path))
158             {
159                 return mr;
160             }
161         }
162         return defaultResource;
163     }
164 
165     @Override
166     public Iterator<MappedResource<E>> iterator()
167     {
168         return mappings.iterator();
169     }
170 
171     public void put(PathSpec pathSpec, E resource)
172     {
173         MappedResource<E> entry = new MappedResource<>(pathSpec,resource);
174         if (pathSpec.group == PathSpecGroup.DEFAULT)
175         {
176             defaultResource = entry;
177         }
178         // TODO: warning on replacement of existing mapping?
179         mappings.add(entry);
180         if (LOG.isDebugEnabled())
181             LOG.debug("Added {} to {}",entry,this);
182         Collections.sort(mappings);
183     }
184 
185     @Override
186     public String toString()
187     {
188         return String.format("%s[size=%d]",this.getClass().getSimpleName(),mappings.size());
189     }
190 }