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 | UnknownHostException | URISyntaxException e )
120         {
121             throw new ScmRepositoryException( "Illegal URL: " + url + "(" + e.getMessage() + ")" );
122         }
123     }
124 
125     private void parseUrl( String url )
126         throws MalformedURLException, URISyntaxException, UnknownHostException
127     {
128         if ( url.indexOf( '|' ) != -1 )
129         {
130             StringTokenizer tokenizer = new StringTokenizer( url, "|" );
131             fillInProperties( tokenizer );
132         }
133         else
134         {
135             StringTokenizer tokenizer = new StringTokenizer( url, ":" );
136             fillInProperties( tokenizer );
137         }
138     }
139 
140     private void fillInProperties( StringTokenizer tokenizer )
141         throws UnknownHostException, URISyntaxException, MalformedURLException
142     {
143         String configSpecString = null;
144 
145         if ( CLEARCASE_UCM.equals( settings.getClearcaseType() ) )
146         {
147             configSpecString = fillUCMProperties( tokenizer );
148         }
149         else
150         {
151             configSpecString = fillDefaultProperties( tokenizer );
152         }
153 
154         if ( !configSpecString.startsWith( "load " ) )
155         {
156             configSpec = createConfigSpecFile( configSpecString );
157             loadDirectory = null;
158         }
159         else
160         {
161             configSpec = null;
162             loadDirectory = configSpecString.substring( 5 );
163 
164         }
165     }
166 
167     private String fillDefaultProperties( StringTokenizer tokenizer )
168         throws UnknownHostException
169     {
170         int tokenNumber = tokenizer.countTokens();
171         String configSpecString;
172         if ( tokenNumber == 1 )
173         {
174             // No view name was given
175             viewName = getDefaultViewName();
176             configSpecString = tokenizer.nextToken();
177         }
178         else
179         {
180             configSpecString = checkViewName( tokenizer );
181             checkUnexpectedParameter( tokenizer, tokenNumber, 2 );
182         }
183         if ( logger.isDebugEnabled() )
184         {
185             logger.debug( "viewName = '" + viewName + "' ; configSpec = '" + configSpecString + "'" );
186         }
187         return configSpecString;
188     }
189 
190     private String fillUCMProperties( StringTokenizer tokenizer )
191         throws UnknownHostException, MalformedURLException
192     {
193         int tokenNumber = tokenizer.countTokens();
194         if ( tokenNumber <= 2 )
195         {
196             throw new MalformedURLException( "ClearCaseUCM need more parameters. Expected url format : "
197                 + "[view_name]|[configspec]|[vob_name]|[stream_name]" );
198         }
199 
200         String configSpecString;
201         if ( tokenNumber == 3 )
202         {
203             // No view name was given
204             viewName = getDefaultViewName();
205             configSpecString = tokenizer.nextToken();
206             vobName = tokenizer.nextToken();
207             streamName = tokenizer.nextToken();
208         }
209         else if ( tokenNumber == 4 )
210         {
211             String[] tokens = new String[4];
212             tokens[0] = tokenizer.nextToken();
213             tokens[1] = tokenizer.nextToken();
214             tokens[2] = tokenizer.nextToken();
215             tokens[3] = tokenizer.nextToken();
216 
217             if ( tokens[3].startsWith( "/main/" ) )
218             {
219                 viewName = getDefaultViewName();
220                 configSpecString = tokens[0];
221                 vobName = tokens[1];
222                 streamName = tokens[2];
223                 elementName = tokens[3];
224             }
225             else
226             {
227                 viewName = tokens[0];
228                 viewNameGivenByUser = true;
229                 configSpecString = tokens[1];
230                 vobName = tokens[2];
231                 streamName = tokens[3];
232             }
233         }
234         else
235         {
236             configSpecString = checkViewName( tokenizer );
237             vobName = tokenizer.nextToken();
238             streamName = tokenizer.nextToken();
239             elementName = tokenizer.nextToken();
240             checkUnexpectedParameter( tokenizer, tokenNumber, 5 );
241         }
242 
243         if ( logger.isInfoEnabled() )
244         {
245             logger.info( "viewName = '" + viewName + "' ; configSpec = '" + configSpecString + "' ; vobName = '"
246                 + vobName + "' ; streamName = '" + streamName + "' ; elementName = '" + elementName + "'" );
247         }
248 
249         return configSpecString;
250     }
251 
252     private String checkViewName( StringTokenizer tokenizer )
253         throws UnknownHostException
254     {
255         viewName = tokenizer.nextToken();
256         if ( viewName.length() > 0 )
257         {
258             viewNameGivenByUser = true;
259         }
260         else
261         {
262             viewName = getDefaultViewName();
263         }
264 
265         return tokenizer.nextToken();
266     }
267 
268     private void checkUnexpectedParameter( StringTokenizer tokenizer, int tokenNumber, int maxTokenNumber )
269     {
270         if ( tokenNumber > maxTokenNumber )
271         {
272             String unexpectedToken = tokenizer.nextToken();
273             if ( logger.isInfoEnabled() )
274             {
275                 logger.info( "The SCM URL contains unused parameter : " + unexpectedToken );
276             }
277         }
278     }
279 
280     private File createConfigSpecFile( String spec )
281         throws URISyntaxException, MalformedURLException
282     {
283         File result;
284         if ( spec.indexOf( ':' ) == -1 )
285         {
286             result = new File( spec );
287         }
288         else
289         {
290             result = new File( new URI( new URL( spec ).toString() ) );
291         }
292         return result;
293     }
294 
295     /**
296      * Default: ${hostname}-{user.name}-maven
297      *
298      * @return the default view name
299      */
300     private String getDefaultViewName()
301         throws UnknownHostException
302     {
303         String username = System.getProperty( "user.name", "nouser" );
304         String hostname = getHostName();
305         return username + "-" + hostname + "-maven";
306     }
307 
308     private String getHostName()
309         throws UnknownHostException
310     {
311         return InetAddress.getLocalHost().getHostName();
312     }
313 
314     /**
315      * Returns the name of the view. If it is defined in the scm url, then it is returned as defined there.
316      * If it is the default name, then the uniqueId is added
317      *
318      * @param uniqueId
319      * @return the name of the view
320      */
321     public String getViewName( String uniqueId )
322     {
323         String result;
324         if ( viewNameGivenByUser )
325         {
326             result = viewName;
327         }
328         else
329         {
330             result = viewName + "-" + uniqueId;
331         }
332 
333         return result;
334     }
335 
336     /**
337      * Returns the user-supplied config spec or <code>null</code> in case it
338      * should be automatically generated
339      *
340      * @return File or <code>null</code>
341      * @see #isAutoConfigSpec()
342      */
343     public File getConfigSpec()
344     {
345         return configSpec;
346     }
347 
348     /**
349      * Returns true when the config spec has not been supplied by the user, but
350      * instead should automatically be generated by the plugin
351      *
352      * @return true if auto config spec
353      */
354     public boolean isAutoConfigSpec()
355     {
356         return configSpec == null;
357     }
358 
359     /**
360      * Returns the VOB directory to be loaded when auto-generating the config
361      * spec.
362      *
363      * @return <code>null</code> when isAutoConfigSpec() returns false;
364      *         otherwise the VOB directory
365      */
366     public String getLoadDirectory()
367     {
368         return loadDirectory;
369     }
370 
371     public String getStreamName()
372     {
373         return streamName;
374     }
375 
376     public String getVobName()
377     {
378         return vobName;
379     }
380 
381     public String getElementName()
382     {
383         return elementName;
384     }
385 
386     public boolean hasElements()
387     {
388         if ( elementName == null )
389         {
390             return false;
391         }
392 
393         return true;
394     }
395 }