View Javadoc
1   package org.apache.maven.scm.provider.clearcase.repository;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.scm.log.ScmLogger;
23  import org.apache.maven.scm.provider.ScmProviderRepository;
24  import org.apache.maven.scm.providers.clearcase.settings.Settings;
25  import org.apache.maven.scm.repository.ScmRepositoryException;
26  
27  import java.io.File;
28  import java.net.InetAddress;
29  import java.net.MalformedURLException;
30  import java.net.URI;
31  import java.net.URISyntaxException;
32  import java.net.URL;
33  import java.net.UnknownHostException;
34  import java.util.StringTokenizer;
35  
36  /**
37   * Provider Repository for ClearCase (standard, LT, UCM)
38   * <p />
39   * Url format for ClearCase and ClearCaseLT : <br />
40   * [view_name]:[configspec] or [view_name]|[configspec]
41   * <p />
42   * Url format for ClearCaseUCM : <br />
43   * [view_name]|[configspec]|[vob_name]|[stream_name] or [view_name]:[configspec]:[vob_name]:[stream_name]
44   * <p />
45   * [configspec] can be used in two different ways:
46   * <ul>
47   * <li>Path to a config spec file that is
48   * used when creating the snapshot view, e.g.
49   * "\\myserver\clearcase\configspecs\my_module.txt", or:</li>
50   * <li>A load rule that is used to automatically create a config spec, e.g. "load /MY_VOB/my/project/dir"</li>
51   * </ul>
52   * Notice that checking out from a tag is currently only supported when the second option is used.
53   *
54   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
55   */
56  public class ClearCaseScmProviderRepository
57      extends ScmProviderRepository
58  {
59      private ScmLogger logger;
60  
61      private boolean viewNameGivenByUser = false;
62  
63      private String viewName;
64  
65      /**
66       * The user-specified config spec; may be null.
67       */
68      private File configSpec;
69  
70      /**
71       * The directory to be loaded, when auto-generating the config spec.
72       */
73      private String loadDirectory;
74  
75      /**
76       * Describe the stream linked to the view. Only used with ClearCaseUCM
77       */
78      private String streamName;
79  
80      /**
81       * Describe the vob containing the stream. Only used with ClearCaseUCM
82       */
83      private String vobName;
84  
85      /**
86       * Provider configuration settings
87       */
88      private Settings settings;
89  
90      /**
91       * Describe the Element Name
92       */
93      private String elementName;
94  
95      /**
96       * Define the flag used in the clearcase-settings.xml when using ClearCaseLT
97       */
98      public static final String CLEARCASE_LT = "LT";
99  
100     /**
101      * Define the flag used in the clearcase-settings.xml when using ClearCaseUCM
102      */
103     public static final String CLEARCASE_UCM = "UCM";
104 
105     /**
106      * Define the default value from the clearcase-settings.xml when using ClearCase
107      */
108     public static final String CLEARCASE_DEFAULT = null;
109 
110     public ClearCaseScmProviderRepository( ScmLogger logger, String url, Settings settings )
111         throws ScmRepositoryException
112     {
113         this.logger = logger;
114         this.settings = settings;
115         try
116         {
117             parseUrl( url );
118         }
119         catch ( MalformedURLException e )
120         {
121             throw new ScmRepositoryException( "Illegal URL: " + url + "(" + e.getMessage() + ")" );
122         }
123         catch ( URISyntaxException e )
124         {
125             throw new ScmRepositoryException( "Illegal URL: " + url + "(" + e.getMessage() + ")" );
126         }
127         catch ( UnknownHostException e )
128         {
129             throw new ScmRepositoryException( "Illegal URL: " + url + "(" + e.getMessage() + ")" );
130         }
131     }
132 
133     private void parseUrl( String url )
134         throws MalformedURLException, URISyntaxException, UnknownHostException
135     {
136         if ( url.indexOf( '|' ) != -1 )
137         {
138             StringTokenizer tokenizer = new StringTokenizer( url, "|" );
139             fillInProperties( tokenizer );
140         }
141         else
142         {
143             StringTokenizer tokenizer = new StringTokenizer( url, ":" );
144             fillInProperties( tokenizer );
145         }
146     }
147 
148     private void fillInProperties( StringTokenizer tokenizer )
149         throws UnknownHostException, URISyntaxException, MalformedURLException
150     {
151         String configSpecString = null;
152 
153         if ( CLEARCASE_UCM.equals( settings.getClearcaseType() ) )
154         {
155             configSpecString = fillUCMProperties( tokenizer );
156         }
157         else
158         {
159             configSpecString = fillDefaultProperties( tokenizer );
160         }
161 
162         if ( !configSpecString.startsWith( "load " ) )
163         {
164             configSpec = createConfigSpecFile( configSpecString );
165             loadDirectory = null;
166         }
167         else
168         {
169             configSpec = null;
170             loadDirectory = configSpecString.substring( 5 );
171 
172         }
173     }
174 
175     private String fillDefaultProperties( StringTokenizer tokenizer )
176         throws UnknownHostException
177     {
178         int tokenNumber = tokenizer.countTokens();
179         String configSpecString;
180         if ( tokenNumber == 1 )
181         {
182             // No view name was given
183             viewName = getDefaultViewName();
184             configSpecString = tokenizer.nextToken();
185         }
186         else
187         {
188             configSpecString = checkViewName( tokenizer );
189             checkUnexpectedParameter( tokenizer, tokenNumber, 2 );
190         }
191         if ( logger.isDebugEnabled() )
192         {
193             logger.debug( "viewName = '" + viewName + "' ; configSpec = '" + configSpecString + "'" );
194         }
195         return configSpecString;
196     }
197 
198     private String fillUCMProperties( StringTokenizer tokenizer )
199         throws UnknownHostException, MalformedURLException
200     {
201         int tokenNumber = tokenizer.countTokens();
202         if ( tokenNumber <= 2 )
203         {
204             throw new MalformedURLException( "ClearCaseUCM need more parameters. Expected url format : "
205                 + "[view_name]|[configspec]|[vob_name]|[stream_name]" );
206         }
207 
208         String configSpecString;
209         if ( tokenNumber == 3 )
210         {
211             // No view name was given
212             viewName = getDefaultViewName();
213             configSpecString = tokenizer.nextToken();
214             vobName = tokenizer.nextToken();
215             streamName = tokenizer.nextToken();
216         }
217         else if ( tokenNumber == 4 )
218         {
219             String[] tokens = new String[4];
220             tokens[0] = tokenizer.nextToken();
221             tokens[1] = tokenizer.nextToken();
222             tokens[2] = tokenizer.nextToken();
223             tokens[3] = tokenizer.nextToken();
224 
225             if ( tokens[3].startsWith( "/main/" ) )
226             {
227                 viewName = getDefaultViewName();
228                 configSpecString = tokens[0];
229                 vobName = tokens[1];
230                 streamName = tokens[2];
231                 elementName = tokens[3];
232             }
233             else
234             {
235                 viewName = tokens[0];
236                 viewNameGivenByUser = true;
237                 configSpecString = tokens[1];
238                 vobName = tokens[2];
239                 streamName = tokens[3];
240             }
241         }
242         else
243         {
244             configSpecString = checkViewName( tokenizer );
245             vobName = tokenizer.nextToken();
246             streamName = tokenizer.nextToken();
247             elementName = tokenizer.nextToken();
248             checkUnexpectedParameter( tokenizer, tokenNumber, 5 );
249         }
250 
251         if ( logger.isInfoEnabled() )
252         {
253             logger.info( "viewName = '" + viewName + "' ; configSpec = '" + configSpecString + "' ; vobName = '"
254                 + vobName + "' ; streamName = '" + streamName + "' ; elementName = '" + elementName + "'" );
255         }
256 
257         return configSpecString;
258     }
259 
260     private String checkViewName( StringTokenizer tokenizer )
261         throws UnknownHostException
262     {
263         viewName = tokenizer.nextToken();
264         if ( viewName.length() > 0 )
265         {
266             viewNameGivenByUser = true;
267         }
268         else
269         {
270             viewName = getDefaultViewName();
271         }
272 
273         return tokenizer.nextToken();
274     }
275 
276     private void checkUnexpectedParameter( StringTokenizer tokenizer, int tokenNumber, int maxTokenNumber )
277     {
278         if ( tokenNumber > maxTokenNumber )
279         {
280             String unexpectedToken = tokenizer.nextToken();
281             if ( logger.isInfoEnabled() )
282             {
283                 logger.info( "The SCM URL contains unused parameter : " + unexpectedToken );
284             }
285         }
286     }
287 
288     private File createConfigSpecFile( String spec )
289         throws URISyntaxException, MalformedURLException
290     {
291         File result;
292         if ( spec.indexOf( ':' ) == -1 )
293         {
294             result = new File( spec );
295         }
296         else
297         {
298             result = new File( new URI( new URL( spec ).toString() ) );
299         }
300         return result;
301     }
302 
303     /**
304      * Default: ${hostname}-{user.name}-maven
305      *
306      * @return the default view name
307      */
308     private String getDefaultViewName()
309         throws UnknownHostException
310     {
311         String username = System.getProperty( "user.name", "nouser" );
312         String hostname = getHostName();
313         return username + "-" + hostname + "-maven";
314     }
315 
316     private String getHostName()
317         throws UnknownHostException
318     {
319         return InetAddress.getLocalHost().getHostName();
320     }
321 
322     /**
323      * Returns the name of the view. If it is defined in the scm url, then it is returned as defined there.
324      * If it is the default name, then the uniqueId is added
325      *
326      * @param uniqueId
327      * @return the name of the view
328      */
329     public String getViewName( String uniqueId )
330     {
331         String result;
332         if ( viewNameGivenByUser )
333         {
334             result = viewName;
335         }
336         else
337         {
338             result = viewName + "-" + uniqueId;
339         }
340 
341         return result;
342     }
343 
344     /**
345      * Returns the user-supplied config spec or <code>null</code> in case it
346      * should be automatically generated
347      *
348      * @return File or <code>null</code>
349      * @see #isAutoConfigSpec()
350      */
351     public File getConfigSpec()
352     {
353         return configSpec;
354     }
355 
356     /**
357      * Returns true when the config spec has not been supplied by the user, but
358      * instead should automatically be generated by the plugin
359      *
360      * @return true if auto config spec
361      */
362     public boolean isAutoConfigSpec()
363     {
364         return configSpec == null;
365     }
366 
367     /**
368      * Returns the VOB directory to be loaded when auto-generating the config
369      * spec.
370      *
371      * @return <code>null</code> when isAutoConfigSpec() returns false;
372      *         otherwise the VOB directory
373      */
374     public String getLoadDirectory()
375     {
376         return loadDirectory;
377     }
378 
379     public String getStreamName()
380     {
381         return streamName;
382     }
383 
384     public String getVobName()
385     {
386         return vobName;
387     }
388 
389     public String getElementName()
390     {
391         return elementName;
392     }
393 
394     public boolean hasElements()
395     {
396         if ( elementName == null )
397         {
398             return false;
399         }
400 
401         return true;
402     }
403 }