KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > idaremedia > antx > solo > ExportTask


1 /**
2  * $Id: ExportTask.java 180 2007-03-15 12:56:38Z ssmc $
3  * Copyright 2002-2004 iDare Media, Inc. All rights reserved.
4  *
5  * Originally written by iDare Media, Inc. for release into the public domain. This
6  * library, source form and binary form, is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License as published by the
8  * Free Software Foundation; either version 2.1 of the License, or (at your option) any
9  * later version.<p>
10  *
11  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU LGPL (GNU Lesser General Public License) for more details.<p>
14  *
15  * You should have received a copy of the GNU Lesser General Public License along with this
16  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite
17  * 330, Boston, MA 02111-1307 USA. The LGPL can be found online at
18  * http://www.fsf.org/copyleft/lesser.html<p>
19  *
20  * This product has been influenced by several projects within the open-source community.
21  * The JWare developers wish to acknowledge the open-source community's support. For more
22  * information regarding the open-source products used within JWare, please visit the
23  * JWare website.
24  *----------------------------------------------------------------------------------------*
25  * WEBSITE- http://www.jware.info EMAIL- inquiries@jware.info
26  *----------------------------------------------------------------------------------------*
27  **/

28
29 package com.idaremedia.antx.solo;
30
31 import java.text.DecimalFormat JavaDoc;
32
33 import org.apache.tools.ant.BuildException;
34 import org.apache.tools.ant.Project;
35
36 import com.idaremedia.antx.AntX;
37 import com.idaremedia.antx.AssertableTask;
38 import com.idaremedia.antx.ExportScope;
39 import com.idaremedia.antx.FlexString;
40 import com.idaremedia.antx.apis.AntLibFriendly;
41 import com.idaremedia.antx.helpers.Tk;
42 import com.idaremedia.antx.parameters.TransformEnabled;
43 import com.idaremedia.antx.parameters.TransformHelper;
44 import com.idaremedia.antx.parameters.ValueTransform;
45
46 /**
47  * Helper task that manipulates a {@linkplain com.idaremedia.antx.ExportedProperties
48  * modifiable property}. Intended for unit tests and other controlled build environments.
49  * When combined with assertions can make test build files almost auto-testing.
50  * <p>
51  * <b>Example Usage:</b><pre>
52  * &lt;assign var="loopcount" value="0"/&gt;
53  * &lt;assign var="loopcount" op="++"/&gt;
54  * &lt;assign var="__bn" fromproperty="build.number"/&gt;
55  * &lt;assign var="num.changes" op="+" value="${diff.count}"/&gt;
56  * &lt;assign var="num.changes" copyproperty="__loop.num.changes"/&gt;
57  * &lt;assign var="time" op="now"/&gt;
58  * &lt;assign var="duration" op="-now" fromvariable="time"/&gt;
59  * &lt;assign var="time" op="-now"/&gt;
60  * &lt;assign var="totaltime" op="+" fromvariable="duration"/&gt;
61  * </pre>
62  *
63  * @since JWare/AntX 0.1
64  * @author ssmc, &copy;2002-2004 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
65  * @version 0.5
66  * @.safety single
67  * @.group api,helper
68  * @see ImportTask
69  **/

70
71 public class ExportTask extends AssertableTask
72     implements TransformEnabled, AntLibFriendly
73 {
74     private static final String JavaDoc SRC_ATTRS = "value|fromproperty|fromvariable";
75
76 // ---------------------------------------------------------------------------------------
77
// Construction:
78
// ---------------------------------------------------------------------------------------
79

80     /**
81      * Initializes a new export task instance.
82      **/

83     public ExportTask()
84     {
85         super(AntX.nopackage);
86     }
87
88
89     /**
90      * Initializes a new CV-labeled export task instance.
91      **/

92     public ExportTask(String JavaDoc iam)
93     {
94         super(iam);
95     }
96
97
98     /**
99      * Initializes this task's project.
100      **/

101     public void setProject(Project project)
102     {
103         super.setProject(project);
104         m_value.setProject(project);
105     }
106
107
108 // ---------------------------------------------------------------------------------------
109
// Parameters:
110
// ---------------------------------------------------------------------------------------
111

112     /**
113      * Sets this export task's effective scope. Value must be one
114      * of "<i>project</i>","<i>thread</i>", or "<i>all</i>". Defaults
115      * to "<i>thread</i>".
116      * @since JWare/AntX 0.2
117      **/

118     public void setScope(ExportScope scope)
119     {
120         require_(scope!=null,"setScop- nonzro");
121         m_scope = scope;
122     }
123
124
125     /**
126      * Returns this export task's effective scope. Never returns
127      * <i>null</i>; defaults to "<i>thread</i>".
128      * @since JWare/AntX 0.2
129      **/

130     public final ExportScope getScope()
131     {
132         return m_scope;
133     }
134
135
136     /**
137      * Sets this export task's modifiable property name.
138      * @param name property's name (non-null)
139      **/

140     public void setName(String JavaDoc name)
141     {
142         require_(!Tk.isWhitespace(name),"setNam- nonwspc name");
143         m_name = name;
144     }
145
146
147     /**
148      * Synonym for {@linkplain #setName setName}.
149      **/

150     public final void setVar(String JavaDoc name)
151     {
152         setName(name);
153     }
154
155
156     /**
157      * Returns this export task's property's name. Will return
158      * <i>null</i> if never set.
159      **/

160     public final String JavaDoc getName()
161     {
162         return m_name;
163     }
164
165
166     /**
167      * Sets this export task's new value as a literal as-is string.
168      * @param value new value (non-null)
169      * @see #setOp
170      **/

171     public void setValue(String JavaDoc value)
172     {
173         require_(value!=null,"setValu- nonzro valu");
174         m_value.set(value);
175         m_value.setIsLiteral();
176     }
177
178
179     /**
180      * Sets this export task's new value from a property's value.
181      * @param property property's name (non-null)
182      * @since JWare/AntX 0.3
183      **/

184     public void setFromProperty(String JavaDoc property)
185     {
186         require_(property!=null,"setFromProp- nonzro name");
187         m_value.set(property);
188         m_value.setIsProperty(true);
189     }
190
191
192     /**
193      * Sets this export task's new value from another variable's
194      * value. The source variable is assumed in the thread-scope.
195      * @param variable variable's name (non-null)
196      * @since JWare/AntX 0.3
197      **/

198     public void setFromVariable(String JavaDoc variable)
199     {
200         require_(variable!=null,"setFromVar- nonzro name");
201         m_value.set(variable);
202         m_value.setIsExported(true);
203     }
204
205
206     /**
207      * Synonym for {@linkplain #setFromVariable setFromVariable}.
208      * @since JWare/AntX 0.4
209      **/

210     public final void setFromVar(String JavaDoc variable)
211     {
212         setFromVariable(variable);
213     }
214
215
216     /**
217      * Returns this export task's source value. Can return <i>null</i>
218      * if this task's source was never defined or source is missing.
219      * The returned value represents a literal ({@linkplain #setValue
220      * value}), a property's value ({@linkplain #setFromProperty
221      * fromproperty}), or another variable's value ({@linkplain
222      * #setFromVariable fromvariable}).
223      **/

224     public final String JavaDoc getValue()
225     {
226         return m_value.getValue();
227     }
228
229
230     /**
231      * Changes this export task's default <i>assign</i> operation.
232      * @param op required modification (non-null)
233      **/

234     public final void setOp(Modification op)
235     {
236         require_(op!=null,"setModf- nonzro op");
237         m_Op= op;
238     }
239
240
241     /**
242      * Returns this export task's modification operation. Never
243      * returns <i>null</i>. Defaults to simple assignment.
244      **/

245     public final Modification getOp()
246     {
247         return m_Op;
248     }
249
250
251     /**
252      * Sets the value transform for the value copied to
253      * the variable.
254      * @since JWare/AntX 0.4
255      **/

256     public final void setTransform(ValueTransform t)
257     {
258         m_T = t==null ? null : ValueTransform.from(t.getIndex());//normalize
259
}
260
261
262     /**
263      * Returns the value transformation this task will
264      * perform on the to-be-copied value. Will return
265      * {@linkplain ValueTransform#NONE} if never set.
266      * @since JWare/AntX 0.4
267      **/

268     public final ValueTransform getTransform()
269     {
270         return m_T==null ? ValueTransform.NONE : m_T;
271     }
272
273
274
275     /**
276      * Sets a name for a regular property to be updated with new
277      * exported property's value. This update is done <em>in
278      * addition</em> to the exported property's update.
279      * @param property property's name (non-null)
280      **/

281     public void setCopyProperty(String JavaDoc property)
282     {
283         require_(property!=null,"setP- nonzro propnam");
284         m_copyProperty = property;
285     }
286
287
288     /**
289      * Returns name of regular property to be updated in
290      * addition to the exported property. Returns <i>null</i>
291      * if not set.
292      **/

293     public final String JavaDoc getCopyProperty()
294     {
295         return m_copyProperty;
296     }
297
298 // ---------------------------------------------------------------------------------------
299
// Managing Modifiable Variable:
300
// ---------------------------------------------------------------------------------------
301

302     /**
303      * Returns <i>true</i> if this task's source (value) has
304      * not be explicitly defined.
305      * @since JWare/AntX 0.3
306      **/

307     protected final boolean isUndefined()
308     {
309         return m_value.isUndefined();
310     }
311
312
313     /**
314      * Updates the modifiable property with given value. What
315      * this method actually effects depends on this task's scope.
316      * @see ExportScope#setTheProperty ExportScope
317      **/

318     protected final void setTheProperty(String JavaDoc value)
319     {
320         ExportScope.setTheProperty(getScope(),getProject(),getName(),
321                                    value,true);
322     }
323
324
325     /**
326      * Returns the modifiable property's current value. Can return
327      * <i>null</i> if property never set.
328      * @see ExportScope#getTheProperty ExportScope
329      **/

330     protected final String JavaDoc getTheProperty()
331     {
332         return ExportScope.getTheProperty(getScope(),getProject(),
333                                           getName());
334     }
335
336
337     /**
338      * Sets a cached predetermined value for this task. This allows
339      * pre-checks to cache values w/o changing the task's formal
340      * definition.
341      * @since JWare/AntX 0.3
342      **/

343     protected final void setShortcutValue(String JavaDoc value)
344     {
345         m_shortcutValue = value;
346     }
347
348
349     /**
350      * Ensures auto-assigned delta values for certain modification
351      * are defined; for example, "++" is shorthand for an increase of
352      * one.
353      **/

354     protected void fixDefaults()
355     {
356         if (isUndefined()) {
357             int op= getOp().getIndex();
358             switch (op) {
359                 case Modification.INC_BY1_INDEX:
360                 case Modification.DEC_BY1_INDEX: {
361                     setShortcutValue("1");
362                     break;
363                 }
364                 //JWare/AntX 0.3
365
case Modification.NOW_INDEX:
366                 case Modification.MINUS_NOW_INDEX: {
367                     setShortcutValue(String.valueOf(System.currentTimeMillis()));
368                     break;
369                 }
370             }
371         }
372     }
373
374
375     /**
376      * Returns the initializing variable value. Defaults to a zero
377      * Long. Could be different for typed variables; for instance
378      * a timestamp might return the current system time.
379      * @param like [optional] hint about the type of operation
380      * value to be used in
381      * @since JWare/AntX 0.2
382      **/

383     protected Number JavaDoc initialValue(Number JavaDoc like)
384     {
385         if (like instanceof Double JavaDoc) {
386             return INITIAL_NUMF;
387         }
388         return INITIAL_NUMI;
389     }
390
391
392     /**
393      * Returns any predetermined value for this task. This allows
394      * pre-checks to cache values w/o changing the task's attribute
395      * definitions.
396      * @since JWare/AntX 0.3
397      **/

398     protected String JavaDoc shortcutValue()
399     {
400         return m_shortcutValue;
401     }
402
403
404     /**
405      * Returns the value with which this task should operate. Takes
406      * any cached shortcut values and/or flex conversion into acccount.
407      * @see #getValue
408      * @see #shortcutValue
409      * @since JWare/AntX 0.3
410      **/

411     protected String JavaDoc getWorkValue()
412     {
413         String JavaDoc value = shortcutValue();
414         if (value==null) {
415             value = getValue();
416         }
417         return value;
418     }
419
420
421
422     /**
423      * Applies any value transformation instruction(s) to the given
424      * value. Extension point; by default we let another task like
425      * {@linkplain CopyPropertyTask} do transformation work.
426      * @param value [optional the value to be transformed
427      * @param numberValue [optional] the numeric value to be transformed
428      * @return the transformed value or same if no transformation necessary
429      * @since JWare/AntX 0.4
430      **/

431     protected String JavaDoc getExportValue(String JavaDoc value, Number JavaDoc numberValue)
432     {
433         if (value==null) {
434             // NB: do what most people expect in terms of float formatting!
435
if (m_T==ValueTransform.DECIMAL) {
436                 synchronized(DFI) {
437                     return DFI.format(numberValue);
438                 }
439             }
440             value = numberValue.toString();
441         }
442         if (m_T!=null) {
443             value = TransformHelper.apply(m_T,value,getProject());
444         }
445         return value;
446     }
447
448
449
450     /**
451      * Ensures this task is in a valid project and has an assigned
452      * value.
453      * @throws BuildException if value not defined
454      **/

455     protected void verifyCanExecute_(String JavaDoc calr)
456     {
457         verifyInProject_(calr);
458
459         if (getName()==null) {
460             String JavaDoc ermsg = uistrs().get("task.needs.name",getTaskName());
461             log(ermsg, Project.MSG_ERR);
462             throw new BuildException(ermsg,getLocation());
463         }
464
465         fixDefaults();
466
467         if (isUndefined() && shortcutValue()==null) {
468             if (getCopyProperty()!=null &&
469                 getOp().getIndex()==Modification.SET_INDEX) {//justCopy
470
return;
471             }
472             String JavaDoc ermsg = uistrs().get
473                 ("task.needs.this.attr",getTaskName(),SRC_ATTRS);
474             log(ermsg, Project.MSG_ERR);
475             throw new BuildException(ermsg,getLocation());
476         }
477     }
478
479
480
481     /**
482      * Performs a delta operation on the existing property value (which
483      * must be either undefined or a valid number).
484      * @param negate <i>true</i> if operation is a decrement
485      * @throws BuildException if either the current value or the delta
486      * value are not valid numbers
487      **/

488     protected void doDeltaOperation(boolean negate)
489     {
490         String JavaDoc value = getWorkValue();
491         Number JavaDoc delta = Tk.numberFrom(value);
492         if (delta==Tk.NO_NUM_NUM) {
493             String JavaDoc ermsg = uistrs().get("export.value.NAN",value);
494             log(ermsg, Project.MSG_ERR);
495             throw new BuildException(ermsg, getLocation());
496         }
497
498         String JavaDoc oldvalue = getTheProperty();
499         Number JavaDoc current;
500         if (oldvalue!=null) {
501             current = Tk.numberFrom(oldvalue);
502         } else {
503             current = initialValue(delta);//!?
504
}
505         if (current==Tk.NO_NUM_NUM) {
506             String JavaDoc ermsg = uistrs().get("export.current.NAN",getName(),oldvalue);
507             log(ermsg, Project.MSG_ERR);
508             throw new BuildException(ermsg, getLocation());
509         }
510         
511         if (current instanceof Double JavaDoc || delta instanceof Double JavaDoc) {
512             double delta_ = delta.doubleValue();
513             if (negate) {
514                 delta_ = -delta_;
515             }
516             current = new Double JavaDoc(current.doubleValue()+delta_);
517         } else {
518             long delta_ = delta.longValue();
519             if (negate) {
520                 delta_ = -delta_;
521             }
522             current = new Long JavaDoc(current.longValue()+delta_);
523         }
524         setTheProperty(getExportValue(null,current));
525     }
526
527
528
529     /**
530      * Performs either of two string-specific operations (len or
531      * strcat).
532      * @since JWare/AntX 0.5
533      **/

534     protected void doStringOperation()
535     {
536         String JavaDoc value = null;
537         int opI= getOp().getIndex();
538         if (opI==Modification.STRLEN_INDEX) {
539             value = String.valueOf(getWorkValue().length());
540         }
541         else if (opI==Modification.STRCAT_INDEX) {
542             value = getTheProperty();
543             if (value==null) {
544                 value = "";
545             }
546             value = value + getWorkValue();
547         }
548         setTheProperty(getExportValue(value,null));
549     }
550
551
552
553
554     /**
555      * Performs the assignment operation of the current value to
556      * the exported variable.
557      * @since JWare/AntX 0.3
558      **/

559     protected void doAssignOperation()
560     {
561         String JavaDoc value = getWorkValue();
562         if (value==null) {
563             String JavaDoc ermsg = uistrs().get("export.value.undefined",m_value.get());
564             log(ermsg,Project.MSG_ERR);
565             throw new BuildException(ermsg,getLocation());
566         }
567         setTheProperty(getExportValue(value,Tk.NO_NUM_NUM));
568     }
569
570
571
572     /**
573      * Returns <i>true</i> if is just copy to property operation.
574      **/

575     private boolean isJustCopy()
576     {
577         return isUndefined() &&
578             shortcutValue()==null &&
579             getCopyProperty()!=null;
580     }
581
582
583
584     /**
585      * Modifies this task's named property according to operation
586      * and value definitions.
587      * @throws BuildException if invalid parameters or current value
588      * cannot be modified in manner requested
589      **/

590     public void execute() throws BuildException
591     {
592         verifyCanExecute_("execute");
593
594         if (isJustCopy()) {
595             getProject().setNewProperty(getCopyProperty(),
596                               getExportValue(getTheProperty(),Tk.NO_NUM_NUM));
597             return;
598         }
599
600         switch (getOp().getIndex()) {
601             case Modification.NOW_INDEX: {
602                 if (!isUndefined()) {
603                     String JavaDoc warning = uistrs().get
604                         ("task.one.or.other.attr", "now", SRC_ATTRS);
605                     log(warning, Project.MSG_WARN);
606                 }
607                 //+fall-through to assign
608
}
609             case Modification.SET_INDEX: {
610                 doAssignOperation();
611                 break;
612             }
613             case Modification.MINUS_NOW_INDEX: {
614                 if (!isUndefined()) {
615                     Number JavaDoc from = Tk.numberFrom(getValue());
616                     if (from!=Tk.NO_NUM_NUM) {
617                         long diff = System.currentTimeMillis() - from.longValue();
618                         if (diff<0) {
619                             from= Tk.NO_NUM_NUM;
620                         } else {
621                             setShortcutValue(String.valueOf(diff));
622                             doAssignOperation();
623                             break;
624                         }
625                     }
626                     if (from==Tk.NO_NUM_NUM) {
627                         String JavaDoc ermsg = uistrs().get("export.value.NAN",m_value.get());
628                         log(ermsg, Project.MSG_ERR);
629                         throw new BuildException(ermsg, getLocation());
630                     }
631                 }
632                 doDeltaOperation(true);
633                 break;
634             }
635             case Modification.INC_INDEX:
636             case Modification.INC_BY1_INDEX: {
637                 doDeltaOperation(false);
638                 break;
639             }
640             case Modification.DEC_INDEX:
641             case Modification.DEC_BY1_INDEX: {
642                 doDeltaOperation(true);
643                 break;
644             }
645             default: {
646                 doStringOperation();
647                 break;
648             }
649         }
650
651         if (getCopyProperty()!=null) {
652             getProject().setNewProperty(getCopyProperty(), getTheProperty());
653         }
654     }
655
656
657     private static final Long JavaDoc INITIAL_NUMI= new Long JavaDoc(0);
658     private static final Double JavaDoc INITIAL_NUMF= new Double JavaDoc(0.0f);
659     private static final DecimalFormat JavaDoc DFI = new DecimalFormat JavaDoc("#.###");//NB:90+% expects
660

661     private String JavaDoc m_name;
662     private FlexString m_value = new FlexString();
663     private String JavaDoc m_copyProperty;
664     private Modification m_Op= Modification.SET;
665     private ExportScope m_scope= ExportScope.DEFAULT_SCOPE;
666     private String JavaDoc m_shortcutValue;
667     private ValueTransform m_T;//NB: none-by-default
668
}
669
670 /* end-of-ExportTask.java */
671
Popular Tags