001 package org.apache.maven.scm.provider.clearcase.repository;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import org.apache.maven.scm.log.ScmLogger;
023 import org.apache.maven.scm.provider.ScmProviderRepository;
024 import org.apache.maven.scm.providers.clearcase.settings.Settings;
025 import org.apache.maven.scm.repository.ScmRepositoryException;
026
027 import java.io.File;
028 import java.net.InetAddress;
029 import java.net.MalformedURLException;
030 import java.net.URI;
031 import java.net.URISyntaxException;
032 import java.net.URL;
033 import java.net.UnknownHostException;
034 import java.util.StringTokenizer;
035
036 /**
037 * Provider Repository for ClearCase (standard, LT, UCM)
038 * <p />
039 * Url format for ClearCase and ClearCaseLT : <br />
040 * [view_name]:[configspec] or [view_name]|[configspec]
041 * <p />
042 * Url format for ClearCaseUCM : <br />
043 * [view_name]|[configspec]|[vob_name]|[stream_name] or [view_name]:[configspec]:[vob_name]:[stream_name]
044 * <p />
045 * [configspec] can be used in two different ways:
046 * <ul>
047 * <li>Path to a config spec file that is
048 * used when creating the snapshot view, e.g.
049 * "\\myserver\clearcase\configspecs\my_module.txt", or:</li>
050 * <li>A load rule that is used to automatically create a config spec, e.g. "load /MY_VOB/my/project/dir"</li>
051 * </ul>
052 * Notice that checking out from a tag is currently only supported when the second option is used.
053 *
054 * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
055 * @version $Id: ClearCaseScmProviderRepository.java 483105 2006-12-06 15:07:54Z
056 * evenisse $
057 */
058 public class ClearCaseScmProviderRepository
059 extends ScmProviderRepository
060 {
061 private ScmLogger logger;
062
063 private boolean viewNameGivenByUser = false;
064
065 private String viewName;
066
067 /**
068 * The user-specified config spec; may be null.
069 */
070 private File configSpec;
071
072 /**
073 * The directory to be loaded, when auto-generating the config spec.
074 */
075 private String loadDirectory;
076
077 /**
078 * Describe the stream linked to the view. Only used with ClearCaseUCM
079 */
080 private String streamName;
081
082 /**
083 * Describe the vob containing the stream. Only used with ClearCaseUCM
084 */
085 private String vobName;
086
087 /**
088 * Provider configuration settings
089 */
090 private Settings settings;
091
092 /**
093 * Describe the Element Name
094 */
095 private String elementName;
096
097 /**
098 * Define the flag used in the clearcase-settings.xml when using ClearCaseLT
099 */
100 public static final String CLEARCASE_LT = "LT";
101
102 /**
103 * Define the flag used in the clearcase-settings.xml when using ClearCaseUCM
104 */
105 public static final String CLEARCASE_UCM = "UCM";
106
107 /**
108 * Define the default value from the clearcase-settings.xml when using ClearCase
109 */
110 public static final String CLEARCASE_DEFAULT = null;
111
112 public ClearCaseScmProviderRepository( ScmLogger logger, String url, Settings settings )
113 throws ScmRepositoryException
114 {
115 this.logger = logger;
116 this.settings = settings;
117 try
118 {
119 parseUrl( url );
120 }
121 catch ( MalformedURLException e )
122 {
123 throw new ScmRepositoryException( "Illegal URL: " + url + "(" + e.getMessage() + ")" );
124 }
125 catch ( URISyntaxException e )
126 {
127 throw new ScmRepositoryException( "Illegal URL: " + url + "(" + e.getMessage() + ")" );
128 }
129 catch ( UnknownHostException e )
130 {
131 throw new ScmRepositoryException( "Illegal URL: " + url + "(" + e.getMessage() + ")" );
132 }
133 }
134
135 private void parseUrl( String url )
136 throws MalformedURLException, URISyntaxException, UnknownHostException
137 {
138 if ( url.indexOf( '|' ) != -1 )
139 {
140 StringTokenizer tokenizer = new StringTokenizer( url, "|" );
141 fillInProperties( tokenizer );
142 }
143 else
144 {
145 StringTokenizer tokenizer = new StringTokenizer( url, ":" );
146 fillInProperties( tokenizer );
147 }
148 }
149
150 private void fillInProperties( StringTokenizer tokenizer )
151 throws UnknownHostException, URISyntaxException, MalformedURLException
152 {
153 String configSpecString = null;
154
155 if ( CLEARCASE_UCM.equals( settings.getClearcaseType() ) )
156 {
157 configSpecString = fillUCMProperties( tokenizer );
158 }
159 else
160 {
161 configSpecString = fillDefaultProperties( tokenizer );
162 }
163
164 if ( !configSpecString.startsWith( "load " ) )
165 {
166 configSpec = createConfigSpecFile( configSpecString );
167 loadDirectory = null;
168 }
169 else
170 {
171 configSpec = null;
172 loadDirectory = configSpecString.substring( 5 );
173
174 }
175 }
176
177 private String fillDefaultProperties( StringTokenizer tokenizer )
178 throws UnknownHostException
179 {
180 int tokenNumber = tokenizer.countTokens();
181 String configSpecString;
182 if ( tokenNumber == 1 )
183 {
184 // No view name was given
185 viewName = getDefaultViewName();
186 configSpecString = tokenizer.nextToken();
187 }
188 else
189 {
190 configSpecString = checkViewName( tokenizer );
191 checkUnexpectedParameter( tokenizer, tokenNumber, 2 );
192 }
193 if ( logger.isDebugEnabled() )
194 {
195 logger.debug( "viewName = '" + viewName + "' ; configSpec = '" + configSpecString + "'" );
196 }
197 return configSpecString;
198 }
199
200 private String fillUCMProperties( StringTokenizer tokenizer )
201 throws UnknownHostException, MalformedURLException
202 {
203 int tokenNumber = tokenizer.countTokens();
204 if ( tokenNumber <= 2 )
205 {
206 throw new MalformedURLException( "ClearCaseUCM need more parameters. Expected url format : "
207 + "[view_name]|[configspec]|[vob_name]|[stream_name]" );
208 }
209
210 String configSpecString;
211 if ( tokenNumber == 3 )
212 {
213 // No view name was given
214 viewName = getDefaultViewName();
215 configSpecString = tokenizer.nextToken();
216 vobName = tokenizer.nextToken();
217 streamName = tokenizer.nextToken();
218 }
219 else if ( tokenNumber == 4 )
220 {
221 String[] tokens = new String[4];
222 tokens[0] = tokenizer.nextToken();
223 tokens[1] = tokenizer.nextToken();
224 tokens[2] = tokenizer.nextToken();
225 tokens[3] = tokenizer.nextToken();
226
227 if ( tokens[3].startsWith( "/main/" ) )
228 {
229 viewName = getDefaultViewName();
230 configSpecString = tokens[0];
231 vobName = tokens[1];
232 streamName = tokens[2];
233 elementName = tokens[3];
234 }
235 else
236 {
237 viewName = tokens[0];
238 viewNameGivenByUser = true;
239 configSpecString = tokens[1];
240 vobName = tokens[2];
241 streamName = tokens[3];
242 }
243 }
244 else
245 {
246 configSpecString = checkViewName( tokenizer );
247 vobName = tokenizer.nextToken();
248 streamName = tokenizer.nextToken();
249 elementName = tokenizer.nextToken();
250 checkUnexpectedParameter( tokenizer, tokenNumber, 5 );
251 }
252
253 if ( logger.isInfoEnabled() )
254 {
255 logger.info( "viewName = '" + viewName + "' ; configSpec = '" + configSpecString + "' ; vobName = '"
256 + vobName + "' ; streamName = '" + streamName + "' ; elementName = '" + elementName + "'" );
257 }
258
259 return configSpecString;
260 }
261
262 private String checkViewName( StringTokenizer tokenizer )
263 throws UnknownHostException
264 {
265 viewName = tokenizer.nextToken();
266 if ( viewName.length() > 0 )
267 {
268 viewNameGivenByUser = true;
269 }
270 else
271 {
272 viewName = getDefaultViewName();
273 }
274
275 return tokenizer.nextToken();
276 }
277
278 private void checkUnexpectedParameter( StringTokenizer tokenizer, int tokenNumber, int maxTokenNumber )
279 {
280 if ( tokenNumber > maxTokenNumber )
281 {
282 String unexpectedToken = tokenizer.nextToken();
283 if ( logger.isInfoEnabled() )
284 {
285 logger.info( "The SCM URL contains unused parameter : " + unexpectedToken );
286 }
287 }
288 }
289
290 private File createConfigSpecFile( String spec )
291 throws URISyntaxException, MalformedURLException
292 {
293 File result;
294 if ( spec.indexOf( ':' ) == -1 )
295 {
296 result = new File( spec );
297 }
298 else
299 {
300 result = new File( new URI( new URL( spec ).toString() ) );
301 }
302 return result;
303 }
304
305 /**
306 * Default: ${hostname}-{user.name}-maven
307 *
308 * @return the default view name
309 */
310 private String getDefaultViewName()
311 throws UnknownHostException
312 {
313 String username = System.getProperty( "user.name", "nouser" );
314 String hostname = getHostName();
315 return username + "-" + hostname + "-maven";
316 }
317
318 private String getHostName()
319 throws UnknownHostException
320 {
321 return InetAddress.getLocalHost().getHostName();
322 }
323
324 /**
325 * Returns the name of the view. If it is defined in the scm url, then it is returned as defined there.
326 * If it is the default name, then the uniqueId is added
327 *
328 * @param uniqueId
329 * @return the name of the view
330 */
331 public String getViewName( String uniqueId )
332 {
333 String result;
334 if ( viewNameGivenByUser )
335 {
336 result = viewName;
337 }
338 else
339 {
340 result = viewName + "-" + uniqueId;
341 }
342
343 return result;
344 }
345
346 /**
347 * Returns the user-supplied config spec or <code>null</code> in case it
348 * should be automatically generated
349 *
350 * @return File or <code>null</code>
351 * @see #isAutoConfigSpec()
352 */
353 public File getConfigSpec()
354 {
355 return configSpec;
356 }
357
358 /**
359 * Returns true when the config spec has not been supplied by the user, but
360 * instead should automatically be generated by the plugin
361 *
362 * @return true if auto config spec
363 */
364 public boolean isAutoConfigSpec()
365 {
366 return configSpec == null;
367 }
368
369 /**
370 * Returns the VOB directory to be loaded when auto-generating the config
371 * spec.
372 *
373 * @return <code>null</code> when isAutoConfigSpec() returns false;
374 * otherwise the VOB directory
375 */
376 public String getLoadDirectory()
377 {
378 return loadDirectory;
379 }
380
381 public String getStreamName()
382 {
383 return streamName;
384 }
385
386 public String getVobName()
387 {
388 return vobName;
389 }
390
391 public String getElementName()
392 {
393 return elementName;
394 }
395
396 public boolean hasElements()
397 {
398 if ( elementName == null )
399 {
400 return false;
401 }
402
403 return true;
404 }
405 }