View Javadoc

1   package org.alfresco.maven.plugin.amp.util;
2   
3   import java.io.IOException;
4   import java.util.HashMap;
5   import java.util.Iterator;
6   import java.util.Map;
7   import java.util.Set;
8   
9   /***
10   * Represents the structure of a web application composed of multiple
11   * overlays. Each overlay is registered within this structure with the
12   * set of files it holds.
13   * <p/>
14   * Note that this structure is persisted to disk at each invocation to
15   * store wich owner holds which path (file).
16   *
17   * @author Stephane Nicoll
18   */
19  public class AmpStructure
20  {
21  
22      private Map registeredFiles;
23  
24      private transient PathSet allFiles = new PathSet();
25  
26      private transient AmpStructure cache;
27  
28      /***
29       * Creates a new empty instance.
30       */
31      public AmpStructure()
32      {
33          this.registeredFiles = new HashMap();
34          this.cache = null;
35      }
36  
37      /***
38       * Creates a new instance with the specified cache.
39       *
40       * @param cache the cache
41       */
42      public AmpStructure( AmpStructure cache )
43      {
44          this.registeredFiles = new HashMap();
45          if ( cache == null )
46          {
47              this.cache = new AmpStructure();
48          }
49          else
50          {
51              this.cache = cache;
52          }
53      }
54  
55  
56      /***
57       * Specify if the specified <tt>path</tt> is registered or not.
58       *
59       * @param path the relative path from the webapp root directory
60       * @return true if the path is registered, false otherwise
61       */
62      public boolean isRegistered( String path )
63      {
64          return getFullStructure().contains( path );
65  
66      }
67  
68      /***
69       * Registers the specified path for the specified owner. Returns <tt>true</tt>
70       * if the path is not already registered, <tt>false</tt> otherwise.
71       *
72       * @param id   the owner of the path
73       * @param path the relative path from the webapp root directory
74       * @return true if the file was registered successfully
75       */
76      public boolean registerFile( String id, String path )
77      {
78          if ( !isRegistered( path ) )
79          {
80              doRegister( id, path );
81              return true;
82          }
83          else
84          {
85              return false;
86          }
87      }
88  
89      /***
90       * Registers the specified path for the specified owner. Invokes
91       * the <tt>callback</tt> with the result of the registration.
92       *
93       * @param id       the owner of the path
94       * @param path     the relative path from the webapp root directory
95       * @param callback the callback to invoke with the result of the registration
96       * @throws IOException if the callback invocation throws an IOException
97       */
98      public void registerFile( String id, String path, RegistrationCallback callback )
99          throws IOException
100     {
101 
102         // If the file is already in the current structure, rejects it with the current owner
103         if ( isRegistered( path ) )
104         {
105             callback.refused( id, path, getOwner( path ) );
106         }
107         else
108         {
109             doRegister( id, path );
110             // This is a new file
111             if ( cache.getOwner( path ) == null )
112             {
113                 callback.registered( id, path );
114 
115             } // The file already belonged to this owner
116             else if ( cache.getOwner( path ).equals( id ) )
117             {
118                 callback.alreadyRegistered( id, path );
119             } // The file belongs to another owner and it's known currently
120             else if ( getOwners().contains( cache.getOwner( path ) ) )
121             {
122                 callback.superseded( id, path, cache.getOwner( path ) );
123             } // The file belongs to another owner and it's unknown
124             else
125             {
126                 callback.supersededUnknownOwner( id, path, cache.getOwner( path ) );
127             }
128         }
129     }
130 
131     /***
132      * Returns the owner of the specified <tt>path</tt>. If the file is not
133      * registered, returns <tt>null</tt>
134      *
135      * @param path the relative path from the webapp root directory
136      * @return the owner or <tt>null</tt>.
137      */
138     public String getOwner( String path )
139     {
140         if ( !isRegistered( path ) )
141         {
142             return null;
143         }
144         else
145         {
146             final Iterator it = registeredFiles.keySet().iterator();
147             while ( it.hasNext() )
148             {
149                 final String owner = (String) it.next();
150                 final PathSet structure = getStructure( owner );
151                 if ( structure.contains( path ) )
152                 {
153                     return owner;
154                 }
155 
156             }
157             throw new IllegalStateException(
158                 "Should not happen, path[" + path + "] is flagged as being registered but was not found." );
159         }
160 
161     }
162 
163     /***
164      * Returns the owners. Note that this the returned {@link Set} may be
165      * inconsistent since it represents a persistent cache accross multiple
166      * invocations.
167      * <p/>
168      * For instance, if an overlay was removed in this execution, it will be
169      * still be there till the cache is cleaned. This happens when the clean
170      * mojo is invoked.
171      *
172      * @return the list of owners
173      */
174     public Set getOwners()
175     {
176         return registeredFiles.keySet();
177     }
178 
179     /***
180      * Returns all paths that have been registered so far.
181      *
182      * @return all registered path
183      */
184     public PathSet getFullStructure()
185     {
186         return allFiles;
187     }
188 
189     /***
190      * Returns the list of registered files for the specified owner.
191      *
192      * @param id the owner
193      * @return the list of files registered for that owner
194      */
195     public PathSet getStructure( String id )
196     {
197         PathSet pathSet = (PathSet) registeredFiles.get( id );
198         if ( pathSet == null )
199         {
200             pathSet = new PathSet();
201             registeredFiles.put( id, pathSet );
202         }
203         return pathSet;
204     }
205 
206     private void doRegister( String id, String path )
207     {
208         getFullStructure().add( path );
209         getStructure( id ).add( path );
210     }
211 
212     private Object readResolve()
213     {
214         // the full structure should be resolved so let's rebuild it
215         this.allFiles = new PathSet();
216         final Iterator it = registeredFiles.values().iterator();
217         while ( it.hasNext() )
218         {
219             PathSet pathSet = (PathSet) it.next();
220             this.allFiles.addAll( pathSet );
221         }
222         return this;
223     }
224 
225     /***
226      * Callback interfce to handle events related to filepath registration in
227      * the webapp.
228      */
229     public interface RegistrationCallback
230     {
231 
232 
233         /***
234          * Called if the <tt>targetFilename</tt> for the specified <tt>ownerId</tt>
235          * has been registered successfully.
236          * <p/>
237          * This means that the <tt>targetFilename</tt> was unknown and has been
238          * registered successfully.
239          *
240          * @param ownerId        the ownerId
241          * @param targetFilename the relative path according to the root of the webapp
242          * @throws IOException if an error occured while handling this event
243          */
244         void registered( String ownerId, String targetFilename )
245             throws IOException;
246 
247         /***
248          * Called if the <tt>targetFilename</tt> for the specified <tt>ownerId</tt>
249          * has already been registered.
250          * <p/>
251          * This means that the <tt>targetFilename</tt> was known and belongs to the
252          * specified owner.
253          *
254          * @param ownerId        the ownerId
255          * @param targetFilename the relative path according to the root of the webapp
256          * @throws IOException if an error occured while handling this event
257          */
258         void alreadyRegistered( String ownerId, String targetFilename )
259             throws IOException;
260 
261         /***
262          * Called if the registration of the <tt>targetFilename</tt> for the
263          * specified <tt>ownerId</tt> has been refused since the path already
264          * belongs to the <tt>actualOwnerId</tt>.
265          * <p/>
266          * This means that the <tt>targetFilename</tt> was known and does not
267          * belong to the specified owner.
268          *
269          * @param ownerId        the ownerId
270          * @param targetFilename the relative path according to the root of the webapp
271          * @param actualOwnerId  the actual owner
272          * @throws IOException if an error occured while handling this event
273          */
274         void refused( String ownerId, String targetFilename, String actualOwnerId )
275             throws IOException;
276 
277         /***
278          * Called if the <tt>targetFilename</tt> for the specified <tt>ownerId</tt>
279          * has been registered successfully by superseding a <tt>deprecatedOwnerId</tt>,
280          * that is the previous owner of the file.
281          * <p/>
282          * This means that the <tt>targetFilename</tt> was known but for another
283          * owner. This usually happens after a project's configuration change. As a
284          * result, the file has been registered successfully to the new owner.
285          *
286          * @param ownerId           the ownerId
287          * @param targetFilename    the relative path according to the root of the webapp
288          * @param deprecatedOwnerId the previous owner that does not exist anymore
289          * @throws IOException if an error occured while handling this event
290          */
291         void superseded( String ownerId, String targetFilename, String deprecatedOwnerId )
292             throws IOException;
293 
294         /***
295          * Called if the <tt>targetFilename</tt> for the specified <tt>ownerId</tt>
296          * has been registered successfully by superseding a <tt>unknownOwnerId</tt>,
297          * that is an owner that does not exist anymore in the current project.
298          * <p/>
299          * This means that the <tt>targetFilename</tt> was known but for an owner that
300          * does not exist anymore. Hence the file has been registered successfully to
301          * the new owner.
302          *
303          * @param ownerId        the ownerId
304          * @param targetFilename the relative path according to the root of the webapp
305          * @param unknownOwnerId the previous owner that does not exist anymore
306          * @throws IOException if an error occured while handling this event
307          */
308         void supersededUnknownOwner( String ownerId, String targetFilename, String unknownOwnerId )
309             throws IOException;
310 
311     }
312 }