Subversion Repository Public Repository

litesoft

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

Diff revisions: vs.
  @@ -1,883 +1,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 - {
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 + {
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 + }