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 | 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}