Subversion Repository Public Repository

litesoft

Diff Revisions 950 vs 959 for /trunk/Java/ScarPlus/src/com/esotericsoftware/scar/ProjectParameters.java

Diff revisions: vs.
  @@ -1,883 +1,703 @@
1 - package com.esotericsoftware.scar;
2 -
3 - import com.esotericsoftware.filesystem.*;
4 - import com.esotericsoftware.scar.support.*;
5 - import com.esotericsoftware.utils.*;
6 -
7 - import java.io.*;
8 - import java.util.*;
9 - import java.util.regex.*;
10 -
11 - import static com.esotericsoftware.scar.support.Parameter.*;
12 -
13 - @SuppressWarnings({"UnusedDeclaration"})
14 - public class ProjectParameters extends FileUtil
15 - {
16 - public static final Parameter NAME = def( "name", Form.STRING, "The name of the project. Used to name the JAR.", //
17 - "Default:\n" + //
18 - " The name of the directory containing the project YAML file, or\n" + //
19 - " the name of the YAML file if it is not 'build'." );
20 -
21 - public static final Parameter VERSION = def( "version", Form.STRING, "The version of the project. If available, used to name the 'default' named JAR." );
22 -
23 - public static final Parameter MAIN = def( "main", Form.STRING, "Name of the main class." );
24 -
25 - public static final Parameter TARGET = def( "target", Form.STRING, "The directory to output build artifacts.", //
26 - "Default: The directory containing the project YAML file, plus 'build'." );
27 -
28 - public static final Parameter DEPENDENCIES =
29 - def( "dependencies", Form.STRING_LIST, "Relative or absolute path(s) to dependency project directories or YAML files." );
30 -
31 - public static final Parameter COMPILECLASSPATH =
32 - def( "compileclasspath", Form.PATHS, "Wildcard patterns for the file(s) to include on the 'compile' classpath.", //
33 - "Note: automatically includes the ClassPath(s)." );
34 -
35 - public static final Parameter CLASSPATH =
36 - def( "classpath", Form.PATHS, "Wildcard patterns for the file(s) to include on the classpath (both, compile & runtime/deployment).", //
37 - "Default: 'lib|**.jar'." );
38 -
39 - public static final Parameter SOURCE = def( "source", Form.PATHS, "Wildcard patterns for the Java file(s) to compile.", //
40 - "Default: 'src|**.java' or 'src/main/java|**.java'." );
41 -
42 - public static final Parameter RESOURCES = def( "resources", Form.PATHS, "Wildcard patterns for the file(s) to include in the JAR.", //
43 - "Default: 'resources' or 'src/main/resources'." );
44 -
45 - public static final Parameter JAR =
46 - def( "jar", Form.STRING, "JAR name w/ optional path for the JAR ('.jar' added to the end if does not end with 'jar', case insensitive).", //
47 - "Default: '$target$[-$version$]'." );
48 -
49 - public static final Parameter DIST = def( "dist", Form.PATHS, "Wildcard patterns for the file(s) to include in the distribution, outside the JAR.", //
50 - "Default: 'war' (if there)." );
51 -
52 - // ------------------------------- Packaging Options, these are mutually exclusive ---------------------------------
53 -
54 - public static final Parameter PHONEGAPDIR = def( "phonegapdir", Form.STRING, "Directory path to bring together all the files needed for a PgoneGap app", //
55 - "('dist', for this project and all dependencies, recursively)." );
56 -
57 - public static final Parameter APPDIR = def( "appdir", Form.STRING, "Directory path to bring together all files (both JARs and 'dist', for this project", //
58 - "and all dependencies, recursively) the application needs to be run from JAR files." );
59 -
60 - public static final Parameter ONEJAR =
61 - def( "onejar", Form.STRING, "JAR name w/ optional path for the JAR ('.jar' added to the end if does not end with 'jar', case insensitive),", //
62 - "that all 'exploded' dependendend JARs and dist files will be JAR'd into (this should make a single JAR application)." );
63 -
64 - public static final Parameter WAR = def( "war", Form.STRING,
65 - "Target WAR directory or WAR name (if ends w/ '.war'), produces a war directory (as specified, " +
66 - "or a default one if a '.war' is requested)",
67 - //
68 - "then if a '.war' is requested, packages the war directory into the specified '.war' file." );
69 -
70 - // ------------------------------------------------ GWT Parameters -------------------------------------------------
71 -
72 - public static final Parameter GWT = def( "GWT", Form.STRING, "The 'package' Name of the 'root' '.gwt.xml' file. e.g. 'org.sample.MyGwtApplication'" );
73 -
74 - public static final Parameter GWTat = def( "GWTat", Form.STRING, "The directory to find the GWT JARs. Required if 'GWT' indicated" );
75 -
76 - public static final Parameter GWTwar = def( "GWTwar", Form.STRING, "The directory to put the GWT Compiler's output in.", //
77 - "Default: '$target$/GWTCompilerOutput'." );
78 -
79 - public static final Parameter GWTstyle =
80 - def( "GWTstyle", Form.STRING, "GWT Compiler's output 'style'. Options are: OBF, PRETTY, or DETAILED. Note: OBF == Obfuscated.", //
81 - "Default: 'OBF'." );
82 -
83 - public static final Parameter GWTlogging =
84 - def( "GWTlogging", Form.STRING, "Logging level for the GWT Compiler. Options are: ERROR, WARN, INFO, TRACE, DEBUG, SPAM, or ALL.", //
85 - "Default: 'INFO'." );
86 -
87 - public static final Parameter GWTmx = def( "GWTmx", Form.STRING, "the -Xmx value for the GWT Compiler.", //
88 - "Default: '1024m'." );
89 -
90 - public static final String GWT_DEV = "gwt-dev.jar";
91 - public static final String GWT_USER = "gwt-user.jar";
92 - public static final String GWT_SERVLET = "gwt-servlet.jar";
93 - public static final String GWT_VALIDATION = "validation-api-1.0.0.GA.jar";
94 - public static final String GWT_VALIDATION_SOURCE = "validation-api-1.0.0.GA-sources.jar";
95 -
96 - private static final String[] GWT_JARS = {GWT_DEV, GWT_USER, GWT_SERVLET};
97 -
98 - // -------------------------------------------------- Validation ---------------------------------------------------
99 -
100 - public ProjectParameters validate()
101 - {
102 - List<String> zPackaging = new ArrayList<String>();
103 - check( zPackaging, "AppDir", getAppDir() );
104 - check( zPackaging, "OneJAR", getOneJar() );
105 - check( zPackaging, "WAR", getWar() );
106 - check( zPackaging, "PhoneGapDir", getPhoneGapDir() );
107 - switch ( zPackaging.size() )
108 - {
109 - case 0:
110 - case 1:
111 - return this;
112 - case 2:
113 - throw new IllegalArgumentException( "May not specify both: " + zPackaging.get( 0 ) + " & " + zPackaging.get( 1 ) );
114 - default:
115 - String zMsg = "May only specify one of:";
116 - while ( zPackaging.size() > 1 )
117 - {
118 - zMsg += " " + zPackaging.remove( 0 ) + ",";
119 - }
120 - throw new IllegalArgumentException( zMsg + " or " + zPackaging.get( 0 ) );
121 - }
122 - }
123 -
124 - private void check( List<String> pPackaging, String pLabel, Object pObjectToCheck )
125 - {
126 - if ( pObjectToCheck != null )
127 - {
128 - pPackaging.add( pLabel );
129 - }
130 - }
131 -
132 - // ------------------------------------------------ Default Support ------------------------------------------------
133 -
134 - protected synchronized void applyDefaults()
135 - {
136 - defaultTARGET();
137 - defaultCLASSPATH();
138 - defaultSOURCE();
139 - defaultRESOURCES();
140 - defaultJAR();
141 - defaultDIST();
142 - defaultGWT();
143 - defaultOneJar();
144 - }
145 -
146 - protected void defaultOneJar()
147 - {
148 - enforceJarExtension( ONEJAR.getName() );
149 - }
150 -
151 - protected void defaultDIST()
152 - {
153 - defaultSubDirOptional( DIST, "war" );
154 - }
155 -
156 - protected void defaultJAR()
157 - {
158 - if ( null == enforceJarExtension( JAR.getName() ) )
159 - {
160 - mManager.put( JAR.getName(), "$target$/$name$" + (hasVersion() ? "-$version$" : "") + ".jar" );
161 - }
162 - }
163 -
164 - protected void defaultTARGET()
165 - {
166 - defaultKey( TARGET, "build" );
167 - }
168 -
169 - protected void defaultCLASSPATH()
170 - {
171 - defaultSubDirOptional( CLASSPATH, "lib|**.jar" );
172 - }
173 -
174 - protected void defaultRESOURCES()
175 - {
176 - defaultSubDirOptional( RESOURCES, "src/main/resources", "resources" );
177 - }
178 -
179 - protected void defaultSOURCE()
180 - {
181 - defaultSubDirOptional( SOURCE, "src/main/java|**.java", "src|**.java" );
182 - }
183 -
184 - protected void defaultGWT()
185 - {
186 - String zGWT = getGWT();
187 - if ( null != zGWT )
188 - {
189 - verifyGWTlibs( getGWTatDir() );
190 - defaultKey( GWTwar, "$target$/GWTCompilerOutput" );
191 - defaultKey( GWTstyle, "OBF" );
192 - defaultKey( GWTlogging, "INFO" );
193 - defaultKey( GWTmx, "1024m" );
194 - }
195 - }
196 -
197 - protected void verifyGWTlibs( File pGWTdir )
198 - {
199 - if ( pGWTdir == null )
200 - {
201 - throw new IllegalStateException( "GWT specified, but NO GWTat!" );
202 - }
203 - if ( !pGWTdir.isDirectory() )
204 - {
205 - throw new IllegalStateException( "GWTat '" + pGWTdir + "' is not a directory!" );
206 - }
207 - for ( String zGwtJar : GWT_JARS )
208 - {
209 - if ( !new File( pGWTdir, zGwtJar ).isFile() )
210 - {
211 - throw new IllegalStateException( "GWTat '" + pGWTdir.getPath() + "' did not contain: " + zGwtJar );
212 - }
213 - }
214 - }
215 -
216 - protected String enforceJarExtension( String pEntryName )
217 - {
218 - String zJar = get( pEntryName );
219 - if ( null != zJar )
220 - {
221 - int at = zJar.lastIndexOf( '.' );
222 - if ( at == -1 || !".jar".equalsIgnoreCase( zJar.substring( at ) ) )
223 - {
224 - mManager.put( pEntryName, zJar += ".jar" );
225 - }
226 - }
227 - return zJar;
228 - }
229 -
230 - // ------------------------------------------- Special Property Accessors ------------------------------------------
231 -
232 - public boolean hasVersion()
233 - {
234 - return (null != getVersion());
235 - }
236 -
237 - public String getVersion()
238 - {
239 - return get( VERSION.getName() );
240 - }
241 -
242 - public boolean hasMain()
243 - {
244 - return (null != getMain());
245 - }
246 -
247 - public String getMain()
248 - {
249 - return get( MAIN.getName() );
250 - }
251 -
252 - public String getTarget()
253 - {
254 - return get( TARGET.getName() );
255 - }
256 -
257 - public String getTargetPath()
258 - {
259 - return getPath( TARGET.getName() );
260 - }
261 -
262 - public List<String> getDependencies()
263 - {
264 - List<String> zResult = getCachedWithConvertion( DEPENDENCIES.getName(), FORMATTED_LIST_STRING, null );
265 - return (zResult != null) ? zResult : Collections.<String>emptyList();
266 - }
267 -
268 - public Paths getCompileClasspath()
269 - {
270 - return getPaths( COMPILECLASSPATH.getName() );
271 - }
272 -
273 - public Paths getClasspath()
274 - {
275 - return getPaths( CLASSPATH.getName() );
276 - }
277 -
278 - public Paths getSource()
279 - {
280 - return getPaths( SOURCE.getName() );
281 - }
282 -
283 - public Paths getResources()
284 - {
285 - return getPaths( RESOURCES.getName() );
286 - }
287 -
288 - public String getJar()
289 - {
290 - return get( JAR.getName() );
291 - }
292 -
293 - public String getJarPath()
294 - {
295 - return getPath( JAR.getName() );
296 - }
297 -
298 - public File getJarPathFile()
299 - {
300 - return new File( getJarPath() );
301 - }
302 -
303 - public Paths getDist()
304 - {
305 - return getPaths( DIST.getName() );
306 - }
307 -
308 - public String getPhoneGapDir()
309 - {
310 - return get( PHONEGAPDIR.getName() );
311 - }
312 -
313 - public String getPhoneGapDirPath()
314 - {
315 - return getPath( PHONEGAPDIR.getName() );
316 - }
317 -
318 - public String getAppDir()
319 - {
320 - return get( APPDIR.getName() );
321 - }
322 -
323 - public String getAppDirPath()
324 - {
325 - return getPath( APPDIR.getName() );
326 - }
327 -
328 - public String getOneJar()
329 - {
330 - return get( ONEJAR.getName() );
331 - }
332 -
333 - public String getOneJarPath()
334 - {
335 - return getPath( ONEJAR.getName() );
336 - }
337 -
338 - public File getOneJarPathFile()
339 - {
340 - String zJar = getOneJarPath();
341 - if ( zJar == null )
342 - {
343 - return null;
344 - }
345 - int at = zJar.lastIndexOf( '.' );
346 - if ( at == -1 || !".jar".equalsIgnoreCase( zJar.substring( at ) ) )
347 - {
348 - zJar += ".jar";
349 - }
350 - return new File( zJar );
351 - }
352 -
353 - public String getWar()
354 - {
355 - return get( WAR.getName() );
356 - }
357 -
358 - public String getWarPath()
359 - {
360 - return getPath( WAR.getName() );
361 - }
362 -
363 - public File getWarPathFile()
364 - {
365 - return new File( getWarPath() );
366 - }
367 -
368 - public String getGWT()
369 - {
370 - return get( GWT.getName() );
371 - }
372 -
373 - public String getGWTat()
374 - {
375 - return get( GWTat.getName() );
376 - }
377 -
378 - public File getGWTatDir()
379 - {
380 - return new File( getPath( GWTat.getName() ) );
381 - }
382 -
383 - public String getGWTwar()
384 - {
385 - return get( GWTwar.getName() );
386 - }
387 -
388 - public String getGWTwarPath()
389 - {
390 - return getPath( GWTwar.getName() );
391 - }
392 -
393 - public String getGWTstyle()
394 - {
395 - return get( GWTstyle.getName() );
396 - }
397 -
398 - public String getGWTlogging()
399 - {
400 - return get( GWTlogging.getName() );
401 - }
402 -
403 - public String getGWTmx()
404 - {
405 - return get( GWTmx.getName() );
406 - }
407 -
408 - // ---------------------------------- Generic accessors for the underlying Data (map) ------------------------------
409 -
410 - public boolean has( Object key )
411 - {
412 - return null != getObject( key );
413 - }
414 -
415 - public Object getObject( Object key )
416 - {
417 - return mManager.get( mManager.normalizeKey( key ) );
418 - }
419 -
420 - public Object getObject( Object key, Object defaultValue )
421 - {
422 - return Util.deNull( getObject( key ), defaultValue );
423 - }
424 -
425 - public String get( Object key )
426 - {
427 - Object zValue = getObject( key );
428 - return (zValue != null) ? zValue.toString() : null;
429 - }
430 -
431 - public String get( Object key, String defaultValue )
432 - {
433 - return Util.deNull( get( key ), defaultValue );
434 - }
435 -
436 - public int get_int( Object key )
437 - {
438 - return get_int( key, 0 );
439 - }
440 -
441 - public int get_int( Object key, int defaultValue )
442 - {
443 - return getInteger( key, defaultValue );
444 - }
445 -
446 - public Integer getInteger( Object key, int defaultValue )
447 - {
448 - return Util.deNull( getInteger( key ), defaultValue );
449 - }
450 -
451 - public Integer getInteger( Object key )
452 - {
453 - return getCachedWithConvertion( key, INTEGER, null );
454 - }
455 -
456 - public float get_float( Object key )
457 - {
458 - return get_float( key, 0 );
459 - }
460 -
461 - public float get_float( Object key, float defaultValue )
462 - {
463 - return getFloat( key, defaultValue );
464 - }
465 -
466 - public Float getFloat( Object key, float defaultValue )
467 - {
468 - return Util.deNull( getFloat( key ), defaultValue );
469 - }
470 -
471 - public Float getFloat( Object key )
472 - {
473 - return getCachedWithConvertion( key, FLOAT, null );
474 - }
475 -
476 - public boolean get_boolean( Object key )
477 - {
478 - return get_boolean( key, false );
479 - }
480 -
481 - public boolean get_boolean( Object key, boolean defaultValue )
482 - {
483 - return getBoolean( key, defaultValue );
484 - }
485 -
486 - public Boolean getBoolean( Object key, boolean defaultValue )
487 - {
488 - return Util.deNull( getBoolean( key ), defaultValue );
489 - }
490 -
491 - public Boolean getBoolean( Object key )
492 - {
493 - return getCachedWithConvertion( key, BOOLEAN, null );
494 - }
495 -
496 - /**
497 - * Returns a list of objects under the specified key. If the key is a single value, it is placed in a list and returned. If the
498 - * key does not exist, a list with the defaultValues is returned.
499 - */
500 - public List<?> getObjectListNotNull( Object key, Object... defaultValues )
501 - {
502 - List<?> zList = getObjectList( key );
503 - return (zList != null) ? zList : (defaultValues == null) ? Collections.emptyList() : Arrays.asList( defaultValues );
504 - }
505 -
506 - /**
507 - * Returns a list of objects under the specified key. If the key is a single value, it is placed in a list and returned. If the
508 - * key does not exist, a 'null' is returned.
509 - */
510 - public List<?> getObjectList( Object key )
511 - {
512 - return getCachedWithConvertion( key, LIST_OBJECT, null );
513 - }
514 -
515 - /**
516 - * Returns a list of strings under the specified key. If the key is a single value, it is placed in a list and returned. If the
517 - * key does not exist, a list with the defaultValues is returned.
518 - */
519 - public List<String> getListNotNull( Object key, String... defaultValues )
520 - {
521 - List<String> zList = getList( key );
522 - return (zList != null) ? zList : (defaultValues == null) ? Collections.<String>emptyList() : Arrays.asList( defaultValues );
523 - }
524 -
525 - /**
526 - * Returns a list of strings under the specified key. If the key is a single value, it is placed in a list and returned. If the
527 - * key does not exist, a 'null' is returned.
528 - */
529 - public List<String> getList( Object key )
530 - {
531 - return getCachedWithConvertion( key, LIST_STRING, null );
532 - }
533 -
534 - /**
535 - * Returns a Map<Object,Object> under the specified key. If the key does not exist, a Map with the defaultValues (as Key/Value pairs) is returned.
536 - */
537 - public Map<?, ?> getObjectMapNotNull( Object key, Object... defaultValues )
538 - {
539 - Util.assertPairedEntries( "defaultValues", defaultValues );
540 - Map<?, ?> map = getObjectMap( key );
541 - return (map != null) ? map : createMap( defaultValues );
542 - }
543 -
544 - /**
545 - * Returns a Map<Object,Object> under the specified key. If the key does not exist, a 'null' is returned.
546 - */
547 - public Map<?, ?> getObjectMap( Object key )
548 - {
549 - return getCachedWithConvertion( key, MAP_OBJECT, null );
550 - }
551 -
552 - /**
553 - * Returns a Map<String,String> under the specified key. If the key does not exist, a Map with the defaultValues (as Key/Value pairs) is returned.
554 - */
555 - public Map<String, String> getMapNotNull( Object key, String... defaultValues )
556 - {
557 - Util.assertPairedEntries( "defaultValues", defaultValues );
558 - Map<String, String> map = getMap( key );
559 - return (map != null) ? map : createMap( defaultValues );
560 - }
561 -
562 - /**
563 - * Returns a Map<String, String> under the specified key. If the key does not exist, a 'null' is returned.
564 - */
565 - public Map<String, String> getMap( Object key )
566 - {
567 - return getCachedWithConvertion( key, MAP_STRING, null );
568 - }
569 -
570 - /**
571 - * Uses the strings under the specified key to {@link Paths#glob(String, String...) glob} paths.
572 - */
573 - public Paths getPaths( String key )
574 - {
575 - return getCachedWithConvertion( key, PATHS, PATHS_DEFAULTER );
576 - }
577 -
578 - /**
579 - * Uses the strings under the specified key to {@link Paths#glob(String, String...) glob} paths.
580 - */
581 - public String getPath( String key )
582 - {
583 - return getCachedWithConvertion( key, PATH, null );
584 - }
585 -
586 - /**
587 - * Returns a canonicalizePath built from the specified path.
588 - * If the specified path is a relative path, it is made absolute relative to this project's directory.
589 - */
590 - public String path( String path )
591 - {
592 - if ( path == null )
593 - {
594 - return null;
595 - }
596 - path = format( path );
597 - String zSuffix = "";
598 - int pipeIndex = path.indexOf( '|' );
599 - if ( pipeIndex > -1 )
600 - {
601 - // Handle wildcard search patterns.
602 - zSuffix = path.substring( pipeIndex );
603 - path = path.substring( 0, pipeIndex );
604 - }
605 - return canonicalizePath( getCanonicalProjectDir(), path ).getPath() + zSuffix;
606 - }
607 -
608 - /**
609 - * Replaces property names surrounded by dollar-signs ('$') with the value from this project.
610 - */
611 - public String format( String text )
612 - {
613 - Matcher matcher = formatPattern.matcher( text );
614 - StringBuilder buffer = new StringBuilder( 128 );
615 - while ( matcher.find() )
616 - {
617 - buffer.append( matcher.group( 1 ) );
618 - String name = matcher.group( 2 );
619 - Object value = getObject( name );
620 - if ( value instanceof String )
621 - {
622 - buffer.append( format( (String) value ) );
623 - }
624 - else if ( value != null )
625 - {
626 - buffer.append( value );
627 - }
628 - else
629 - {
630 - buffer.append( name );
631 - }
632 - buffer.append( matcher.group( 3 ) );
633 - }
634 - if ( buffer.length() == 0 )
635 - {
636 - return text;
637 - }
638 - return buffer.toString();
639 - }
640 -
641 - public Object[] keys()
642 - {
643 - return mManager.keys();
644 - }
645 -
646 - public File getCanonicalProjectDir()
647 - {
648 - return mCanonicalProjectDir;
649 - }
650 -
651 - public String getName()
652 - {
653 - return mName;
654 - }
655 -
656 - public ProjectParameters( File pProjectFile, String pName, File pCanonicalProjectDir, Map<Object, Object> pData )
657 - {
658 - this( pProjectFile.lastModified(), pName, pCanonicalProjectDir, new Manager( pData ) );
659 - }
660 -
661 - // ---------------------------------------------------- Support ----------------------------------------------------
662 -
663 - protected ProjectParameters( ProjectParameters pParameters )
664 - {
665 - this( pParameters.mProjectFileLastModified, pParameters.getName(), pParameters.getCanonicalProjectDir(), pParameters.mManager );
666 - }
667 -
668 - private ProjectParameters( long pProjectFileLastModified, String pName, File pCanonicalProjectDir, Manager pManager )
669 - {
670 - mProjectFileLastModified = pProjectFileLastModified;
671 - mCanonicalProjectDir = pCanonicalProjectDir;
672 - mManager = pManager;
673 - Object zName = mManager.get( NAME.getName() );
674 - mManager.put( NAME.getName(), mName = (zName != null) ? zName.toString() : pName );
675 - }
676 -
677 - protected final long mProjectFileLastModified;
678 - protected final File mCanonicalProjectDir;
679 - protected final Manager mManager;
680 - protected final String mName;
681 -
682 - static private final java.util.regex.Pattern formatPattern = java.util.regex.Pattern.compile( "([^\\$]*)\\$([^\\$]+)\\$([^\\$]*)" );
683 -
684 - @SuppressWarnings({"unchecked"})
685 - private <T> Map<T, T> getAsMap( Object pKey )
686 - {
687 - Object zValue = getObject( pKey );
688 - return (zValue instanceof Map) ? (Map<T, T>) zValue : null;
689 - }
690 -
691 - @Override
692 - public String toString()
693 - {
694 - return getName();
695 - }
696 -
697 - protected void defaultSubDirOptional( Parameter pParameter, String... pOptions )
698 - {
699 - Object o = mManager.get( pParameter.getName() );
700 - if ( o == null )
701 - {
702 - for ( String zOption : pOptions )
703 - {
704 - int at = zOption.indexOf( '|' );
705 - if ( dirExists( (at == -1) ? zOption : zOption.substring( 0, at ) ) )
706 - {
707 - mManager.put( pParameter.getName(), zOption );
708 - return;
709 - }
710 - }
711 - }
712 - }
713 -
714 - protected boolean dirExists( String pPath )
715 - {
716 - int pipeAt = pPath.indexOf( '|' );
717 - if ( pipeAt != -1 )
718 - {
719 - pPath = pPath.substring( pipeAt );
720 - }
721 - return new File( getCanonicalProjectDir(), pPath ).isDirectory();
722 - }
723 -
724 - protected void defaultKey( Parameter pParameter, String pDefault )
725 - {
726 - if ( null == get( pParameter.getName() ) )
727 - {
728 - mManager.put( pParameter.getName(), pDefault );
729 - }
730 - }
731 -
732 - protected <T> Map<T, T> createMap( T[] defaultValues )
733 - {
734 - Map<T, T> map = new HashMap<T, T>();
735 - if ( defaultValues != null )
736 - {
737 - for ( int i = 0; i < defaultValues.length; )
738 - {
739 - T defaultKey = defaultValues[i++];
740 - T defaultValue = defaultValues[i++];
741 - map.put( defaultKey, defaultValue );
742 - }
743 - }
744 - return map;
745 - }
746 -
747 - protected <T> T getCachedWithConvertion( Object pKey, DataConverter<T> pConverter, DataDefaulter<T> pDefaulter )
748 - {
749 - Object zValue = mManager.getCachedResponse( pKey = mManager.normalizeKey( pKey ) );
750 - if ( zValue != null )
751 - {
752 - //noinspection unchecked
753 - return (T) zValue;
754 - }
755 - zValue = mManager.get( pKey );
756 - T zConverted = null;
757 - if ( zValue != null )
758 - {
759 - zConverted = pConverter.convert( zValue );
760 - }
761 - else if ( pDefaulter != null )
762 - {
763 - zConverted = pDefaulter.createDefault();
764 - }
765 - if ( zConverted != null )
766 - {
767 - mManager.addCachedResponse( pKey, zConverted );
768 - }
769 - return zConverted;
770 - }
771 -
772 - private static final DataConverter<Integer> INTEGER = new DataConverter<Integer>()
773 - {
774 - @Override
775 - public Integer convert( Object pValue )
776 - {
777 - return (pValue instanceof Number) ? ((Number) pValue).intValue() : Integer.parseInt( pValue.toString() );
778 - }
779 - };
780 -
781 - private static final DataConverter<Float> FLOAT = new DataConverter<Float>()
782 - {
783 - @Override
784 - public Float convert( Object pValue )
785 - {
786 - return (pValue instanceof Number) ? ((Number) pValue).floatValue() : Float.parseFloat( pValue.toString() );
787 - }
788 - };
789 -
790 - private static final DataConverter<Boolean> BOOLEAN = new DataConverter<Boolean>()
791 - {
792 - @Override
793 - public Boolean convert( Object pValue )
794 - {
795 - return (pValue instanceof Boolean) ? (Boolean) pValue : Boolean.parseBoolean( pValue.toString() );
796 - }
797 - };
798 -
799 - private static final DataConverter<List<?>> LIST_OBJECT = new DataConverter<List<?>>()
800 - {
801 - @Override
802 - public List<?> convert( Object pValue )
803 - {
804 - return (pValue instanceof List) ? (List<?>) pValue : Arrays.asList( pValue );
805 - }
806 - };
807 -
808 - private static final DataConverter<List<String>> LIST_STRING = new DataConverter<List<String>>()
809 - {
810 - @Override
811 - public List<String> convert( Object pValue )
812 - {
813 - //noinspection unchecked
814 - return (pValue instanceof List) ? (List<String>) pValue : Arrays.asList( pValue.toString() );
815 - }
816 - };
817 -
818 - private static final DataConverter<Map<?, ?>> MAP_OBJECT = new DataConverter<Map<?, ?>>()
819 - {
820 - @Override
821 - public Map<?, ?> convert( Object pValue )
822 - {
823 - return (Map<?, ?>) pValue;
824 - }
825 - };
826 -
827 - private static final DataConverter<Map<String, String>> MAP_STRING = new DataConverter<Map<String, String>>()
828 - {
829 - @Override
830 - public Map<String, String> convert( Object pValue )
831 - {
832 - //noinspection unchecked
833 - return (Map<String, String>) pValue;
834 - }
835 - };
836 -
837 - private final DataConverter<List<String>> FORMATTED_LIST_STRING = new DataConverter<List<String>>()
838 - {
839 - @Override
840 - public List<String> convert( Object pValue )
841 - {
842 - List<String> zList = LIST_STRING.convert( pValue );
843 - List<String> zFormattedList = new ArrayList<String>( zList.size() );
844 - for ( String zEntry : zList )
845 - {
846 - zFormattedList.add( format( zEntry ) );
847 - }
848 - return zFormattedList;
849 - }
850 - };
851 -
852 - private final DataConverter<String> PATH = new DataConverter<String>()
853 - {
854 - @Override
855 - public String convert( Object pValue )
856 - {
857 - return path( pValue.toString() );
858 - }
859 - };
860 -
861 - private final DataConverter<Paths> PATHS = new DataConverter<Paths>()
862 - {
863 - @Override
864 - public Paths convert( Object pValue )
865 - {
866 - Paths paths = new Paths();
867 - List<String> zList = LIST_STRING.convert( pValue );
868 - for ( String dirPattern : zList )
869 - {
870 - paths.glob( path( dirPattern ) );
871 - }
872 - return paths;
873 - }
874 - };
875 -
876 - private final DataDefaulter<Paths> PATHS_DEFAULTER = new DataDefaulter<Paths>()
877 - {
878 - @Override public Paths createDefault()
879 - {
880 - return new Paths();
881 - }
882 - };
883 - }
1 + package com.esotericsoftware.scar;
2 +
3 + import com.esotericsoftware.filesystem.*;
4 + import com.esotericsoftware.scar.support.*;
5 + import com.esotericsoftware.utils.*;
6 +
7 + import java.io.*;
8 + import java.util.*;
9 + import java.util.regex.*;
10 +
11 + import static com.esotericsoftware.scar.support.Parameter.*;
12 +
13 + @SuppressWarnings({"UnusedDeclaration"})
14 + public class ProjectParameters extends FileUtil {
15 + public static final Parameter NAME = def( "name", Form.STRING,
16 + "The name of the project. Used to name the JAR.", //
17 + "Default:\n" + //
18 + " The name of the directory containing the project YAML file, or\n" + //
19 + " the name of the YAML file if it is not 'build'." );
20 +
21 + public static final Parameter VERSION = def( "version", Form.STRING,
22 + "The version of the project. If available, used to name the 'default' named JAR." );
23 +
24 + public static final Parameter MAIN = def( "main", Form.STRING,
25 + "Name of the main class." );
26 +
27 + public static final Parameter TARGET = def( "target", Form.STRING,
28 + "The directory to output build artifacts.", //
29 + "Default: The directory containing the project YAML file, plus 'build'." );
30 +
31 + public static final Parameter DEPENDENCIES = def( "dependencies", Form.STRING_LIST,
32 + "Relative or absolute path(s) to dependency project directories or YAML files." );
33 +
34 + public static final Parameter COMPILECLASSPATH = def( "compileclasspath", Form.PATHS,
35 + "Wildcard patterns for the file(s) to include on the 'compile' classpath.", //
36 + "Note: automatically includes the ClassPath(s)." );
37 +
38 + public static final Parameter CLASSPATH = def( "classpath", Form.PATHS,
39 + "Wildcard patterns for the file(s) to include on the classpath (both, compile & runtime/deployment).", //
40 + "Default: 'lib|**.jar'." );
41 +
42 + public static final Parameter SOURCE = def( "source", Form.PATHS,
43 + "Wildcard patterns for the Java file(s) to compile.", //
44 + "Default: 'src|**.java' or 'src/main/java|**.java'." );
45 +
46 + public static final Parameter RESOURCES = def( "resources", Form.PATHS,
47 + "Wildcard patterns for the file(s) to include in the JAR.", //
48 + "Default: 'resources' or 'src/main/resources'." );
49 +
50 + public static final Parameter JAR = def( "jar", Form.STRING,
51 + "JAR name w/ optional path for the JAR ('.jar' added to the end if does not end with 'jar', case insensitive).", //
52 + "Default: '$target$[-$version$]'." );
53 +
54 + public static final Parameter DIST = def( "dist", Form.PATHS,
55 + "Wildcard patterns for the file(s) to include in the distribution, outside the JAR.", //
56 + "Default: 'war' (if there)." );
57 +
58 + // ------------------------------- Packaging Options, these are mutually exclusive ---------------------------------
59 +
60 + public static final Parameter PHONEGAPDIR = def( "phonegapdir", Form.STRING,
61 + "Directory path to bring together all the files needed for a PgoneGap app", //
62 + "('dist', for this project and all dependencies, recursively)." );
63 +
64 + public static final Parameter APPDIR = def( "appdir", Form.STRING,
65 + "Directory path to bring together all files (both JARs and 'dist', for this project", //
66 + "and all dependencies, recursively) the application needs to be run from JAR files." );
67 +
68 + public static final Parameter ONEJAR = def( "onejar", Form.STRING,
69 + "JAR name w/ optional path for the JAR ('.jar' added to the end if does not end with 'jar', case insensitive),", //
70 + "that all 'exploded' dependendend JARs and dist files will be JAR'd into (this should make a single JAR application)." );
71 +
72 + public static final Parameter WAR = def( "war", Form.STRING,
73 + "Target WAR directory or WAR name (if ends w/ '.war'), produces a war directory (as specified, " +
74 + "or a default one if a '.war' is requested)",
75 + "then if a '.war' is requested, packages the war directory into the specified '.war' file." );
76 +
77 + // ------------------------------------------------ GWT Parameters -------------------------------------------------
78 +
79 + public static final Parameter GWT = def( "GWT", Form.STRING,
80 + "The 'package' Name of the 'root' '.gwt.xml' file. e.g. 'org.sample.MyGwtApplication'" );
81 +
82 + public static final Parameter GWTat = def( "GWTat", Form.STRING,
83 + "The directory to find the GWT JARs. Required if 'GWT' indicated" );
84 +
85 + public static final Parameter GWTwar = def( "GWTwar", Form.STRING,
86 + "The directory to put the GWT Compiler's output in.", //
87 + "Default: '$target$/GWTCompilerOutput'." );
88 +
89 + public static final Parameter GWTstyle = def( "GWTstyle", Form.STRING,
90 + "GWT Compiler's output 'style'. Options are: OBF, PRETTY, or DETAILED. Note: OBF == Obfuscated.", //
91 + "Default: 'OBF'." );
92 +
93 + public static final Parameter GWTlogging = def( "GWTlogging", Form.STRING,
94 + "Logging level for the GWT Compiler. Options are: ERROR, WARN, INFO, TRACE, DEBUG, SPAM, or ALL.", //
95 + "Default: 'INFO'." );
96 +
97 + public static final Parameter GWTmx = def( "GWTmx", Form.STRING,
98 + "the -Xmx value for the GWT Compiler.", //
99 + "Default: '1024m'." );
100 +
101 + public static final Parameter GWTcr = def( "GWTcr", Form.STRING,
102 + "indicates that a GWT Compile Report is requested." );
103 +
104 +
105 + public static final String GWT_DEV = "gwt-dev.jar";
106 + public static final String GWT_USER = "gwt-user.jar";
107 + public static final String GWT_SERVLET = "gwt-servlet.jar";
108 + public static final String GWT_VALIDATION = "validation-api-1.0.0.GA.jar";
109 + public static final String GWT_VALIDATION_SOURCE = "validation-api-1.0.0.GA-sources.jar";
110 +
111 + private static final String[] GWT_JARS = {GWT_DEV, GWT_USER, GWT_SERVLET};
112 +
113 + // -------------------------------------------------- Validation ---------------------------------------------------
114 +
115 + public ProjectParameters validate() {
116 + mManager.applySystemPropertyOverrides();
117 + List<String> zPackaging = new ArrayList<String>();
118 + check( zPackaging, "AppDir", getAppDir() );
119 + check( zPackaging, "OneJAR", getOneJar() );
120 + check( zPackaging, "WAR", getWar() );
121 + check( zPackaging, "PhoneGapDir", getPhoneGapDir() );
122 + switch ( zPackaging.size() ) {
123 + case 0:
124 + case 1:
125 + return this;
126 + case 2:
127 + throw new IllegalArgumentException( "May not specify both: " + zPackaging.get( 0 ) + " & " + zPackaging.get( 1 ) );
128 + default:
129 + String zMsg = "May only specify one of:";
130 + while ( zPackaging.size() > 1 ) {
131 + zMsg += " " + zPackaging.remove( 0 ) + ",";
132 + }
133 + throw new IllegalArgumentException( zMsg + " or " + zPackaging.get( 0 ) );
134 + }
135 + }
136 +
137 + private void check( List<String> pPackaging, String pLabel, Object pObjectToCheck ) {
138 + if ( pObjectToCheck != null ) {
139 + pPackaging.add( pLabel );
140 + }
141 + }
142 +
143 + // ------------------------------------------------ Default Support ------------------------------------------------
144 +
145 + protected synchronized void applyDefaults() {
146 + defaultTARGET();
147 + defaultCLASSPATH();
148 + defaultSOURCE();
149 + defaultRESOURCES();
150 + defaultJAR();
151 + defaultDIST();
152 + defaultGWT();
153 + defaultOneJar();
154 + }
155 +
156 + protected void defaultOneJar() {
157 + enforceJarExtension( ONEJAR.getName(), null );
158 + }
159 +
160 + protected void defaultDIST() {
161 + defaultSubDirOptional( DIST, "war" );
162 + }
163 +
164 + protected void defaultJAR() {
165 + enforceJarExtension( ONEJAR.getName(), new DataDefaulter<String>() {
166 + @Override
167 + public String createDefault() {
168 + return "$target$/$name$" + (hasVersion() ? "-$version$" : "") + ".jar";
169 + }
170 + } );
171 + }
172 +
173 + protected void defaultTARGET() {
174 + defaultKey( TARGET, "build" );
175 + }
176 +
177 + protected void defaultCLASSPATH() {
178 + defaultSubDirOptional( CLASSPATH, "lib|**.jar" );
179 + }
180 +
181 + protected void defaultRESOURCES() {
182 + defaultSubDirOptional( RESOURCES, "src/main/resources", "resources" );
183 + }
184 +
185 + protected void defaultSOURCE() {
186 + defaultSubDirOptional( SOURCE, "src/main/java|**.java", "src|**.java" );
187 + }
188 +
189 + protected void defaultGWT() {
190 + String zGWT = getGWT();
191 + if ( null != zGWT ) {
192 + verifyGWTlibs( getGWTatDir() );
193 + defaultKey( GWTwar, "$target$/GWTCompilerOutput" );
194 + defaultKey( GWTstyle, "OBF" );
195 + defaultKey( GWTlogging, "INFO" );
196 + defaultKey( GWTmx, "1024m" );
197 + }
198 + }
199 +
200 + protected void verifyGWTlibs( File pGWTdir ) {
201 + if ( pGWTdir == null ) {
202 + throw new IllegalStateException( "GWT specified, but NO GWTat!" );
203 + }
204 + if ( !pGWTdir.isDirectory() ) {
205 + throw new IllegalStateException( "GWTat '" + pGWTdir + "' is not a directory!" );
206 + }
207 + for ( String zGwtJar : GWT_JARS ) {
208 + if ( !new File( pGWTdir, zGwtJar ).isFile() ) {
209 + throw new IllegalStateException( "GWTat '" + pGWTdir.getPath() + "' did not contain: " + zGwtJar );
210 + }
211 + }
212 + }
213 +
214 + protected void enforceJarExtension( String pEntryName, DataDefaulter<String> pDefaulter ) {
215 + mManager.ensureEntry( JAR.getName(), JAR_EXTENSION_CONVERTER, pDefaulter );
216 + }
217 +
218 + private static final DataConverter<String> JAR_EXTENSION_CONVERTER = new DataConverter<String>() {
219 + @Override
220 + public String convert( Object pValue ) {
221 + if ( pValue != null ) {
222 + String zValue = pValue.toString();
223 + if ( zValue != null ) {
224 + return ensureExtension( zValue, "jar" );
225 + }
226 + }
227 + return null;
228 + }
229 + };
230 +
231 + private static String ensureExtension( String pFileName, String pExtension ) {
232 + int at = pFileName.lastIndexOf( '.' ) + 1;
233 + if ( (at > 0) && pFileName.substring( at ).equalsIgnoreCase( pExtension ) ) {
234 + return pFileName;
235 + }
236 + return pFileName + "." + pExtension;
237 + }
238 +
239 + // ------------------------------------------- Special Property Accessors ------------------------------------------
240 +
241 + public boolean hasVersion() {
242 + return (null != getVersion());
243 + }
244 +
245 + public String getVersion() {
246 + return get( VERSION.getName() );
247 + }
248 +
249 + public boolean hasMain() {
250 + return (null != getMain());
251 + }
252 +
253 + public String getMain() {
254 + return get( MAIN.getName() );
255 + }
256 +
257 + public String getTarget() {
258 + return get( TARGET.getName() );
259 + }
260 +
261 + public String getTargetPath() {
262 + return getPath( TARGET.getName() );
263 + }
264 +
265 + public List<String> getDependencies() {
266 + List<String> zResult = mManager.getCachedWithConversion( DEPENDENCIES.getName(), FORMATTED_LIST_STRING );
267 + return (zResult != null) ? zResult : Collections.<String>emptyList();
268 + }
269 +
270 + public Paths getCompileClasspath() {
271 + return getPaths( COMPILECLASSPATH.getName() );
272 + }
273 +
274 + public Paths getClasspath() {
275 + return getPaths( CLASSPATH.getName() );
276 + }
277 +
278 + public Paths getSource() {
279 + return getPaths( SOURCE.getName() );
280 + }
281 +
282 + public Paths getResources() {
283 + return getPaths( RESOURCES.getName() );
284 + }
285 +
286 + public String getJar() {
287 + return get( JAR.getName() );
288 + }
289 +
290 + public String getJarPath() {
291 + return getPath( JAR.getName() );
292 + }
293 +
294 + public File getJarPathFile() {
295 + return new File( getJarPath() );
296 + }
297 +
298 + public Paths getDist() {
299 + return getPaths( DIST.getName() );
300 + }
301 +
302 + public String getPhoneGapDir() {
303 + return get( PHONEGAPDIR.getName() );
304 + }
305 +
306 + public String getPhoneGapDirPath() {
307 + return getPath( PHONEGAPDIR.getName() );
308 + }
309 +
310 + public String getAppDir() {
311 + return get( APPDIR.getName() );
312 + }
313 +
314 + public String getAppDirPath() {
315 + return getPath( APPDIR.getName() );
316 + }
317 +
318 + public String getOneJar() {
319 + return get( ONEJAR.getName() );
320 + }
321 +
322 + public String getOneJarPath() {
323 + return getPath( ONEJAR.getName() );
324 + }
325 +
326 + public File getOneJarPathFile() {
327 + String zJar = getOneJarPath();
328 + if ( zJar == null ) {
329 + return null;
330 + }
331 + int at = zJar.lastIndexOf( '.' );
332 + if ( at == -1 || !".jar".equalsIgnoreCase( zJar.substring( at ) ) ) {
333 + zJar += ".jar";
334 + }
335 + return new File( zJar );
336 + }
337 +
338 + public String getWar() {
339 + return get( WAR.getName() );
340 + }
341 +
342 + public String getWarPath() {
343 + return getPath( WAR.getName() );
344 + }
345 +
346 + public File getWarPathFile() {
347 + return new File( getWarPath() );
348 + }
349 +
350 + public String getGWT() {
351 + return get( GWT.getName() );
352 + }
353 +
354 + public String getGWTat() {
355 + return get( GWTat.getName() );
356 + }
357 +
358 + public File getGWTatDir() {
359 + return new File( getPath( GWTat.getName() ) );
360 + }
361 +
362 + public String getGWTwar() {
363 + return get( GWTwar.getName() );
364 + }
365 +
366 + public String getGWTwarPath() {
367 + return getPath( GWTwar.getName() );
368 + }
369 +
370 + public String getGWTstyle() {
371 + return get( GWTstyle.getName() );
372 + }
373 +
374 + public String getGWTlogging() {
375 + return get( GWTlogging.getName() );
376 + }
377 +
378 + public String getGWTmx() {
379 + return get( GWTmx.getName() );
380 + }
381 +
382 + public String[] getGWTcompileReport() {
383 + String zValue = get( GWTcr.getName() );
384 + if ( zValue == null ) {
385 + return null;
386 + }
387 + if ( zValue.length() == 0 ) {
388 + return new String[]{"-compileReport"};
389 + }
390 + return new String[]{"-compileReport", "-extra", zValue};
391 + }
392 +
393 + // ---------------------------------- Generic accessors for the underlying Data (map) ------------------------------
394 +
395 + public boolean has( Object key ) {
396 + return null != getObject( key );
397 + }
398 +
399 + public Object getObject( Object key ) {
400 + return mManager.get( key );
401 + }
402 +
403 + public Object getObject( Object key, Object defaultValue ) {
404 + return Util.deNull( getObject( key ), defaultValue );
405 + }
406 +
407 + public String get( Object key ) {
408 + Object zValue = getObject( key );
409 + return (zValue != null) ? zValue.toString() : null;
410 + }
411 +
412 + public String get( Object key, String defaultValue ) {
413 + return Util.deNull( get( key ), defaultValue );
414 + }
415 +
416 + public int get_int( Object key ) {
417 + return get_int( key, 0 );
418 + }
419 +
420 + public int get_int( Object key, int defaultValue ) {
421 + return getInteger( key, defaultValue );
422 + }
423 +
424 + public Integer getInteger( Object key, int defaultValue ) {
425 + return Util.deNull( getInteger( key ), defaultValue );
426 + }
427 +
428 + public Integer getInteger( Object key ) {
429 + return mManager.getCachedWithConversion( key, DataConverter.INTEGER );
430 + }
431 +
432 + public float get_float( Object key ) {
433 + return get_float( key, 0 );
434 + }
435 +
436 + public float get_float( Object key, float defaultValue ) {
437 + return getFloat( key, defaultValue );
438 + }
439 +
440 + public Float getFloat( Object key, float defaultValue ) {
441 + return Util.deNull( getFloat( key ), defaultValue );
442 + }
443 +
444 + public Float getFloat( Object key ) {
445 + return mManager.getCachedWithConversion( key, DataConverter.FLOAT );
446 + }
447 +
448 + public boolean get_boolean( Object key ) {
449 + return get_boolean( key, false );
450 + }
451 +
452 + public boolean get_boolean( Object key, boolean defaultValue ) {
453 + return getBoolean( key, defaultValue );
454 + }
455 +
456 + public Boolean getBoolean( Object key, boolean defaultValue ) {
457 + return Util.deNull( getBoolean( key ), defaultValue );
458 + }
459 +
460 + public Boolean getBoolean( Object key ) {
461 + return mManager.getCachedWithConversion( key, DataConverter.BOOLEAN );
462 + }
463 +
464 + /**
465 + * Returns a list of objects under the specified key. If the key is a single value, it is placed in a list and returned. If the
466 + * key does not exist, a list with the defaultValues is returned.
467 + */
468 + public List<?> getObjectListNotNull( Object key, Object... defaultValues ) {
469 + List<?> zList = getObjectList( key );
470 + return (zList != null) ? zList : (defaultValues == null) ? Collections.emptyList() : Arrays.asList( defaultValues );
471 + }
472 +
473 + /**
474 + * Returns a list of objects under the specified key. If the key is a single value, it is placed in a list and returned. If the
475 + * key does not exist, a 'null' is returned.
476 + */
477 + public List<?> getObjectList( Object key ) {
478 + return mManager.getCachedWithConversion( key, DataConverter.LIST_OBJECT );
479 + }
480 +
481 + /**
482 + * Returns a list of strings under the specified key. If the key is a single value, it is placed in a list and returned. If the
483 + * key does not exist, a list with the defaultValues is returned.
484 + */
485 + public List<String> getListNotNull( Object key, String... defaultValues ) {
486 + List<String> zList = getList( key );
487 + return (zList != null) ? zList : (defaultValues == null) ? Collections.<String>emptyList() : Arrays.asList( defaultValues );
488 + }
489 +
490 + /**
491 + * Returns a list of strings under the specified key. If the key is a single value, it is placed in a list and returned. If the
492 + * key does not exist, a 'null' is returned.
493 + */
494 + public List<String> getList( Object key ) {
495 + return mManager.getCachedWithConversion( key, DataConverter.LIST_STRING );
496 + }
497 +
498 + /**
499 + * Returns a Map<Object,Object> under the specified key. If the key does not exist, a Map with the defaultValues (as Key/Value pairs) is returned.
500 + */
501 + public Map<?, ?> getObjectMapNotNull( Object key, Object... defaultValues ) {
502 + Util.assertPairedEntries( "defaultValues", defaultValues );
503 + Map<?, ?> map = getObjectMap( key );
504 + return (map != null) ? map : createMap( defaultValues );
505 + }
506 +
507 + /**
508 + * Returns a Map<Object,Object> under the specified key. If the key does not exist, a 'null' is returned.
509 + */
510 + public Map<?, ?> getObjectMap( Object key ) {
511 + return mManager.getCachedWithConversion( key, DataConverter.MAP_OBJECT );
512 + }
513 +
514 + /**
515 + * Returns a Map<String,String> under the specified key. If the key does not exist, a Map with the defaultValues (as Key/Value pairs) is returned.
516 + */
517 + public Map<String, String> getMapNotNull( Object key, String... defaultValues ) {
518 + Util.assertPairedEntries( "defaultValues", defaultValues );
519 + Map<String, String> map = getMap( key );
520 + return (map != null) ? map : createMap( defaultValues );
521 + }
522 +
523 + /**
524 + * Returns a Map<String, String> under the specified key. If the key does not exist, a 'null' is returned.
525 + */
526 + public Map<String, String> getMap( Object key ) {
527 + return mManager.getCachedWithConversion( key, DataConverter.MAP_STRING );
528 + }
529 +
530 + /**
531 + * Uses the strings under the specified key to {@link Paths#glob(String, String...) glob} paths.
532 + */
533 + public Paths getPaths( String key ) {
534 + return mManager.getCachedWithConversion( key, PATHS, DataDefaulter.PATHS );
535 + }
536 +
537 + /**
538 + * Uses the strings under the specified key to {@link Paths#glob(String, String...) glob} paths.
539 + */
540 + public String getPath( String key ) {
541 + return mManager.getCachedWithConversion( key, PATH );
542 + }
543 +
544 + /**
545 + * Returns a canonicalizePath built from the specified path.
546 + * If the specified path is a relative path, it is made absolute relative to this project's directory.
547 + */
548 + public String path( String path ) {
549 + if ( path == null ) {
550 + return null;
551 + }
552 + path = format( path );
553 + String zSuffix = "";
554 + int pipeIndex = path.indexOf( '|' );
555 + if ( pipeIndex > -1 ) {
556 + // Handle wildcard search patterns.
557 + zSuffix = path.substring( pipeIndex );
558 + path = path.substring( 0, pipeIndex );
559 + }
560 + return canonicalizePath( getCanonicalProjectDir(), path ).getPath() + zSuffix;
561 + }
562 +
563 + /**
564 + * Replaces property names surrounded by dollar-signs ('$') with the value from this project.
565 + */
566 + public String format( String text ) {
567 + Matcher matcher = formatPattern.matcher( text );
568 + StringBuilder buffer = new StringBuilder( 128 );
569 + while ( matcher.find() ) {
570 + buffer.append( matcher.group( 1 ) );
571 + String name = matcher.group( 2 );
572 + Object value = getObject( name );
573 + if ( value instanceof String ) {
574 + buffer.append( format( (String) value ) );
575 + } else if ( value != null ) {
576 + buffer.append( value );
577 + } else {
578 + buffer.append( name );
579 + }
580 + buffer.append( matcher.group( 3 ) );
581 + }
582 + if ( buffer.length() == 0 ) {
583 + return text;
584 + }
585 + return buffer.toString();
586 + }
587 +
588 + public Object[] keys() {
589 + return mManager.keys();
590 + }
591 +
592 + public File getCanonicalProjectDir() {
593 + return mCanonicalProjectDir;
594 + }
595 +
596 + public String getName() {
597 + return mName;
598 + }
599 +
600 + public ProjectParameters( File pProjectFile, String pName, File pCanonicalProjectDir, Map<Object, Object> pData ) {
601 + this( pProjectFile.lastModified(), pName, pCanonicalProjectDir, new ParameterStore( pData ) );
602 + }
603 +
604 + // ---------------------------------------------------- Support ----------------------------------------------------
605 +
606 + protected ProjectParameters( ProjectParameters pParameters ) {
607 + this( pParameters.mProjectFileLastModified, pParameters.getName(), pParameters.getCanonicalProjectDir(), pParameters.mManager );
608 + }
609 +
610 + private ProjectParameters( long pProjectFileLastModified, String pName, File pCanonicalProjectDir, ParameterStore pManager ) {
611 + mProjectFileLastModified = pProjectFileLastModified;
612 + mCanonicalProjectDir = pCanonicalProjectDir;
613 + mName = (mManager = pManager).ensureEntryAsString( NAME.getName(), pName );
614 + }
615 +
616 + protected final long mProjectFileLastModified;
617 + protected final File mCanonicalProjectDir;
618 + protected final ParameterStore mManager;
619 + protected final String mName;
620 +
621 + static private final java.util.regex.Pattern formatPattern = java.util.regex.Pattern.compile( "([^\\$]*)\\$([^\\$]+)\\$([^\\$]*)" );
622 +
623 + @SuppressWarnings({"unchecked"})
624 + private <T> Map<T, T> getAsMap( Object pKey ) {
625 + Object zValue = getObject( pKey );
626 + return (zValue instanceof Map) ? (Map<T, T>) zValue : null;
627 + }
628 +
629 + @Override
630 + public String toString() {
631 + return getName();
632 + }
633 +
634 + protected void defaultSubDirOptional( Parameter pParameter, final String... pOptions ) {
635 + mManager.ensureEntry( pParameter.getName(), new DataDefaulter<String>() {
636 + @Override
637 + public String createDefault() {
638 + for ( String zOption : pOptions ) {
639 + int at = zOption.indexOf( '|' );
640 + if ( dirExists( (at == -1) ? zOption : zOption.substring( 0, at ) ) ) {
641 + return zOption;
642 + }
643 + }
644 + return null;
645 + }
646 + } );
647 + }
648 +
649 + protected boolean dirExists( String pPath ) {
650 + int pipeAt = pPath.indexOf( '|' );
651 + if ( pipeAt != -1 ) {
652 + pPath = pPath.substring( pipeAt );
653 + }
654 + return new File( getCanonicalProjectDir(), pPath ).isDirectory();
655 + }
656 +
657 + protected void defaultKey( Parameter pParameter, String pDefault ) {
658 + mManager.ensureEntry( pParameter.getName(), pDefault );
659 + }
660 +
661 + protected <T> Map<T, T> createMap( T[] defaultValues ) {
662 + Map<T, T> map = new HashMap<T, T>();
663 + if ( defaultValues != null ) {
664 + for ( int i = 0; i < defaultValues.length; ) {
665 + T defaultKey = defaultValues[i++];
666 + T defaultValue = defaultValues[i++];
667 + map.put( defaultKey, defaultValue );
668 + }
669 + }
670 + return map;
671 + }
672 +
673 + private final DataConverter<List<String>> FORMATTED_LIST_STRING = new DataConverter<List<String>>() {
674 + @Override
675 + public List<String> convert( Object pValue ) {
676 + List<String> zList = LIST_STRING.convert( pValue );
677 + List<String> zFormattedList = new ArrayList<String>( zList.size() );
678 + for ( String zEntry : zList ) {
679 + zFormattedList.add( format( zEntry ) );
680 + }
681 + return zFormattedList;
682 + }
683 + };
684 +
685 + private final DataConverter<String> PATH = new DataConverter<String>() {
686 + @Override
687 + public String convert( Object pValue ) {
688 + return path( pValue.toString() );
689 + }
690 + };
691 +
692 + private final DataConverter<Paths> PATHS = new DataConverter<Paths>() {
693 + @Override
694 + public Paths convert( Object pValue ) {
695 + Paths paths = new Paths();
696 + List<String> zList = LIST_STRING.convert( pValue );
697 + for ( String dirPattern : zList ) {
698 + paths.glob( path( dirPattern ) );
699 + }
700 + return paths;
701 + }
702 + };
703 + }