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 */ 056public class ClearCaseScmProviderRepository 057 extends ScmProviderRepository 058{ 059 private ScmLogger logger; 060 061 private boolean viewNameGivenByUser = false; 062 063 private String viewName; 064 065 /** 066 * The user-specified config spec; may be null. 067 */ 068 private File configSpec; 069 070 /** 071 * The directory to be loaded, when auto-generating the config spec. 072 */ 073 private String loadDirectory; 074 075 /** 076 * Describe the stream linked to the view. Only used with ClearCaseUCM 077 */ 078 private String streamName; 079 080 /** 081 * Describe the vob containing the stream. Only used with ClearCaseUCM 082 */ 083 private String vobName; 084 085 /** 086 * Provider configuration settings 087 */ 088 private Settings settings; 089 090 /** 091 * Describe the Element Name 092 */ 093 private String elementName; 094 095 /** 096 * Define the flag used in the clearcase-settings.xml when using ClearCaseLT 097 */ 098 public static final String CLEARCASE_LT = "LT"; 099 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}