001package 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 022import org.apache.maven.scm.log.ScmLogger; 023import org.apache.maven.scm.provider.ScmProviderRepository; 024import org.apache.maven.scm.providers.clearcase.settings.Settings; 025import org.apache.maven.scm.repository.ScmRepositoryException; 026 027import java.io.File; 028import java.net.InetAddress; 029import java.net.MalformedURLException; 030import java.net.URI; 031import java.net.URISyntaxException; 032import java.net.URL; 033import java.net.UnknownHostException; 034import 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 */ 058public 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}