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&oslash;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    }