summaryrefslogtreecommitdiff
path: root/projects/net.wotonomy.web/src/main/java
diff options
context:
space:
mode:
authorBenjamin Culkin <scorpress@gmail.com>2024-05-20 17:58:16 -0400
committerBenjamin Culkin <scorpress@gmail.com>2024-05-20 17:58:16 -0400
commit40a9d99496e098562f090fb7ffce9e749011b131 (patch)
tree437df24d65470582e943e494a52db8ed65a881ae /projects/net.wotonomy.web/src/main/java
parentff072dfe782f6f22123cd4ba050828d35c0d0fbd (diff)
Formatting pass
Diffstat (limited to 'projects/net.wotonomy.web/src/main/java')
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/ObservableArray.java488
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/URI.java6836
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionResults.java38
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionURL.java39
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActiveImage.java115
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOApplication.java2021
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOAssociation.java236
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOBody.java150
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCheckBox.java124
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponent.java2118
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentContent.java27
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentRequestHandler.java340
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOConditional.java131
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOContext.java929
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCookie.java314
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectAction.java440
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectActionRequestHandler.java322
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java4219
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODynamicElement.java339
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOElement.java115
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOForm.java181
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOFrame.java99
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericContainer.java61
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericElement.java114
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHiddenField.java19
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHyperlink.java408
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImage.java277
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImageButton.java78
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOInput.java135
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMailDelivery.java52
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMessage.java354
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOParentElement.java258
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPasswordField.java18
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPopUpButton.java251
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORadioButton.java18
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORepetition.java295
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequest.java1003
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequestHandler.java59
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResetButton.java33
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java776
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceRequestHandler.java150
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceURL.java38
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResponse.java235
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOServletSessionStore.java262
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSession.java918
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSessionStore.java118
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOStaticElement.java68
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOString.java173
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSubmitButton.java77
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSwitchComponent.java160
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOText.java52
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOTextField.java63
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/util/BrowserLauncher.java1242
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoder.java146
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java663
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCEncoder.java840
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCReceiver.java77
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCSelector.java320
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java423
59 files changed, 14030 insertions, 15825 deletions
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/ObservableArray.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/ObservableArray.java
index cef1372..1c91115 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/ObservableArray.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/ObservableArray.java
@@ -28,324 +28,272 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSRange;
/**
-* A package class that extends NSMutableArray but makes use
-* of the fact that wotonomy's implementation extends ArrayList
-* to intercept insertions and deletion and register and
-* unregister objects for change notifications as appropriate.
-* Since we can't be sure of ArrayList's implementation, we're
-* forced to override each and every add and remove method,
-* some of which probably call each other. However,
-* EOObserverCenter will only register us once per object.
-*/
-class ObservableArray extends NSMutableArray
-{
- EOObserving observer;
-
- ObservableArray( EOObserving anObserver )
- {
- observer = anObserver;
- }
-
+ * A package class that extends NSMutableArray but makes use of the fact that
+ * wotonomy's implementation extends ArrayList to intercept insertions and
+ * deletion and register and unregister objects for change notifications as
+ * appropriate. Since we can't be sure of ArrayList's implementation, we're
+ * forced to override each and every add and remove method, some of which
+ * probably call each other. However, EOObserverCenter will only register us
+ * once per object.
+ */
+class ObservableArray extends NSMutableArray {
+ EOObserving observer;
+
+ ObservableArray(EOObserving anObserver) {
+ observer = anObserver;
+ }
+
/**
- * Removes the last object from the array.
- */
- public void removeLastObject ()
- {
- remove( count() - 1 );
- }
+ * Removes the last object from the array.
+ */
+ public void removeLastObject() {
+ remove(count() - 1);
+ }
/**
- * Removes the object at the specified index.
- */
- public void removeObjectAtIndex (int index)
- {
- remove( index );
- }
+ * Removes the object at the specified index.
+ */
+ public void removeObjectAtIndex(int index) {
+ remove(index);
+ }
/**
- * Adds all objects in the specified collection.
- */
- public void addObjectsFromArray (Collection aCollection)
- {
- addAll( aCollection );
- }
+ * Adds all objects in the specified collection.
+ */
+ public void addObjectsFromArray(Collection aCollection) {
+ addAll(aCollection);
+ }
/**
- * Removes all objects from the array.
- */
- public void removeAllObjects ()
- {
- clear();
- }
+ * Removes all objects from the array.
+ */
+ public void removeAllObjects() {
+ clear();
+ }
/**
- * Removes all objects equivalent to the specified object
- * within the range of specified indices.
- */
- public void removeObject (Object anObject, NSRange aRange)
- {
- if ( ( anObject == null ) || ( aRange == null ) ) return;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject.equals( get( i ) ) )
- {
- remove( i );
- i = i - 1;
- max = max - 1;
- }
- }
- }
+ * Removes all objects equivalent to the specified object within the range of
+ * specified indices.
+ */
+ public void removeObject(Object anObject, NSRange aRange) {
+ if ((anObject == null) || (aRange == null))
+ return;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject.equals(get(i))) {
+ remove(i);
+ i = i - 1;
+ max = max - 1;
+ }
+ }
+ }
/**
- * Removes all instances of the specified object within the
- * range of specified indices, comparing by reference.
- */
- public void removeIdenticalObject (Object anObject, NSRange aRange)
- {
- if ( ( anObject == null ) || ( aRange == null ) ) return;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject == get( i ) )
- {
- remove( i );
- i = i - 1;
- max = max - 1;
- }
- }
- }
+ * Removes all instances of the specified object within the range of specified
+ * indices, comparing by reference.
+ */
+ public void removeIdenticalObject(Object anObject, NSRange aRange) {
+ if ((anObject == null) || (aRange == null))
+ return;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject == get(i)) {
+ remove(i);
+ i = i - 1;
+ max = max - 1;
+ }
+ }
+ }
/**
- * Removes all objects in the specified collection from the array.
- */
- public void removeObjectsInArray (Collection aCollection)
- {
- removeAll( aCollection );
- }
+ * Removes all objects in the specified collection from the array.
+ */
+ public void removeObjectsInArray(Collection aCollection) {
+ removeAll(aCollection);
+ }
/**
- * Removes all objects in the indices within the specified range
- * from the array.
- */
- public void removeObjectsInRange (NSRange aRange)
- {
- if ( aRange == null ) return;
-
- for ( int i = 0; i < aRange.length(); i++ )
- {
- remove( aRange.location() );
- }
- }
+ * Removes all objects in the indices within the specified range from the array.
+ */
+ public void removeObjectsInRange(NSRange aRange) {
+ if (aRange == null)
+ return;
+
+ for (int i = 0; i < aRange.length(); i++) {
+ remove(aRange.location());
+ }
+ }
/**
- * Replaces objects in the current range with objects from
- * the specified range of the specified array. If currentRange
- * is larger than otherRange, the extra objects are removed.
- * If otherRange is larger than currentRange, the extra objects
- * are added.
- */
- public void replaceObjectsInRange (NSRange currentRange,
- List otherArray, NSRange otherRange)
- {
- if ( ( currentRange == null ) || ( otherArray == null ) ||
- ( otherRange == null ) ) return;
-
+ * Replaces objects in the current range with objects from the specified range
+ * of the specified array. If currentRange is larger than otherRange, the extra
+ * objects are removed. If otherRange is larger than currentRange, the extra
+ * objects are added.
+ */
+ public void replaceObjectsInRange(NSRange currentRange, List otherArray, NSRange otherRange) {
+ if ((currentRange == null) || (otherArray == null) || (otherRange == null))
+ return;
+
// transform otherRange if out of bounds for array
- if ( otherRange.maxRange() > otherArray.size() )
- {
+ if (otherRange.maxRange() > otherArray.size()) {
// TODO: Test this logic.
- int loc = Math.min( otherRange.location(), otherArray.size() - 1 );
- otherRange = new NSRange( loc, otherArray.size() - loc );
+ int loc = Math.min(otherRange.location(), otherArray.size() - 1);
+ otherRange = new NSRange(loc, otherArray.size() - loc);
}
-
+
Object o;
- List subList = subList(
- currentRange.location(), currentRange.maxRange() );
+ List subList = subList(currentRange.location(), currentRange.maxRange());
int otherIndex = otherRange.location();
// TODO: Test this logic.
- for ( int i = 0; i < subList.size(); i++ )
- {
- if ( otherIndex < otherRange.maxRange() )
- { // set object
- subList.set( i, otherArray.get( otherIndex ) );
- }
- else
- { // remove extra elements from currentRange
- subList.remove( i );
- i--;
+ for (int i = 0; i < subList.size(); i++) {
+ if (otherIndex < otherRange.maxRange()) { // set object
+ subList.set(i, otherArray.get(otherIndex));
+ } else { // remove extra elements from currentRange
+ subList.remove(i);
+ i--;
}
otherIndex++;
}
// TODO: Test this logic.
- for ( int i = otherIndex; i < otherRange.maxRange(); i++ )
- {
- add( otherArray.get( i ) );
+ for (int i = otherIndex; i < otherRange.maxRange(); i++) {
+ add(otherArray.get(i));
}
}
/**
- * Clears the current array and then populates it with the
- * contents of the specified collection.
- */
- public void setArray (Collection aCollection)
- {
- clear();
- addAll( aCollection );
- }
+ * Clears the current array and then populates it with the contents of the
+ * specified collection.
+ */
+ public void setArray(Collection aCollection) {
+ clear();
+ addAll(aCollection);
+ }
/**
- * Removes all objects equivalent to the specified object.
- */
- public void removeObject (Object anObject)
- {
- remove( anObject );
- }
+ * Removes all objects equivalent to the specified object.
+ */
+ public void removeObject(Object anObject) {
+ remove(anObject);
+ }
/**
- * Removes all occurences of the specified object,
- * comparing by reference.
- */
- public void removeIdenticalObject (Object anObject)
- {
- EOObserverCenter.removeObserver( observer, anObject );
- super.removeIdenticalObject( anObject );
- }
+ * Removes all occurences of the specified object, comparing by reference.
+ */
+ public void removeIdenticalObject(Object anObject) {
+ EOObserverCenter.removeObserver(observer, anObject);
+ super.removeIdenticalObject(anObject);
+ }
/**
- * Inserts the specified object into this array at the
- * specified index.
- */
- public void insertObjectAtIndex (Object anObject, int anIndex)
- {
- add( anIndex, anObject );
- }
-
+ * Inserts the specified object into this array at the specified index.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ add(anIndex, anObject);
+ }
+
/**
- * Replaces the object at the specified index with the
- * specified object.
- */
- public void replaceObjectAtIndex (int anIndex, Object anObject)
- {
- set( anIndex, anObject );
- }
+ * Replaces the object at the specified index with the specified object.
+ */
+ public void replaceObjectAtIndex(int anIndex, Object anObject) {
+ set(anIndex, anObject);
+ }
/**
- * Adds the specified object to the end of this array.
- */
- public void addObject (Object anObject)
- {
- add( anObject );
- }
-
- // interface List: mutators
-
- public void add(int index, Object element)
- {
- EOObserverCenter.addObserver( observer, element );
- super.add( index, element );
- }
-
- public boolean add(Object o)
- {
- EOObserverCenter.addObserver( observer, o );
- return super.add(o);
- }
-
- public boolean addAll(Collection coll)
- {
- Iterator it = coll.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.addObserver( observer, it.next() );
- }
- return super.addAll(coll);
- }
-
- public boolean addAll(int index, Collection c)
- {
- Iterator it = c.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.addObserver( observer, it.next() );
- }
- return super.addAll( index, c );
- }
-
- public void clear()
- {
- Iterator it = iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.removeObserver( observer, it.next() );
- }
- super.clear();
- }
-
- public Object remove(int index)
- {
- EOObserverCenter.removeObserver( observer, get(index) );
- return super.remove( index );
- }
-
- public boolean remove(Object o)
- {
- EOObserverCenter.removeObserver( observer, o );
- return super.remove(o);
- }
-
- public boolean removeAll(Collection coll)
- {
- Iterator it = coll.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.removeObserver( observer, it.next() );
- }
- return super.removeAll(coll);
- }
-
- public boolean retainAll(Collection coll)
- {
- throw new UnsupportedOperationException();
- }
-
- public Object set(int index, Object element)
- {
- EOObserverCenter.removeObserver( observer, get(index) );
- EOObserverCenter.addObserver( observer, element );
- return super.set( index, element );
- }
+ * Adds the specified object to the end of this array.
+ */
+ public void addObject(Object anObject) {
+ add(anObject);
+ }
+
+ // interface List: mutators
+
+ public void add(int index, Object element) {
+ EOObserverCenter.addObserver(observer, element);
+ super.add(index, element);
+ }
+
+ public boolean add(Object o) {
+ EOObserverCenter.addObserver(observer, o);
+ return super.add(o);
+ }
+
+ public boolean addAll(Collection coll) {
+ Iterator it = coll.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.addObserver(observer, it.next());
+ }
+ return super.addAll(coll);
+ }
+
+ public boolean addAll(int index, Collection c) {
+ Iterator it = c.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.addObserver(observer, it.next());
+ }
+ return super.addAll(index, c);
+ }
+
+ public void clear() {
+ Iterator it = iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.removeObserver(observer, it.next());
+ }
+ super.clear();
+ }
+
+ public Object remove(int index) {
+ EOObserverCenter.removeObserver(observer, get(index));
+ return super.remove(index);
+ }
+
+ public boolean remove(Object o) {
+ EOObserverCenter.removeObserver(observer, o);
+ return super.remove(o);
+ }
+
+ public boolean removeAll(Collection coll) {
+ Iterator it = coll.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.removeObserver(observer, it.next());
+ }
+ return super.removeAll(coll);
+ }
+
+ public boolean retainAll(Collection coll) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object set(int index, Object element) {
+ EOObserverCenter.removeObserver(observer, get(index));
+ EOObserverCenter.addObserver(observer, element);
+ return super.set(index, element);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/01/18 23:31:32 mpowers
- * Needed for WODisplayGroup.
+ * Revision 1.1 2003/01/18 23:31:32 mpowers Needed for WODisplayGroup.
*
- * Revision 1.2 2002/10/24 21:15:36 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.2 2002/10/24 21:15:36 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.1 2001/02/20 16:38:55 mpowers
- * MasterDetailAssociations now observe their controlled display group's
- * objects for changes to that the parent object will be marked as updated.
- * Before, only inserts and deletes to an object's items are registered.
- * Also, moved ObservableArray to package access.
+ * Revision 1.1 2001/02/20 16:38:55 mpowers MasterDetailAssociations now observe
+ * their controlled display group's objects for changes to that the parent
+ * object will be marked as updated. Before, only inserts and deletes to an
+ * object's items are registered. Also, moved ObservableArray to package access.
*
- * Revision 1.1 2001/01/24 14:37:24 mpowers
- * Contributing a delegate useful for debugging.
+ * Revision 1.1 2001/01/24 14:37:24 mpowers Contributing a delegate useful for
+ * debugging.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/URI.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/URI.java
index 41f77f5..ba608a4 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/URI.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/URI.java
@@ -59,7 +59,7 @@
*
* [Additional notices, if required by prior licensing conditions]
*
- */
+ */
// excellent class borrowed from Apache Commons project:
//package org.apache.commons.httpclient;
@@ -80,30 +80,39 @@ import sun.security.action.GetPropertyAction;
/**
* The interface for the URI(Uniform Resource Identifiers) version of RFC 2396.
* This class has the purpose of supportting of parsing a URI reference to
- * extend any specific protocols, the character encoding of the protocol to
- * be transported and the charset of the document.
+ * extend any specific protocols, the character encoding of the protocol to be
+ * transported and the charset of the document.
* <p>
* A URI is always in an "escaped" form, since escaping or unescaping a
- * completed URI might change its semantics.
+ * completed URI might change its semantics.
* <p>
- * Implementers should be careful not to escape or unescape the same string
- * more than once, since unescaping an already unescaped string might lead to
- * misinterpreting a percent data character as another escaped character,
- * or vice versa in the case of escaping an already escaped string.
+ * Implementers should be careful not to escape or unescape the same string more
+ * than once, since unescaping an already unescaped string might lead to
+ * misinterpreting a percent data character as another escaped character, or
+ * vice versa in the case of escaping an already escaped string.
* <p>
* In order to avoid these problems, data types used as follows:
- * <p><blockquote><pre>
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
* URI character sequence: char
* octet sequence: byte
* original character sequence: String
- * </pre></blockquote><p>
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
*
- * So, a URI is a sequence of characters as an array of a char type, which
- * is not always represented as a sequence of octets as an array of byte.
+ * So, a URI is a sequence of characters as an array of a char type, which is
+ * not always represented as a sequence of octets as an array of byte.
* <p>
*
* URI Syntactic Components
- * <p><blockquote><pre>
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
* - In general, written as follows:
* Absolute URI = &lt;scheme&gt:&lt;scheme-specific-part&gt;
* Generic URI = &lt;scheme&gt;://&lt;authority&gt;&lt;path&gt;?&lt;query&gt;
@@ -113,9 +122,13 @@ import sun.security.action.GetPropertyAction;
* hier_part = ( net_path | abs_path ) [ "?" query ]
* net_path = "//" authority [ abs_path ]
* abs_path = "/" path_segments
- * </pre></blockquote><p>
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
*
* The following examples illustrate URI that are in common use.
+ *
* <pre>
* ftp://ftp.is.co.za/rfc/rfc1808.txt
* -- ftp scheme for File Transfer Protocol services
@@ -130,11 +143,14 @@ import sun.security.action.GetPropertyAction;
* telnet://melvyl.ucop.edu/
* -- telnet scheme for interactive services via the TELNET Protocol
* </pre>
+ *
* Please, notice that there are many modifications from URL(RFC 1738) and
* relative URL(RFC 1808).
* <p>
* <b>The expressions for a URI</b>
- * <p><pre>
+ * <p>
+ *
+ * <pre>
* For escaped URI forms
* - URI(char[]) // constructor
* - char[] getRawXxx() // method
@@ -144,3321 +160,3489 @@ import sun.security.action.GetPropertyAction;
* For unescaped URI forms
* - URI(String) // constructor
* - String getXXX() // method
- * </pre><p>
+ * </pre>
+ * <p>
*
* @author <a href="mailto:jericho@apache.org">Sung-Gu</a>
- * @version $Revision: 905 $ $Date: 2002/03/14 15:14:01
+ * @version $Revision: 905 $ $Date: 2002/03/14 15:14:01
*/
class URI implements Cloneable, Comparable, Serializable {
-
- // ----------------------------------------------------------- Constructors
-
- protected URI() {
- }
-
- /**
- * Construct a URI as an escaped form of a character array.
- * An URI can be placed within double-quotes or angle brackets like
- * "http://test.com/" and &lt;http://test.com/&gt;
- *
- * @param escaped the URI character sequence
- * @exception IOException
- * @throws NullPointerException if <code>escaped</code> is <code>null</code>
- */
- public URI(char[] escaped) throws IOException {
- parseUriReference(new String(escaped), true);
- }
-
-
- /**
- * Construct a URI from the given string.
- * <p><blockquote><pre>
- * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- * </pre></blockquote><p>
- * An URI can be placed within double-quotes or angle brackets like
- * "http://test.com/" and &lt;http://test.com/&gt;
- *
- * @param original the string to be represented to URI character sequence
- * It is one of absoluteURI and relativeURI.
- * @exception IOException
- */
- public URI(String original) throws IOException {
- parseUriReference(original, false);
- }
-
- /**
- * Construct a URI from a URL.
- *
- * @param url a valid URL.
- * @throws IOException
- * @since 2.0
- */
- public URI(URL url) throws IOException {
- this(url.toString());
- }
-
-
- /**
- * Construct a general URI from the given components.
- * <p><blockquote><pre>
- * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- * absoluteURI = scheme ":" ( hier_part | opaque_part )
- * opaque_part = uric_no_slash *uric
- * </pre></blockquote><p>
- * It's for absolute URI = &lt;scheme&gt;:&lt;scheme-specific-part&gt;#
- * &lt;fragment&gt;.
- *
- * @param scheme the scheme string
- * @param scheme_specific_part scheme_specific_part
- * @param fragment the fragment string
- * @exception IOException
- */
- public URI(String scheme, String scheme_specific_part, String fragment)
- throws IOException {
-
- // validate and contruct the URI character sequence
- if (scheme == null) {
- throw new IOException(/*IOException.PARSING,*/ "URI: scheme required");
- }
- char[] s = scheme.toLowerCase().toCharArray();
- if (validate(s, URI.scheme)) {
- _scheme = s; // is_absoluteURI
- } else {
- throw new IOException(/*IOException.PARSING,*/ "URI: incorrect scheme");
- }
- _opaque = encode(scheme_specific_part, allowed_opaque_part);
- // Set flag
- _is_opaque_part = true;
- setUriReference();
- }
-
-
- /**
- * Construct a general URI from the given components.
- * <p><blockquote><pre>
- * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- * absoluteURI = scheme ":" ( hier_part | opaque_part )
- * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- * hier_part = ( net_path | abs_path ) [ "?" query ]
- * </pre></blockquote><p>
- * It's for absolute URI = &lt;scheme&gt;:&lt;path&gt;?&lt;query&gt;#&lt;
- * fragment&gt; and relative URI = &lt;path&gt;?&lt;query&gt;#&lt;fragment
- * &gt;.
- *
- * @param scheme the scheme string
- * @param authority the authority string
- * @param path the path string
- * @param query the query string
- * @param fragment the fragment string
- * @exception IOException
- */
- public URI(String scheme, String authority, String path, String query,
- String fragment) throws IOException {
-
- // validate and contruct the URI character sequence
- StringBuffer buff = new StringBuffer();
- if (scheme != null) {
- buff.append(scheme);
- buff.append(':');
- }
- if (authority != null) {
- buff.append("//");
- buff.append(authority);
- }
- if (path != null) { // accept empty path
- if ((scheme != null || authority != null)
- && !path.startsWith("/")) {
- throw new IOException(/*IOException.PARSING*,*/
- "URI: abs_path requested");
- }
- buff.append(path);
- }
- if (query != null) {
- buff.append('?');
- buff.append(query);
- }
- if (fragment != null) {
- buff.append('#');
- buff.append(fragment);
- }
- parseUriReference(buff.toString(), false);
- }
-
-
- /**
- * Construct a general URI from the given components.
- *
- * @param scheme the scheme string
- * @param userinfo the userinfo string
- * @param host the host string
- * @param port the port number
- * @exception IOException
- */
- public URI(String scheme, String userinfo, String host, int port)
- throws IOException {
-
- this(scheme, userinfo, host, port, null, null, null);
- }
-
-
- /**
- * Construct a general URI from the given components.
- *
- * @param scheme the scheme string
- * @param userinfo the userinfo string
- * @param host the host string
- * @param port the port number
- * @param path the path string
- * @exception IOException
- */
- public URI(String scheme, String userinfo, String host, int port,
- String path) throws IOException {
-
- this(scheme, userinfo, host, port, path, null, null);
- }
-
-
- /**
- * Construct a general URI from the given components.
- *
- * @param scheme the scheme string
- * @param userinfo the userinfo string
- * @param host the host string
- * @param port the port number
- * @param path the path string
- * @param query the query string
- * @exception IOException
- */
- public URI(String scheme, String userinfo, String host, int port,
- String path, String query) throws IOException {
-
- this(scheme, userinfo, host, port, path, query, null);
- }
-
-
- /**
- * Construct a general URI from the given components.
- *
- * @param scheme the scheme string
- * @param userinfo the userinfo string
- * @param host the host string
- * @param port the port number
- * @param path the path string
- * @param query the query string
- * @param fragment the fragment string
- * @exception IOException
- */
- public URI(String scheme, String userinfo, String host, int port,
- String path, String query, String fragment) throws IOException {
-
- this(scheme, (host == null) ? null :
- ((userinfo != null) ? userinfo + '@' : "") + host +
- ((port != -1) ? ":" + port : ""), path, query, fragment);
- }
-
-
- /**
- * Construct a general URI from the given components.
- *
- * @param scheme the scheme string
- * @param host the host string
- * @param path the path string
- * @param fragment the fragment string
- * @exception IOException
- */
- public URI(String scheme, String host, String path, String fragment)
- throws IOException {
-
- this(scheme, host, path, null, fragment);
- }
-
-
- /**
- * Construct a general URI with the given relative URI string.
- *
- * @param base the base URI
- * @param relative the relative URI string
- * @exception IOException
- */
- public URI(URI base, String relative) throws IOException {
- this(base, new URI(relative));
- }
-
-
- /**
- * Construct a general URI with the given relative URI.
- * <p><blockquote><pre>
- * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- * </pre></blockquote><p>
- * Resolving Relative References to Absolute Form.
- *
- * <strong>Examples of Resolving Relative URI References</strong>
- *
- * Within an object with a well-defined base URI of
- * <p><blockquote><pre>
- * http://a/b/c/d;p?q
- * </pre></blockquote><p>
- * the relative URI would be resolved as follows:
- *
- * Normal Examples
- *
- * <p><blockquote><pre>
- * g:h = g:h
- * g = http://a/b/c/g
- * ./g = http://a/b/c/g
- * g/ = http://a/b/c/g/
- * /g = http://a/g
- * //g = http://g
- * ?y = http://a/b/c/?y
- * g?y = http://a/b/c/g?y
- * #s = (current document)#s
- * g#s = http://a/b/c/g#s
- * g?y#s = http://a/b/c/g?y#s
- * ;x = http://a/b/c/;x
- * g;x = http://a/b/c/g;x
- * g;x?y#s = http://a/b/c/g;x?y#s
- * . = http://a/b/c/
- * ./ = http://a/b/c/
- * .. = http://a/b/
- * ../ = http://a/b/
- * ../g = http://a/b/g
- * ../.. = http://a/
- * ../../ = http://a/
- * ../../g = http://a/g
- * </pre></blockquote><p>
- *
- * Some URI schemes do not allow a hierarchical syntax matching the
- * <hier_part> syntax, and thus cannot use relative references.
- *
- * @param base the base URI
- * @param relative the relative URI
- * @exception IOException
- */
- public URI(URI base, URI relative) throws IOException {
-
- if (base._scheme == null) {
- throw new IOException(/* IOException.PARSING,*/ "URI: base URI required");
- }
- if (base._scheme != null) {
- this._scheme = base._scheme;
- this._authority = base._authority;
- }
- if (base._is_opaque_part || relative._is_opaque_part) {
- this._scheme = base._scheme;
- this._is_opaque_part = relative._is_opaque_part;
- this._opaque = relative._opaque;
- this._fragment = relative._fragment;
- this.setUriReference();
- return;
- }
- if (relative._scheme != null) {
- this._scheme = relative._scheme;
- this._is_net_path = relative._is_net_path;
- this._authority = relative._authority;
- if (relative._is_server) {
- this._userinfo = relative._userinfo;
- this._host = relative._host;
- this._port = relative._port;
- } else if (relative._is_reg_name) {
- this._is_reg_name = relative._is_reg_name;
- }
- this._is_abs_path = relative._is_abs_path;
- this._is_rel_path = relative._is_rel_path;
- this._path = relative._path;
- } else if (base._authority != null && relative._scheme == null) {
- this._is_net_path = base._is_net_path;
- this._authority = base._authority;
- if (base._is_server) {
- this._userinfo = base._userinfo;
- this._host = base._host;
- this._port = base._port;
- } else if (base._is_reg_name) {
- this._is_reg_name = base._is_reg_name;
- }
- }
- if (relative._authority != null) {
- this._is_net_path = relative._is_net_path;
- this._authority = relative._authority;
- if (relative._is_server) {
- this._is_server = relative._is_server;
- this._userinfo = relative._userinfo;
- this._host = relative._host;
- this._port = relative._port;
- } else if (relative._is_reg_name) {
- this._is_reg_name = relative._is_reg_name;
- }
- this._is_abs_path = relative._is_abs_path;
- this._is_rel_path = relative._is_rel_path;
- this._path = relative._path;
- }
- // resolve the path
- if (relative._scheme == null && relative._authority == null ||
- equals(base._scheme, relative._scheme)) {
- this._path = resolvePath(base._path, relative._path);
- }
- // base._query removed
- if (relative._query != null) {
- this._query = relative._query;
- }
- // base._fragment removed
- if (relative._fragment != null) {
- this._fragment = relative._fragment;
- }
- this.setUriReference();
- }
-
- // --------------------------------------------------- Instance Variables
-
- static final long serialVersionUID = 604752400577948726L;
-
-
- /**
- * This Uniform Resource Identifier (URI).
- * The URI is always in an "escaped" form, since escaping or unescaping
- * a completed URI might change its semantics.
- */
- protected char[] _uri = null;
-
-
- /**
- * The default charset of the protocol. RFC 2277, 2396
- */
- protected static String _protocolCharset = "UTF-8";
-
-
- /**
- * The default charset of the document. RFC 2277, 2396
- * The platform's charset is used for the document by default.
- */
- protected static String _documentCharset = null;
- // Static initializer for _documentCharset
- static {
- Locale locale = Locale.getDefault();
- if (locale != null) {
- // in order to support backward compatiblity
- _documentCharset = LocaleToCharsetMap.getCharset(locale);
- } else {
- _documentCharset = (String)AccessController.doPrivileged(
- new GetPropertyAction("file.encoding"));
- }
- }
-
- /**
- * The scheme.
- */
- protected char[] _scheme = null;
-
-
- /**
- * The opaque.
- */
- protected char[] _opaque = null;
-
-
- /**
- * The authority.
- */
- protected char[] _authority = null;
-
-
- /**
- * The userinfo.
- */
- protected char[] _userinfo = null;
-
-
- /**
- * The host.
- */
- protected char[] _host = null;
-
-
- /**
- * The port.
- */
- protected int _port = -1;
-
-
- /**
- * The path.
- */
- protected char[] _path = null;
-
-
- /**
- * The query.
- */
- protected char[] _query = null;
-
-
- /**
- * The fragment.
- */
- protected char[] _fragment = null;
-
-
- /**
- * The root path.
- */
- protected static char[] rootPath = { '/' };
-
- // ---------------------- Generous characters for each component validation
-
- /**
- * The percent "%" character always has the reserved purpose of being the
- * escape indicator, it must be escaped as "%25" in order to be used as
- * data within a URI.
- */
- protected static final BitSet percent = new BitSet(256);
- // Static initializer for percent
- static {
- percent.set('%');
- }
-
-
- /**
- * BitSet for digit.
- * <p><blockquote><pre>
- * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
- * "8" | "9"
- * </pre></blockquote><p>
- */
- protected static final BitSet digit = new BitSet(256);
- // Static initializer for digit
- static {
- for(int i = '0'; i <= '9'; i++) {
- digit.set(i);
- }
- }
-
-
- /**
- * BitSet for alpha.
- * <p><blockquote><pre>
- * alpha = lowalpha | upalpha
- * </pre></blockquote><p>
- */
- protected static final BitSet alpha = new BitSet(256);
- // Static initializer for alpha
- static {
- for (int i = 'a'; i <= 'z'; i++) {
- alpha.set(i);
- }
- for (int i = 'A'; i <= 'Z'; i++) {
- alpha.set(i);
- }
- }
-
-
- /**
- * BitSet for alphanum (join of alpha &amp; digit).
- * <p><blockquote><pre>
- * alphanum = alpha | digit
- * </pre></blockquote><p>
- */
- protected static final BitSet alphanum = new BitSet(256);
- // Static initializer for alphanum
- static {
- alphanum.or(alpha);
- alphanum.or(digit);
- }
-
-
- /**
- * BitSet for hex.
- * <p><blockquote><pre>
- * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
- * "a" | "b" | "c" | "d" | "e" | "f"
- * </pre></blockquote><p>
- */
- protected static final BitSet hex = new BitSet(256);
- // Static initializer for hex
- static {
- hex.or(digit);
- for(int i = 'a'; i <= 'f'; i++) {
- hex.set(i);
- }
- for(int i = 'A'; i <= 'F'; i++) {
- hex.set(i);
- }
- }
-
-
- /**
- * BitSet for escaped.
- * <p><blockquote><pre>
- * escaped = "%" hex hex
- * </pre></blockquote><p>
- */
- protected static final BitSet escaped = new BitSet(256);
- // Static initializer for escaped
- static {
- escaped.or(percent);
- escaped.or(hex);
- }
-
-
- /**
- * BitSet for mark.
- * <p><blockquote><pre>
- * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
- * "(" | ")"
- * </pre></blockquote><p>
- */
- protected static final BitSet mark = new BitSet(256);
- // Static initializer for mark
- static {
- mark.set('-');
- mark.set('_');
- mark.set('.');
- mark.set('!');
- mark.set('~');
- mark.set('*');
- mark.set('\'');
- mark.set('(');
- mark.set(')');
- }
-
-
- /**
- * Data characters that are allowed in a URI but do not have a reserved
- * purpose are called unreserved.
- * <p><blockquote><pre>
- * unreserved = alphanum | mark
- * </pre></blockquote><p>
- */
- protected static final BitSet unreserved = new BitSet(256);
- // Static initializer for unreserved
- static {
- unreserved.or(alphanum);
- unreserved.or(mark);
- }
-
-
- /**
- * BitSet for reserved.
- * <p><blockquote><pre>
- * reserved = ";" | "/" | "?" | ":" | "@" | "&amp;" | "=" | "+" |
- * "$" | ","
- * </pre></blockquote><p>
- */
- protected static final BitSet reserved = new BitSet(256);
- // Static initializer for reserved
- static {
- reserved.set(';');
- reserved.set('/');
- reserved.set('?');
- reserved.set(':');
- reserved.set('@');
- reserved.set('&');
- reserved.set('=');
- reserved.set('+');
- reserved.set('$');
- reserved.set(',');
- }
-
-
- /**
- * BitSet for uric.
- * <p><blockquote><pre>
- * uric = reserved | unreserved | escaped
- * </pre></blockquote><p>
- */
- protected static final BitSet uric = new BitSet(256);
- // Static initializer for uric
- static {
- uric.or(reserved);
- uric.or(unreserved);
- uric.or(escaped);
- }
-
-
- /**
- * BitSet for fragment (alias for uric).
- * <p><blockquote><pre>
- * fragment = *uric
- * </pre></blockquote><p>
- */
- protected static final BitSet fragment = uric;
-
-
- /**
- * BitSet for query (alias for uric).
- * <p><blockquote><pre>
- * query = *uric
- * </pre></blockquote><p>
- */
- protected static final BitSet query = uric;
-
-
- /**
- * BitSet for pchar.
- * <p><blockquote><pre>
- * pchar = unreserved | escaped |
- * ":" | "@" | "&amp;" | "=" | "+" | "$" | ","
- * </pre></blockquote><p>
- */
- protected static final BitSet pchar = new BitSet(256);
- // Static initializer for pchar
- static {
- pchar.or(unreserved);
- pchar.or(escaped);
- pchar.set(':');
- pchar.set('@');
- pchar.set('&');
- pchar.set('=');
- pchar.set('+');
- pchar.set('$');
- pchar.set(',');
- }
-
-
- /**
- * BitSet for param (alias for pchar).
- * <p><blockquote><pre>
- * param = *pchar
- * </pre></blockquote><p>
- */
- protected static final BitSet param = pchar;
-
-
- /**
- * BitSet for segment.
- * <p><blockquote><pre>
- * segment = *pchar *( ";" param )
- * </pre></blockquote><p>
- */
- protected static final BitSet segment = new BitSet(256);
- // Static initializer for segment
- static {
- segment.or(pchar);
- segment.set(';');
- segment.or(param);
- }
-
-
- /**
- * BitSet for path segments.
- * <p><blockquote><pre>
- * path_segments = segment *( "/" segment )
- * </pre></blockquote><p>
- */
- protected static final BitSet path_segments = new BitSet(256);
- // Static initializer for path_segments
- static {
- path_segments.set('/');
- path_segments.or(segment);
- }
-
-
- /**
- * URI absolute path.
- * <p><blockquote><pre>
- * abs_path = "/" path_segments
- * </pre><blockquote><p>
- */
- protected static final BitSet abs_path = new BitSet(256);
- // Static initializer for abs_path
- static {
- abs_path.set('/');
- abs_path.or(path_segments);
- }
-
-
- /**
- * URI bitset for encoding typical non-slash characters.
- * <p><blockquote><pre>
- * uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
- * "&amp;" | "=" | "+" | "$" | ","
- * </pre></blockquote><p>
- */
- protected static final BitSet uric_no_slash = new BitSet(256);
- // Static initializer for uric_no_slash
- static {
- uric_no_slash.or(unreserved);
- uric_no_slash.or(escaped);
- uric_no_slash.set(';');
- uric_no_slash.set('?');
- uric_no_slash.set(';');
- uric_no_slash.set('@');
- uric_no_slash.set('&');
- uric_no_slash.set('=');
- uric_no_slash.set('+');
- uric_no_slash.set('$');
- uric_no_slash.set(',');
- }
-
-
- /**
- * URI bitset that combines uric_no_slash and uric.
- * <p><blockquote><pre>
- * opaque_part = uric_no_slash *uric
- * </pre></blockquote><p>
- */
- protected static final BitSet opaque_part = new BitSet(256);
- // Static initializer for opaque_part
- static {
- opaque_part.or(uric_no_slash);
- opaque_part.or(uric);
- }
-
-
- /**
- * URI bitset that combines absolute path and opaque part.
- * <p><blockquote><pre>
- * path = [ abs_path | opaque_part ]
- * </pre></blockquote><p>
- */
- protected static final BitSet path = new BitSet(256);
- // Static initializer for path
- static {
- path.or(abs_path);
- path.or(opaque_part);
- }
-
-
- /**
- * Port, a logical alias for digit.
- */
- protected static final BitSet port = digit;
-
-
- /**
- * Bitset that combines digit and dot fo IPv$address.
- * <p><blockquote><pre>
- * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
- * </pre></blockquote><p>
- */
- protected static final BitSet IPv4address = new BitSet(256);
- // Static initializer for IPv4address
- static {
- IPv4address.or(digit);
- IPv4address.set('.');
- }
-
-
- /**
- * RFC 2373.
- * <p><blockquote><pre>
- * IPv6address = hexpart [ ":" IPv4address ]
- * </pre></blockquote><p>
- */
- protected static final BitSet IPv6address = new BitSet(256);
- // Static initializer for IPv6address reference
- static {
- IPv6address.or(hex); // hexpart
- IPv6address.set(':');
- IPv6address.or(IPv4address);
- }
-
-
- /**
- * RFC 2732, 2373.
- * <p><blockquote><pre>
- * IPv6reference = "[" IPv6address "]"
- * </pre></blockquote><p>
- */
- protected static final BitSet IPv6reference = new BitSet(256);
- // Static initializer for IPv6reference
- static {
- IPv6reference.set('[');
- IPv6reference.or(IPv6address);
- IPv6reference.set(']');
- }
-
-
- /**
- * BitSet for toplabel.
- * <p><blockquote><pre>
- * toplabel = alpha | alpha *( alphanum | "-" ) alphanum
- * </pre></blockquote><p>
- */
- protected static final BitSet toplabel = new BitSet(256);
- // Static initializer for toplabel
- static {
- toplabel.or(alphanum);
- toplabel.set('-');
- }
-
-
- /**
- * BitSet for domainlabel.
- * <p><blockquote><pre>
- * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
- * </pre></blockquote><p>
- */
- protected static final BitSet domainlabel = toplabel;
-
-
- /**
- * BitSet for hostname.
- * <p><blockquote><pre>
- * hostname = *( domainlabel "." ) toplabel [ "." ]
- * </pre></blockquote><p>
- */
- protected static final BitSet hostname = new BitSet(256);
- // Static initializer for hostname
- static {
- hostname.or(toplabel);
- // hostname.or(domainlabel);
- hostname.set('.');
- }
-
-
- /**
- * BitSet for host.
- * <p><blockquote><pre>
- * host = hostname | IPv4address | IPv6reference
- * </pre></blockquote><p>
- */
- protected static final BitSet host = new BitSet(256);
- // Static initializer for host
- static {
- host.or(hostname);
- // host.or(IPv4address);
- host.or(IPv6reference); // IPv4address
- }
-
-
- /**
- * BitSet for hostport.
- * <p><blockquote><pre>
- * hostport = host [ ":" port ]
- * </pre></blockquote><p>
- */
- protected static final BitSet hostport = new BitSet(256);
- // Static initializer for hostport
- static {
- hostport.or(host);
- hostport.set(':');
- hostport.or(port);
- }
-
-
- /**
- * Bitset for userinfo.
- * <p><blockquote><pre>
- * userinfo = *( unreserved | escaped |
- * ";" | ":" | "&amp;" | "=" | "+" | "$" | "," )
- * </pre></blockquote><p>
- */
- protected static final BitSet userinfo = new BitSet(256);
- // Static initializer for userinfo
- static {
- userinfo.or(unreserved);
- userinfo.or(escaped);
- userinfo.set(';');
- userinfo.set(':');
- userinfo.set('&');
- userinfo.set('=');
- userinfo.set('+');
- userinfo.set('$');
- userinfo.set(',');
- }
-
-
- /**
- * BitSet for within the userinfo component like user and password.
- */
- public static final BitSet within_userinfo = new BitSet(256);
- // Static initializer for within_userinfo
- static {
- within_userinfo.or(userinfo);
- within_userinfo.clear(';'); // reserved within authority
- within_userinfo.clear(':');
- within_userinfo.clear('@');
- within_userinfo.clear('?');
- within_userinfo.clear('/');
- }
-
-
- /**
- * Bitset for server.
- * <p><blockquote><pre>
- * server = [ [ userinfo "@" ] hostport ]
- * </pre></blockquote><p>
- */
- protected static final BitSet server = new BitSet(256);
- // Static initializer for server
- static {
- server.or(userinfo);
- server.set('@');
- server.or(hostport);
- }
-
-
- /**
- * BitSet for reg_name.
- * <p><blockquote><pre>
- * reg_name = 1*( unreserved | escaped | "$" | "," |
- * ";" | ":" | "@" | "&amp;" | "=" | "+" )
- * </pre></blockquote><p>
- */
- protected static final BitSet reg_name = new BitSet(256);
- // Static initializer for reg_name
- static {
- reg_name.or(unreserved);
- reg_name.or(escaped);
- reg_name.set('$');
- reg_name.set(',');
- reg_name.set(';');
- reg_name.set(':');
- reg_name.set('@');
- reg_name.set('&');
- reg_name.set('=');
- reg_name.set('+');
- }
-
-
- /**
- * BitSet for authority.
- * <p><blockquote><pre>
- * authority = server | reg_name
- * </pre></blockquote><p>
- */
- protected static final BitSet authority = new BitSet(256);
- // Static initializer for authority
- static {
- authority.or(server);
- authority.or(reg_name);
- }
-
-
- /**
- * BitSet for scheme.
- * <p><blockquote><pre>
- * scheme = alpha *( alpha | digit | "+" | "-" | "." )
- * </pre></blockquote><p>
- */
- protected static final BitSet scheme = new BitSet(256);
- // Static initializer for scheme
- static {
- scheme.or(alpha);
- scheme.or(digit);
- scheme.set('+');
- scheme.set('-');
- scheme.set('.');
- }
-
-
- /**
- * BitSet for rel_segment.
- * <p><blockquote><pre>
- * rel_segment = 1*( unreserved | escaped |
- * ";" | "@" | "&amp;" | "=" | "+" | "$" | "," )
- * </pre></blockquote><p>
- */
- protected static final BitSet rel_segment = new BitSet(256);
- // Static initializer for rel_segment
- static {
- rel_segment.or(unreserved);
- rel_segment.or(escaped);
- rel_segment.set(';');
- rel_segment.set('@');
- rel_segment.set('&');
- rel_segment.set('=');
- rel_segment.set('+');
- rel_segment.set('$');
- rel_segment.set(',');
- }
-
-
- /**
- * BitSet for rel_path.
- * <p><blockquote><pre>
- * rel_path = rel_segment [ abs_path ]
- * </pre></blockquote><p>
- */
- protected static final BitSet rel_path = new BitSet(256);
- // Static initializer for rel_path
- static {
- rel_path.or(rel_segment);
- rel_path.or(abs_path);
- }
-
-
- /**
- * BitSet for net_path.
- * <p><blockquote><pre>
- * net_path = "//" authority [ abs_path ]
- * </pre></blockquote><p>
- */
- protected static final BitSet net_path = new BitSet(256);
- // Static initializer for net_path
- static {
- net_path.set('/');
- net_path.or(authority);
- net_path.or(abs_path);
- }
-
-
- /**
- * BitSet for hier_part.
- * <p><blockquote><pre>
- * hier_part = ( net_path | abs_path ) [ "?" query ]
- * </pre></blockquote><p>
- */
- protected static final BitSet hier_part = new BitSet(256);
- // Static initializer for hier_part
- static {
- hier_part.or(net_path);
- hier_part.or(abs_path);
- // hier_part.set('?'); aleady included
- hier_part.or(query);
- }
-
-
- /**
- * BitSet for relativeURI.
- * <p><blockquote><pre>
- * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- * </pre></blockquote><p>
- */
- protected static final BitSet relativeURI = new BitSet(256);
- // Static initializer for relativeURI
- static {
- relativeURI.or(net_path);
- relativeURI.or(abs_path);
- relativeURI.or(rel_path);
- // relativeURI.set('?'); aleady included
- relativeURI.or(query);
- }
-
-
- /**
- * BitSet for absoluteURI.
- * <p><blockquote><pre>
- * absoluteURI = scheme ":" ( hier_part | opaque_part )
- * </pre></blockquote><p>
- */
- protected static final BitSet absoluteURI = new BitSet(256);
- // Static initializer for absoluteURI
- static {
- absoluteURI.or(scheme);
- absoluteURI.set(':');
- absoluteURI.or(hier_part);
- absoluteURI.or(opaque_part);
- }
-
-
- /**
- * BitSet for URI-reference.
- * <p><blockquote><pre>
- * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- * </pre></blockquote><p>
- */
- protected static final BitSet URI_reference = new BitSet(256);
- // Static initializer for URI_reference
- static {
- URI_reference.or(absoluteURI);
- URI_reference.or(relativeURI);
- URI_reference.set('#');
- URI_reference.or(fragment);
- }
-
- // ---------------------------- Characters disallowed within the URI syntax
- // Excluded US-ASCII Characters are like control, space, delims and unwise
-
- /**
- * BitSet for control.
- */
- public static final BitSet control = new BitSet(256);
- // Static initializer for control
- static {
- for (int i = 0; i <= 0x1F; i++) {
- control.set(i);
- }
- control.set(0x7F);
- }
-
- /**
- * BitSet for space.
- */
- public static final BitSet space = new BitSet(256);
- // Static initializer for space
- static {
- space.set(0x20);
- }
-
-
- /**
- * BitSet for delims.
- */
- public static final BitSet delims = new BitSet(256);
- // Static initializer for delims
- static {
- delims.set('<');
- delims.set('>');
- delims.set('#');
- delims.set('%');
- delims.set('"');
- }
-
-
- /**
- * BitSet for unwise.
- */
- public static final BitSet unwise = new BitSet(256);
- // Static initializer for unwise
- static {
- unwise.set('{');
- unwise.set('}');
- unwise.set('|');
- unwise.set('\\');
- unwise.set('^');
- unwise.set('[');
- unwise.set(']');
- unwise.set('`');
- }
-
-
- /**
- * Disallowed rel_path before escaping.
- */
- public static final BitSet disallowed_rel_path = new BitSet(256);
- // Static initializer for disallowed_rel_path
- static {
- disallowed_rel_path.or(uric);
- disallowed_rel_path.andNot(rel_path);
- }
-
-
- /**
- * Disallowed opaque_part before escaping.
- */
- public static final BitSet disallowed_opaque_part = new BitSet(256);
- // Static initializer for disallowed_opaque_part
- static {
- disallowed_opaque_part.or(uric);
- disallowed_opaque_part.andNot(opaque_part);
- }
-
- // ----------------------- Characters allowed within and for each component
-
- /**
- * Those characters that are allowed for the authority component.
- */
- public static final BitSet allowed_authority = new BitSet(256);
- // Static initializer for allowed_authority
- static {
- allowed_authority.or(authority);
- allowed_authority.clear('%');
- }
-
-
- /**
- * Those characters that are allowed for the opaque_part.
- */
- public static final BitSet allowed_opaque_part = new BitSet(256);
- // Static initializer for allowed_opaque_part
- static {
- allowed_opaque_part.or(opaque_part);
- allowed_opaque_part.clear('%');
- }
-
-
- /**
- * Those characters that are allowed for the reg_name.
- */
- public static final BitSet allowed_reg_name = new BitSet(256);
- // Static initializer for allowed_reg_name
- static {
- allowed_reg_name.or(reg_name);
- // allowed_reg_name.andNot(percent);
- allowed_reg_name.clear('%');
- }
-
-
- /**
- * Those characters that are allowed for the userinfo component.
- */
- public static final BitSet allowed_userinfo = new BitSet(256);
- // Static initializer for allowed_userinfo
- static {
- allowed_userinfo.or(userinfo);
- // allowed_userinfo.andNot(percent);
- allowed_userinfo.clear('%');
- }
-
-
- /**
- * Those characters that are allowed for within the userinfo component.
- */
- public static final BitSet allowed_within_userinfo = new BitSet(256);
- // Static initializer for allowed_within_userinfo
- static {
- allowed_within_userinfo.or(within_userinfo);
- allowed_within_userinfo.clear('%');
- }
-
-
- /**
- * Those characters that are allowed for the IPv6reference component.
- * The characters '[', ']' in IPv6reference should be excluded.
- */
- public static final BitSet allowed_IPv6reference = new BitSet(256);
- // Static initializer for allowed_IPv6reference
- static {
- allowed_IPv6reference.or(IPv6reference);
- // allowed_IPv6reference.andNot(unwise);
- allowed_IPv6reference.clear('[');
- allowed_IPv6reference.clear(']');
- }
-
-
- /**
- * Those characters that are allowed for the host component.
- * The characters '[', ']' in IPv6reference should be excluded.
- */
- public static final BitSet allowed_host = new BitSet(256);
- // Static initializer for allowed_host
- static {
- allowed_host.or(hostname);
- allowed_host.or(allowed_IPv6reference);
- }
-
-
- /**
- * Those characters that are allowed for the authority component.
- */
- public static final BitSet allowed_within_authority = new BitSet(256);
- // Static initializer for allowed_within_authority
- static {
- allowed_within_authority.or(server);
- allowed_within_authority.or(reg_name);
- allowed_within_authority.clear(';');
- allowed_within_authority.clear(':');
- allowed_within_authority.clear('@');
- allowed_within_authority.clear('?');
- allowed_within_authority.clear('/');
- }
-
-
- /**
- * Those characters that are allowed for the abs_path.
- */
- public static final BitSet allowed_abs_path = new BitSet(256);
- // Static initializer for allowed_abs_path
- static {
- allowed_abs_path.or(abs_path);
- // allowed_abs_path.set('/'); // aleady included
- allowed_abs_path.andNot(percent);
- }
-
-
- /**
- * Those characters that are allowed for the rel_path.
- */
- public static final BitSet allowed_rel_path = new BitSet(256);
- // Static initializer for allowed_rel_path
- static {
- allowed_rel_path.or(rel_path);
- allowed_rel_path.clear('%');
- }
-
-
- /**
- * Those characters that are allowed within the path.
- */
- public static final BitSet allowed_within_path = new BitSet(256);
- // Static initializer for allowed_within_path
- static {
- allowed_within_path.or(abs_path);
- allowed_within_path.clear('/');
- allowed_within_path.clear(';');
- allowed_within_path.clear('=');
- allowed_within_path.clear('?');
- }
-
-
- /**
- * Those characters that are allowed for the query component.
- */
- public static final BitSet allowed_query = new BitSet(256);
- // Static initializer for allowed_query
- static {
- allowed_query.or(uric);
- allowed_query.clear('%');
- }
-
-
- /**
- * Those characters that are allowed within the query component.
- */
- public static final BitSet allowed_within_query = new BitSet(256);
- // Static initializer for allowed_within_query
- static {
- allowed_within_query.or(allowed_query);
- allowed_within_query.andNot(reserved); // excluded 'reserved'
- allowed_within_query.clear('#'); // avoid confict with the fragment
- }
-
-
- /**
- * Those characters that are allowed for the fragment component.
- */
- public static final BitSet allowed_fragment = new BitSet(256);
- // Static initializer for allowed_fragment
- static {
- allowed_fragment.or(uric);
- allowed_fragment.clear('%');
- }
-
- // ------------------------------------------- Flags for this URI-reference
-
- // URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- // absoluteURI = scheme ":" ( hier_part | opaque_part )
- protected boolean _is_hier_part;
- protected boolean _is_opaque_part;
- // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- // hier_part = ( net_path | abs_path ) [ "?" query ]
- protected boolean _is_net_path;
- protected boolean _is_abs_path;
- protected boolean _is_rel_path;
- // net_path = "//" authority [ abs_path ]
- // authority = server | reg_name
- protected boolean _is_reg_name;
- protected boolean _is_server; // = _has_server
- // server = [ [ userinfo "@" ] hostport ]
- // host = hostname | IPv4address | IPv6reference
- protected boolean _is_hostname;
- protected boolean _is_IPv4address;
- protected boolean _is_IPv6reference;
-
- // ------------------------------------------ Character and escape encoding
-
- /**
- * Encode with the default protocol charset.
- *
- * @param original the original character sequence
- * @param allowed those characters that are allowed within a component
- * @return URI character sequence
- * @exception IOException null component or unsupported character encoding
- */
- protected static char[] encode(String original, BitSet allowed)
- throws IOException {
-
- return encode(original, allowed, _protocolCharset);
- }
-
-
- /**
- * Encodes URI string.
- *
- * This is a two mapping, one from original characters to octets, and
- * subsequently a second from octets to URI characters:
- * <p><blockquote><pre>
- * original character sequence->octet sequence->URI character sequence
- * </pre></blockquote><p>
- *
- * An escaped octet is encoded as a character triplet, consisting of the
- * percent character "%" followed by the two hexadecimal digits
- * representing the octet code. For example, "%20" is the escaped
- * encoding for the US-ASCII space character.
- * <p>
- * Conversion from the local filesystem character set to UTF-8 will
- * normally involve a two step process. First convert the local character
- * set to the UCS; then convert the UCS to UTF-8.
- * The first step in the process can be performed by maintaining a mapping
- * table that includes the local character set code and the corresponding
- * UCS code.
- * The next step is to convert the UCS character code to the UTF-8 encoding.
- * <p>
- * Mapping between vendor codepages can be done in a very similar manner
- * as described above.
- * <p>
- * The only time escape encodings can allowedly be made is when a URI is
- * being created from its component parts. The escape and validate methods
- * are internally performed within this method.
- *
- * @param original the original character sequence
- * @param allowed those characters that are allowed within a component
- * @param charset the protocol charset
- * @return URI character sequence
- * @exception IOException null component or unsupported character encoding
- */
- protected static char[] encode(String original, BitSet allowed,
- String charset) throws IOException {
-
- // encode original to uri characters.
- if (original == null) {
- throw new IOException(/*IOException.PARSING,*/ "URI: null");
- }
- // escape octet to uri characters.
- if (allowed == null) {
- throw new IOException(/*IOException.PARSING,*/
- "URI: null allowed characters");
- }
- byte[] octets;
- try {
- octets = original.getBytes(charset);
- } catch (UnsupportedEncodingException error) {
- throw new IOException(/*IOException.UNSUPPORTED_ENCODING,*/ "Unsupported Encoding: " + charset);
- }
- StringBuffer buf = new StringBuffer(octets.length);
- for (int i = 0; i < octets.length; i++) {
- char c = (char) octets[i];
- if (allowed.get(c)) {
- buf.append(c);
- } else {
- buf.append('%');
- byte b = octets[i]; // use the original byte value
- char hexadecimal = Character.forDigit((b >> 4) & 0xF, 16);
- buf.append(Character.toUpperCase(hexadecimal)); // high
- hexadecimal = Character.forDigit(b & 0xF, 16);
- buf.append(Character.toUpperCase(hexadecimal)); // low
- }
- }
-
- return buf.toString().toCharArray();
- }
-
-
- /**
- * Decode with the default protocol charset.
- *
- * @param component the URI character sequence
- * @return original character sequence
- * @exception IOException incomplete trailing escape pattern
- * or unsupported character encoding
- */
- protected static String decode(char[] component) throws IOException {
- return decode(component, _protocolCharset);
- }
-
-
- /**
- * Decodes URI encoded string.
- *
- * This is a two mapping, one from URI characters to octets, and
- * subsequently a second from octets to original characters:
- * <p><blockquote><pre>
- * URI character sequence->octet sequence->original character sequence
- * </pre></blockquote><p>
- *
- * A URI must be separated into its components before the escaped
- * characters within those components can be allowedly decoded.
- * <p>
- * Notice that there is a chance that URI characters that are non UTF-8
- * may be parsed as valid UTF-8. A recent non-scientific analysis found
- * that EUC encoded Japanese words had a 2.7% false reading; SJIS had a
- * 0.0005% false reading; other encoding such as ASCII or KOI-8 have a 0%
- * false reading.
- * <p>
- * The percent "%" character always has the reserved purpose of being
- * the escape indicator, it must be escaped as "%25" in order to be used
- * as data within a URI.
- * <p>
- * The unescape method is internally performed within this method.
- *
- * @param component the URI character sequence
- * @param charset the protocol charset
- * @return original character sequence
- * @exception IOException incomplete trailing escape pattern
- * or unsupported character encoding
- */
- protected static String decode(char[] component, String charset)
- throws IOException {
-
- // unescape uri characters to octets
- if (component == null) return null;
-
- byte[] octets;
- try {
- octets = new String(component).getBytes(charset);
- } catch (UnsupportedEncodingException error) {
- throw new IOException(/* IOException.UNSUPPORTED_ENCODING, */
- "URI: not supported " + charset + " encoding");
- }
- int length = octets.length;
- int oi = 0; // output index
- for (int ii = 0; ii < length; oi++) {
- byte aByte = (byte) octets[ii++];
- if (aByte == '%' && ii+2 <= length) {
- byte high = (byte) Character.digit((char) octets[ii++], 16);
- byte low = (byte) Character.digit((char) octets[ii++], 16);
- if (high == -1 || low == -1) {
- throw new IOException(/* IOException.ESCAPING, */
- "URI: incomplete trailing escape pattern");
-
- }
- aByte = (byte) ((high << 4) + low);
- }
- octets[oi] = (byte) aByte;
- }
-
- String result;
- try {
- result = new String(octets, 0, oi, charset);
- } catch (UnsupportedEncodingException error) {
- throw new IOException(/* IOException.UNSUPPORTED_ENCODING, */
- "URI: not supported " + charset + " encoding");
- }
-
- return result;
- }
-
-
- /**
- * Pre-validate the unescaped URI string within a specific component.
- *
- * @param component the component string within the component
- * @param disallowed those characters disallowed within the component
- * @return if true, it doesn't have the disallowed characters
- * if false, the component is undefined or an incorrect one
- */
- protected boolean prevalidate(String component, BitSet disallowed) {
- // prevalidate the given component by disallowed characters
- if (component == null) {
- return false; // undefined
- }
- char[] target = component.toCharArray();
- for (int i = 0; i < target.length; i++) {
- if (disallowed.get(target[i])) {
- return false;
- }
- }
- return true;
- }
-
-
- /**
- * Validate the URI characters within a specific component.
- * The component must be performed after escape encoding. Or it doesn't
- * include escaped characters.
- *
- * @param component the characters sequence within the component
- * @param generous those characters that are allowed within a component
- * @return if true, it's the correct URI character sequence
- */
- protected boolean validate(char[] component, BitSet generous) {
- // validate each component by generous characters
- return validate(component, 0, -1, generous);
- }
-
-
- /**
- * Validate the URI characters within a specific component.
- * The component must be performed after escape encoding. Or it doesn't
- * include escaped characters.
- * <p>
- * It's not that much strict, generous. The strict validation might be
- * performed before being called this method.
- *
- * @param component the characters sequence within the component
- * @param soffset the starting offset of the given component
- * @param eoffset the ending offset of the given component
- * if -1, it means the length of the component
- * @param generous those characters that are allowed within a component
- * @return if true, it's the correct URI character sequence
- * @throws NullPointerException null component
- */
- protected boolean validate(char[] component, int soffset, int eoffset,
- BitSet generous) {
- // validate each component by generous characters
- if (eoffset == -1) {
- eoffset = component.length -1;
- }
- for (int i = soffset; i <= eoffset; i++) {
- if (!generous.get(component[i])) return false;
- }
- return true;
- }
-
-
- /**
- * In order to avoid any possilbity of conflict with non-ASCII characters,
- * Parse a URI reference as a <code>String</code> with the character
- * encoding of the local system or the document.
- * <p>
- * The following line is the regular expression for breaking-down a URI
- * reference into its components.
- * <p><blockquote><pre>
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * 12 3 4 5 6 7 8 9
- * </pre></blockquote><p>
- * For example, matching the above expression to
- * http://jakarta.apache.org/ietf/uri/#Related
- * results in the following subexpression matches:
- * <p><blockquote><pre>
- * $1 = http:
- * scheme = $2 = http
- * $3 = //jakarta.apache.org
- * authority = $4 = jakarta.apache.org
- * path = $5 = /ietf/uri/
- * $6 = <undefined>
- * query = $7 = <undefined>
- * $8 = #Related
- * fragment = $9 = Related
- * </pre></blockquote><p>
- *
- * @param original the original character sequence
- * @param escaped <code>true</code> if <code>original</code> is escaped
- * @return the original character sequence
- * @exception IOException
- */
- protected void parseUriReference(String original, boolean escaped)
- throws IOException {
-
- // validate and contruct the URI character sequence
- if (original == null || original.length() == 0) {
- throw new IOException("URI-Reference required");
- }
-
- /** @
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- */
- String tmp = original.trim();
-
- /**
- * The length of the string sequence of characters.
- * It may not be equal to the length of the byte array.
- */
- int length = tmp.length();
-
- /**
- * Remove the delimiters like angle brackets around an URI.
- */
- char[] firstDelimiter = { tmp.charAt(0) };
- if (validate(firstDelimiter, delims)) {
- if (length >= 2) {
- char[] lastDelimiter = { tmp.charAt(length - 1) };
- if (validate(lastDelimiter, delims)) {
- tmp = tmp.substring(1, length - 1);
- length = length - 2;
- }
- }
- }
-
- /**
- * The starting index
- */
- int from = 0;
-
- /**
- * The test flag whether the URI is started from the path component.
- */
- boolean isStartedFromPath = false;
- int atColon = tmp.indexOf(':');
- int atSlash = tmp.indexOf('/');
- if (atColon < 0 || (atSlash >= 0 && atSlash < atColon)) {
- isStartedFromPath = true;
- }
-
- /**
- * <p><blockquote><pre>
- * @@@@@@@@
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- int at = indexFirstOf(tmp, isStartedFromPath ? "/?#" : ":/?#", from);
- if (at == -1) at = 0;
-
- /**
- * Parse the scheme.
- * <p><blockquote><pre>
- * scheme = $2 = http
- * @
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- if (at < length && tmp.charAt(at) == ':') {
- char[] target = tmp.substring(0, at).toLowerCase().toCharArray();
- if (validate(target, scheme)) {
- _scheme = target;
- } else {
- throw new IOException("incorrect scheme");
- }
- from = ++at;
- }
-
- /**
- * Parse the authority component.
- * <p><blockquote><pre>
- * authority = $4 = jakarta.apache.org
- * @@
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- // Reset flags
- _is_net_path = _is_abs_path = _is_rel_path = _is_hier_part = false;
- if (0 <= at && at < length && tmp.charAt(at) == '/') {
- // Set flag
- _is_hier_part = true;
- if (at + 2 < length && tmp.charAt(at + 1) == '/') {
- // the temporary index to start the search from
- int next = indexFirstOf(tmp, "/?#", at + 2);
- if (next == -1) {
- next = (tmp.substring(at + 2).length() == 0) ? at + 2 :
- tmp.length();
- }
- parseAuthority(tmp.substring(at + 2, next), escaped);
- from = at = next;
- // Set flag
- _is_net_path = true;
- }
- if (from == at) {
- // Set flag
- _is_abs_path = true;
- }
- }
-
- /**
- * Parse the path component.
- * <p><blockquote><pre>
- * path = $5 = /ietf/uri/
- * @@@@@@
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- if (from < length) {
- // rel_path = rel_segment [ abs_path ]
- int next = indexFirstOf(tmp, "?#", from);
- if (next == -1) {
- next = tmp.length();
- }
- if (!_is_abs_path) {
- if (!escaped && prevalidate(tmp.substring(from, next),
- disallowed_rel_path) || escaped &&
- validate(tmp.substring(from, next).toCharArray(),
- rel_path)) {
- // Set flag
- _is_rel_path = true;
- } else if (!escaped && prevalidate(tmp.substring(from, next),
- disallowed_opaque_part) || escaped &&
- validate(tmp.substring(from, next).toCharArray(),
- opaque_part)) {
- // Set flag
- _is_opaque_part = true;
- } else {
- // the path component may be empty
- _path = null;
- }
- }
- setPath(tmp.substring(from, next));
- at = next;
- }
-
- /**
- * Parse the query component.
- * <p><blockquote><pre>
- * query = $7 = <undefined>
- * @@@@@@@@@
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- if (0 <= at && at+1 < length && tmp.charAt(at) == '?') {
- int next = tmp.indexOf('#', at + 1);
- if (next == -1) {
- next = tmp.length();
- }
- _query = (escaped) ? tmp.substring(at + 1, next).toCharArray() :
- encode(tmp.substring(at + 1, next), allowed_query);
- at = next;
- }
-
- /**
- * Parse the fragment component.
- * <p><blockquote><pre>
- * fragment = $9 = Related
- * @@@@@@@@
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- if (0 <= at && at+1 < length && tmp.charAt(at) == '#') {
- _fragment = (escaped) ? tmp.substring(at + 1).toCharArray() :
- encode(tmp.substring(at + 1), allowed_fragment);
- }
-
- // set this URI.
- setUriReference();
- }
-
-
- /**
- * Get the earlier index that to be searched for the first occurrance in
- * one of any of the given string.
- *
- * @param s the string to be indexed
- * @param delims the delimiters used to index
- * @return the earlier index if there are delimiters
- */
- protected int indexFirstOf(String s, String delims) {
- return indexFirstOf(s, delims, -1);
- }
-
-
- /**
- * Get the earlier index that to be searched for the first occurrance in
- * one of any of the given string.
- *
- * @param s the string to be indexed
- * @param delims the delimiters used to index
- * @param offset the from index
- * @return the earlier index if there are delimiters
- */
- protected int indexFirstOf(String s, String delims, int offset) {
- if (s == null || s.length() == 0) {
- return -1;
- }
- if (delims == null || delims.length() == 0) {
- return -1;
- }
- // check boundaries
- if (offset < 0) {
- offset = 0;
- } else if (offset > s.length()) {
- return -1;
- }
- // s is never null
- int min = s.length();
- char[] delim = delims.toCharArray();
- for (int i = 0; i < delim.length; i++) {
- int at = s.indexOf(delim[i], offset);
- if (at >= 0 && at < min) {
- min = at;
- }
- }
- return (min == s.length()) ? -1 : min;
- }
-
-
- /**
- * Get the earlier index that to be searched for the first occurrance in
- * one of any of the given array.
- *
- * @param s the character array to be indexed
- * @param delim the delimiter used to index
- * @return the ealier index if there are a delimiter
- */
- protected int indexFirstOf(char[] s, char delim) {
- return indexFirstOf(s, delim, 0);
- }
-
-
- /**
- * Get the earlier index that to be searched for the first occurrance in
- * one of any of the given array.
- *
- * @param s the character array to be indexed
- * @param delim the delimiter used to index
- * @return the ealier index if there is a delimiter
- */
- protected int indexFirstOf(char[] s, char delim, int offset) {
- if (s == null || s.length == 0) {
- return -1;
- }
- // check boundaries
- if (offset < 0) {
- offset = 0;
- } else if (offset > s.length) {
- return -1;
- }
- for (int i = offset; i < s.length; i++) {
- if (s[i] == delim) {
- return i;
- }
- }
- return -1;
- }
-
-
- /**
- * Parse the authority component.
- *
- * @param original the original character sequence of authority component
- * @param escaped <code>true</code> if <code>original</code> is escaped
- * @exception IOException
- */
- protected void parseAuthority(String original, boolean escaped)
- throws IOException {
-
- // Reset flags
- _is_reg_name = _is_server =
- _is_hostname = _is_IPv4address = _is_IPv6reference = false;
-
- boolean has_port = true;
- int from = 0;
- int next = original.indexOf('@');
- if (next != -1) { // neither -1 and 0
- // each protocol extented from URI supports the specific userinfo
- _userinfo = (escaped) ? original.substring(0, next).toCharArray() :
- encode(original.substring(0, next), allowed_userinfo);
- from = next + 1;
- }
- next = original.indexOf('[', from);
- if (next >= from) {
- next = original.indexOf(']', from);
- if (next == -1) {
- throw new IOException(/* IOException.PARSING,*/ "URI: IPv6reference");
- } else {
- next++;
- }
- // In IPv6reference, '[', ']' should be excluded
- _host = (escaped) ? original.substring(from, next).toCharArray() :
- encode(original.substring(from, next), allowed_IPv6reference);
- // Set flag
- _is_IPv6reference = true;
- } else { // only for !_is_IPv6reference
- next = original.indexOf(':', from);
- if (next == -1) {
- next = original.length();
- has_port = false;
- }
- // REMINDME: it doesn't need the pre-validation
- _host = original.substring(from, next).toCharArray();
- if (validate(_host, IPv4address)) {
- // Set flag
- _is_IPv4address = true;
- } else if (validate(_host, hostname)) {
- // Set flag
- _is_hostname = true;
- } else {
- // Set flag
- _is_reg_name = true;
- }
- }
- if (_is_reg_name) {
- // Reset flags for a server-based naming authority
- _is_server = _is_hostname = _is_IPv4address =
- _is_IPv6reference = false;
- // set a registry-based naming authority
- _authority = (escaped) ? original.toString().toCharArray() :
- encode(original.toString(), allowed_reg_name);
- } else {
- if (original.length()-1 > next && has_port &&
- original.charAt(next) == ':') { // not empty
- from = next + 1;
- try {
- _port = Integer.parseInt(original.substring(from));
- } catch (NumberFormatException error) {
- throw new IOException(/*IOException.PARSING, */
- "URI: invalid port number");
- }
- }
- // set a server-based naming authority
- StringBuffer buf = new StringBuffer();
- if (_userinfo != null) { // has_userinfo
- buf.append(_userinfo);
- buf.append('@');
- }
- if (_host != null) {
- buf.append(_host);
- if (_port != -1) {
- buf.append(':');
- buf.append(_port);
- }
- }
- _authority = buf.toString().toCharArray();
- // Set flag
- _is_server = true;
- }
- }
-
-
- /**
- * Once it's parsed successfully, set this URI.
- *
- * @see #getRawURI
- */
- protected void setUriReference() {
- // set _uri
- StringBuffer buf = new StringBuffer();
- // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- if (_scheme != null) {
- buf.append(_scheme);
- buf.append(':');
- }
- if (_is_net_path) {
- buf.append("//");
- if (_authority != null) { // has_authority
- if (_userinfo != null) { // by default, remove userinfo part
- if (_host != null) {
- buf.append(_host);
- if (_port != -1) {
- buf.append(':');
- buf.append(_port);
- }
- }
- } else {
- buf.append(_authority);
- }
- }
- }
- if (_opaque != null && _is_opaque_part) {
- buf.append(_opaque);
- } else if (_path != null) {
- // _is_hier_part or _is_relativeURI
- if (_path.length != 0) {
- buf.append(_path);
- }
- }
- if (_query != null) { // has_query
- buf.append('?');
- buf.append(_query);
- }
- if (_fragment != null) { // has_fragment
- buf.append('#');
- buf.append(_fragment);
- }
-
- _uri = buf.toString().toCharArray();
- }
-
- // ----------------------------------------------------------- Test methods
-
-
- /**
- * Tell whether or not this URI is absolute.
- *
- * @return true iif this URI is absoluteURI
- */
- public boolean isAbsoluteURI() {
- return (_scheme != null);
- }
-
-
- /**
- * Tell whether or not this URI is relative.
- *
- * @return true iif this URI is relativeURI
- */
- public boolean isRelativeURI() {
- return (_scheme == null);
- }
-
-
- /**
- * Tell whether or not the absoluteURI of this URI is hier_part.
- *
- * @return true iif the absoluteURI is hier_part
- */
- public boolean isHierPart() {
- return _is_hier_part;
- }
-
-
- /**
- * Tell whether or not the absoluteURI of this URI is opaque_part.
- *
- * @return true iif the absoluteURI is opaque_part
- */
- public boolean isOpaquePart() {
- return _is_opaque_part;
- }
-
-
- /**
- * Tell whether or not the relativeURI or heir_part of this URI is net_path.
- * It's the same function as the has_authority() method.
- *
- * @return true iif the relativeURI or heir_part is net_path
- * @see #hasAuthority
- */
- public boolean isNetPath() {
- return _is_net_path || (_authority != null);
- }
-
-
- /**
- * Tell whether or not the relativeURI or hier_part of this URI is abs_path.
- *
- * @return true iif the relativeURI or hier_part is abs_path
- */
- public boolean isAbsPath() {
- return _is_abs_path;
- }
-
-
- /**
- * Tell whether or not the relativeURI of this URI is rel_path.
- *
- * @return true iif the relativeURI is rel_path
- */
- public boolean isRelPath() {
- return _is_rel_path;
- }
-
-
- /**
- * Tell whether or not this URI has authority.
- * It's the same function as the is_net_path() method.
- *
- * @return true iif this URI has authority
- * @see #isNetPath
- */
- public boolean hasAuthority() {
- return (_authority != null) || _is_net_path;
- }
-
- /**
- * Tell whether or not the authority component of this URI is reg_name.
- *
- * @return true iif the authority component is reg_name
- */
- public boolean isRegName() {
- return _is_reg_name;
- }
-
-
- /**
- * Tell whether or not the authority component of this URI is server.
- *
- * @return true iif the authority component is server
- */
- public boolean isServer() {
- return _is_server;
- }
-
-
- /**
- * Tell whether or not this URI has userinfo.
- *
- * @return true iif this URI has userinfo
- */
- public boolean hasUserinfo() {
- return (_userinfo != null);
- }
-
-
- /**
- * Tell whether or not the host part of this URI is hostname.
- *
- * @return true iif the host part is hostname
- */
- public boolean isHostname() {
- return _is_hostname;
- }
-
-
- /**
- * Tell whether or not the host part of this URI is IPv4address.
- *
- * @return true iif the host part is IPv4address
- */
- public boolean isIPv4address() {
- return _is_IPv4address;
- }
-
-
- /**
- * Tell whether or not the host part of this URI is IPv6reference.
- *
- * @return true iif the host part is IPv6reference
- */
- public boolean isIPv6reference() {
- return _is_IPv6reference;
- }
-
-
- /**
- * Tell whether or not this URI has query.
- *
- * @return true iif this URI has query
- */
- public boolean hasQuery() {
- return (_query != null);
- }
-
-
- /**
- * Tell whether or not this URI has fragment.
- *
- * @return true iif this URI has fragment
- */
- public boolean hasFragment() {
- return (_fragment != null);
- }
-
-
- // ---------------------------------------------------------------- Charset
-
-
- /**
- * Set the default charset of the protocol.
- * <p>
- * The character set used to store files SHALL remain a local decision and
- * MAY depend on the capability of local operating systems. Prior to the
- * exchange of URIs they SHOULD be converted into a ISO/IEC 10646 format
- * and UTF-8 encoded. This approach, while allowing international exchange
- * of URIs, will still allow backward compatibility with older systems
- * because the code set positions for ASCII characters are identical to the
- * one byte sequence in UTF-8.
- * <p>
- * An individual URI scheme may require a single charset, define a default
- * charset, or provide a way to indicate the charset used.
- *
- * @param charset the default charset for each protocol
- */
- public static void setProtocolCharset(String charset) {
- _protocolCharset = charset;
- }
-
-
- /**
- * Get the default charset of the protocol.
- * <p>
- * An individual URI scheme may require a single charset, define a default
- * charset, or provide a way to indicate the charset used.
- * <p>
- * To work globally either requires support of a number of character sets
- * and to be able to convert between them, or the use of a single preferred
- * character set.
- * For support of global compatibility it is STRONGLY RECOMMENDED that
- * clients and servers use UTF-8 encoding when exchanging URIs.
- *
- * @return the charset string
- */
- public static String getProtocolCharset() {
- return _protocolCharset;
- }
-
-
- /**
- * Set the default charset of the document.
- * <p>
- * Notice that it will be possible to contain mixed characters (e.g.
- * ftp://host/KoreanNamespace/ChineseResource). To handle the Bi-directional
- * display of these character sets, the protocol charset could be simply
- * used again. Because it's not yet implemented that the insertion of BIDI
- * control characters at different points during composition is extracted.
- *
- * @param charset the default charset for the document
- */
- public static void setDocumentCharset(String charset) {
- _documentCharset = charset;
- }
-
-
- /**
- * Get the default charset of the document.
- *
- * @return the charset string
- */
- public static String getDocumentCharset() {
- return _documentCharset;
- }
-
- // ------------------------------------------------------------- The scheme
-
- /**
- * Get the scheme.
- *
- * @return the scheme
- */
- public char[] getRawScheme() {
- return _scheme;
- }
-
-
- /**
- * Get the scheme.
- *
- * @return the scheme
- * null if undefined scheme
- */
- public String getScheme() {
- return (_scheme == null) ? null : new String(_scheme);
- }
-
- // ---------------------------------------------------------- The authority
-
- /**
- * Set the authority. It can be one type of server, hostport, hostname,
- * IPv4address, IPv6reference and reg_name.
- * <p><blockquote><pre>
- * authority = server | reg_name
- * </pre></blockquote><p>
- *
- * @param escapedAuthority the raw escaped authority
- * @exception IOException
- * @throws NullPointerException null authority
- */
- public void setRawAuthority(char[] escapedAuthority) throws IOException {
- parseAuthority(new String(escapedAuthority), true);
- setUriReference();
- }
-
-
- /**
- * Set the authority. It can be one type of server, hostport, hostname,
- * IPv4address, IPv6reference and reg_name.
- * Note that there is no setAuthority method by the escape encoding reason.
- *
- * @param escapedAuthority the escaped authority string
- * @exception IOException
- */
- public void setEscapedAuthority(String escapedAuthority)
- throws IOException {
-
- parseAuthority(escapedAuthority, true);
- setUriReference();
- }
-
-
- /**
- * Get the raw-escaped authority.
- *
- * @return the raw-escaped authority
- */
- public char[] getRawAuthority() {
- return _authority;
- }
-
-
- /**
- * Get the escaped authority.
- *
- * @return the escaped authority
- */
- public String getEscapedAuthority() {
- return (_authority == null) ? null : new String(_authority);
- }
-
-
- /**
- * Get the authority.
- *
- * @return the authority
- * @exception IOException
- * @see #decode
- */
- public String getAuthority() throws IOException {
- return (_authority == null) ? null : decode(_authority);
- }
-
- // ----------------------------------------------------------- The userinfo
-
- /**
- * Get the raw-escaped userinfo.
- *
- * @return the raw-escaped userinfo
- * @see #getAuthority
- */
- public char[] getRawUserinfo() {
- return _userinfo;
- }
-
-
- /**
- * Get the escaped userinfo.
- *
- * @return the escaped userinfo
- * @see #getAuthority
- */
- public String getEscapedUserinfo() {
- return (_userinfo == null) ? null : new String(_userinfo);
- }
-
-
- /**
- * Get the userinfo.
- *
- * @return the userinfo
- * @exception IOException
- * @see #decode
- * @see #getAuthority
- */
- public String getUserinfo() throws IOException {
- return (_userinfo == null) ? null : decode(_userinfo);
- }
-
- // --------------------------------------------------------------- The host
-
- /**
- * Get the host.
- * <p><blockquote><pre>
- * host = hostname | IPv4address | IPv6reference
- * </pre></blockquote><p>
- *
- * @return the host
- * @see #getAuthority
- */
- public char[] getRawHost() {
- return _host;
- }
-
-
- /**
- * Get the host.
- * <p><blockquote><pre>
- * host = hostname | IPv4address | IPv6reference
- * </pre></blockquote><p>
- *
- * @return the host
- * @exception IOException
- * @see #decode
- * @see #getAuthority
- */
- public String getHost() throws IOException {
- return decode(_host);
- }
-
- // --------------------------------------------------------------- The port
-
- /**
- * Get the port. In order to get the specfic default port, the specific
- * protocol-supported class extended from the URI class should be used.
- * It has the server-based naming authority.
- *
- * @return the port
- * if -1, it has the default port for the scheme or the server-based
- * naming authority is not supported in the specific URI.
- */
- public int getPort() {
- return _port;
- }
-
- // --------------------------------------------------------------- The path
-
- /**
- * Set the path. The method couldn't be used by API programmers.
- *
- * @param path the path string
- * @exception IOException set incorrectly or fragment only
- * @see #encode
- */
- protected void setPath(String path) throws IOException {
-
- // set path
- if (_is_net_path || _is_abs_path) {
- _path = encode(path, allowed_abs_path);
- } else if (_is_rel_path) {
- StringBuffer buff = new StringBuffer(path.length());
- int at = path.indexOf('/');
- if (at > 0) { // never 0
- buff.append(encode(path.substring(0, at), allowed_rel_path));
- buff.append(encode(path.substring(at), allowed_abs_path));
- } else {
- buff.append(encode(path, allowed_rel_path));
- }
- _path = buff.toString().toCharArray();
- } else if (_is_opaque_part) {
- _opaque = encode(path, allowed_opaque_part);
- } else {
- throw new IOException(/*IOException.PARSING, */"URI: incorrect path");
- }
- }
-
-
- /**
- * Resolve the base and relative path.
- *
- * @param base_path a character array of the base_path
- * @param rel_path a character array of the rel_path
- * @return the resolved path
- */
- protected char[] resolvePath(char[] base_path, char[] rel_path) {
-
- // REMINDME: paths are never null
- String base = (base_path == null) ? "" : new String(base_path);
- int at = base.lastIndexOf('/');
- if (at != -1) {
- base_path = base.substring(0, at + 1).toCharArray();
- }
- // _path could be empty
- if (rel_path == null || rel_path.length == 0) {
- return normalize(base_path);
- } else if (rel_path[0] == '/') {
- return rel_path;
- } else {
- StringBuffer buff = new StringBuffer(base.length() +
- rel_path.length);
- if (at != -1) {
- buff.append(base.substring(0, at + 1));
- buff.append(rel_path);
- }
- return normalize(buff.toString().toCharArray());
- }
- }
-
-
- /**
- * Get the raw-escaped current hierarchy level in the given path.
- * If the last namespace is a collection, the slash mark ('/') should be
- * ended with at the last character of the path string.
- *
- * @param path the path
- * @return the current hierarchy level
- * @exception IOException no hierarchy level
- */
- protected char[] getRawCurrentHierPath(char[] path) throws IOException {
-
- if (_is_opaque_part) {
- throw new IOException(/*IOException.PARSING,*/ "URI: no hierarchy level");
- }
- if (path == null) {
- throw new IOException(/*IOException.PARSING,*/ "URI: emtpy path");
- }
- String buff = new String(path);
- int first = buff.indexOf('/');
- int last = buff.lastIndexOf('/');
- if (last == 0) {
- return rootPath;
- } else if (first != last && last != -1) {
- return buff.substring(0, last).toCharArray();
- }
- // FIXME: it could be a document on the server side
- return path;
- }
-
-
- /**
- * Get the raw-escaped current hierarchy level.
- *
- * @return the raw-escaped current hierarchy level
- * @exception IOException no hierarchy level
- */
- public char[] getRawCurrentHierPath() throws IOException {
- return (_path == null) ? null : getRawCurrentHierPath(_path);
- }
-
-
- /**
- * Get the escaped current hierarchy level.
- *
- * @return the escaped current hierarchy level
- * @exception IOException no hierarchy level
- */
- public String getEscapedCurrentHierPath() throws IOException {
- char[] path = getRawCurrentHierPath();
- return (path == null) ? null : new String(path);
- }
-
-
- /**
- * Get the current hierarchy level.
- *
- * @return the current hierarchy level
- * @exception IOException
- * @see #decode
- */
- public String getCurrentHierPath() throws IOException {
- char[] path = getRawCurrentHierPath();
- return (path == null) ? null : decode(path);
- }
-
-
- /**
- * Get the level above the this hierarchy level.
- *
- * @return the raw above hierarchy level
- * @exception IOException
- */
- public char[] getRawAboveHierPath() throws IOException {
- char[] path = getRawCurrentHierPath();
- return (path == null) ? null : getRawCurrentHierPath(path);
- }
-
-
- /**
- * Get the level above the this hierarchy level.
- *
- * @return the raw above hierarchy level
- * @exception IOException
- */
- public String getEscapedAboveHierPath() throws IOException {
- char[] path = getRawAboveHierPath();
- return (path == null) ? null : new String(path);
- }
-
-
- /**
- * Get the level above the this hierarchy level.
- *
- * @return the above hierarchy level
- * @exception IOException
- * @see #decode
- */
- public String getAboveHierPath() throws IOException {
- char[] path = getRawAboveHierPath();
- return (path == null) ? null : decode(path);
- }
-
-
- /**
- * Get the raw-escaped path.
- * <p><blockquote><pre>
- * path = [ abs_path | opaque_part ]
- * </pre></blockquote><p>
- *
- * @return the raw-escaped path
- */
- public char[] getRawPath() {
- return _is_opaque_part ? _opaque : _path;
- }
-
-
- /**
- * Get the escaped path.
- * <p><blockquote><pre>
- * path = [ abs_path | opaque_part ]
- * abs_path = "/" path_segments
- * opaque_part = uric_no_slash *uric
- * </pre></blockquote><p>
- *
- * @return the escaped path string
- */
- public String getEscapedPath() {
- char[] path = getRawPath();
- return (path == null) ? null : new String(path);
- }
-
-
- /**
- * Get the path.
- * <p><blockquote><pre>
- * path = [ abs_path | opaque_part ]
- * </pre></blockquote><p>
- * @return the path string
- * @exception IOException
- * @see #decode
- */
- public String getPath() throws IOException {
- char[] path = getRawPath();
- return (path == null) ? null : decode(path);
- }
-
-
- /**
- * Get the raw-escaped basename of the path.
- *
- * @return the raw-escaped basename
- */
- public char[] getRawName() {
- if (_path == null) return null;
-
- int at = 0;
- for (int i = _path.length - 1; i >= 0; i--) {
- if (_path[i] == '/') {
- at = i + 1;
- break;
- }
- }
- int len = _path.length - at;
- char[] basename = new char[len];
- System.arraycopy(_path, at, basename, 0, len);
- return basename;
- }
-
-
- /**
- * Get the escaped basename of the path.
- *
- * @return the escaped basename string
- */
- public String getEscapedName() {
- char[] basename = getRawName();
- return (basename == null) ? null : new String(basename);
- }
-
-
- /**
- * Get the basename of the path.
- *
- * @return the basename string
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @see #decode
- */
- public String getName() throws IOException {
- char[] basename = getRawName();
- return (basename == null) ? null : decode(getRawName());
- }
-
- // ----------------------------------------------------- The path and query
-
- /**
- * Get the raw-escaped path and query.
- *
- * @return the raw-escaped path and query
- */
- public char[] getRawPathQuery() {
-
- if (_path == null && _query == null) {
- return null;
- }
- StringBuffer buff = new StringBuffer();
- if (_path != null) {
- buff.append(_path);
- }
- if (_query != null) {
- buff.append('?');
- buff.append(_query);
- }
- return buff.toString().toCharArray();
- }
-
-
- /**
- * Get the escaped query.
- *
- * @return the escaped path and query string
- */
- public String getEscapedPathQuery() {
- char[] rawPathQuery = getRawPathQuery();
- return (rawPathQuery == null) ? null : new String(rawPathQuery);
- }
-
-
- /**
- * Get the path and query.
- *
- * @return the path and query string.
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @see #decode
- */
- public String getPathQuery() throws IOException {
- char[] rawPathQuery = getRawPathQuery();
- return (rawPathQuery == null) ? null : decode(rawPathQuery);
- }
-
- // -------------------------------------------------------------- The query
-
- /**
- * Set the raw-escaped query.
- *
- * @param escapedQuery the raw-escaped query
- * @exception IOException escaped query not valid
- * @throws NullPointerException null query
- */
- public void setRawQuery(char[] escapedQuery) throws IOException {
- if (!validate(escapedQuery, query))
- throw new IOException(/*IOException.ESCAPING,*/
- "URI: escaped query not valid");
- _query = escapedQuery;
- setUriReference();
- }
-
-
- /**
- * Set the escaped query string.
- *
- * @param escapedQuery the escaped query string
- * @exception IOException escaped query not valid
- * @throws NullPointerException null query
- */
- public void setEscapedQuery(String escapedQuery) throws IOException {
- setRawQuery(escapedQuery.toCharArray());
- }
-
-
- /**
- * Set the query.
- * When a query string is not misunderstood the reserved special characters
- * ("&amp;", "=", "+", ",", and "$") within a query component, it is
- * recommended to use in encoding the whole query with this method.
- *
- * @param query the query string.
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @throws NullPointerException null query
- * @see #encode
- */
- public void setQuery(String query) throws IOException {
- setRawQuery(encode(query, allowed_query));
- }
-
-
- /**
- * Get the raw-escaped query.
- *
- * @return the raw-escaped query
- */
- public char[] getRawQuery() {
- return _query;
- }
-
-
- /**
- * Get the escaped query.
- *
- * @return the escaped query string
- */
- public String getEscapedQuery() {
- return (_query == null) ? null : new String(_query);
- }
-
-
- /**
- * Get the query.
- *
- * @return the query string.
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @see #decode
- */
- public String getQuery() throws IOException {
- return (_query == null) ? null : decode(_query);
- }
-
- // ----------------------------------------------------------- The fragment
-
- /**
- * Set the raw-escaped fragment.
- *
- * @param escapedFragment the raw-escaped fragment
- * @exception IOException escaped fragment not valid
- * @throws NullPointerException null fragment
- */
- public void setRawFragment(char[] escapedFragment) throws IOException {
- if (!validate(escapedFragment, fragment))
- throw new IOException(/*IOException.ESCAPING,*/
- "URI: escaped fragment not valid");
- _fragment = escapedFragment;
- setUriReference();
- }
-
-
- /**
- * Set the escaped fragment string.
- *
- * @param escapedFragment the escaped fragment string
- * @exception IOException escaped fragment not valid
- * @throws NullPointerException null fragment
- */
- public void setEscapedFragment(String escapedFragment) throws IOException {
- char[] fragmentSequence = escapedFragment.toCharArray();
- if (!validate(fragmentSequence, fragment))
- throw new IOException(/*IOException.ESCAPING,*/
- "URI: escaped fragment not valid");
- _fragment = fragmentSequence;
- setUriReference();
- }
-
-
- /**
- * Set the fragment.
- *
- * @param the fragment string.
- * @exception IOException
- * Or unsupported character encoding
- * @throws NullPointerException null fragment
- */
- public void setFragment(String fragment) throws IOException {
- _fragment = encode(fragment, allowed_fragment);
- setUriReference();
- }
-
-
- /**
- * Get the raw-escaped fragment.
- * <p>
- * The optional fragment identifier is not part of a URI, but is often used
- * in conjunction with a URI.
- * <p>
- * The format and interpretation of fragment identifiers is dependent on
- * the media type [RFC2046] of the retrieval result.
- * <p>
- * A fragment identifier is only meaningful when a URI reference is
- * intended for retrieval and the result of that retrieval is a document
- * for which the identified fragment is consistently defined.
- *
- * @return the raw-escaped fragment
- */
- public char[] getRawFragment() {
- return _fragment;
- }
-
-
- /**
- * Get the escaped fragment.
- *
- * @return the escaped fragment string
- */
- public String getEscapedFragment() {
- return (_fragment == null) ? null : new String(_fragment);
- }
-
-
- /**
- * Get the fragment.
- *
- * @return the fragment string
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @see #decode
- */
- public String getFragment() throws IOException {
- return (_fragment == null) ? null : decode(_fragment);
- }
-
- // ------------------------------------------------------------- Utilities
-
- /**
- * Normalize the given hier path part.
- *
- * @param path the path to normalize
- * @return the normalized path
- */
- protected char[] normalize(char[] path) {
-
- if (path == null) return null;
-
- String normalized = new String(path);
- boolean endsWithSlash = true;
- // precondition
- if (!normalized.endsWith("/")) {
- normalized += '/';
- endsWithSlash = false;
- }
- if (normalized.endsWith("/./") || normalized.endsWith("/../")) {
- endsWithSlash = true;
- }
- // Resolve occurrences of "/./" in the normalized path
- while (true) {
- int at = normalized.indexOf("/./");
- if (at == -1) {
- break;
- }
- normalized = normalized.substring(0, at) +
- normalized.substring(at + 2);
- }
- // Resolve occurrences of "/../" in the normalized path
- while (true) {
- int at = normalized.indexOf("/../");
- if (at == -1) {
- break;
- }
- if (at == 0) {
- normalized = "/";
- break;
- }
- int backward = normalized.lastIndexOf('/', at - 1);
- if (backward == -1) {
- // consider the rel_path
- normalized = normalized.substring(at + 4);
- } else {
- normalized = normalized.substring(0, backward) +
- normalized.substring(at + 3);
- }
- }
- // Resolve occurrences of "//" in the normalized path
- while (true) {
- int at = normalized.indexOf("//");
- if (at == -1) {
- break;
- }
- normalized = normalized.substring(0, at) +
- normalized.substring(at + 1);
- }
- if (!endsWithSlash && normalized.endsWith("/")) {
- normalized = normalized.substring(0, normalized.length()-1);
- } else if (endsWithSlash && !normalized.endsWith("/")) {
- normalized = normalized + "/";
- }
- // Set the normalized path that we have completed
- return normalized.toCharArray();
- }
-
-
- /**
- * Normalize the path part of this URI.
- */
- public void normalize() {
- _path = normalize(_path);
- }
-
-
- /**
- * Test if the first array is equal to the second array.
- *
- * @param first the first character array
- * @param second the second character array
- * @return true if they're equal
- */
- protected boolean equals(char[] first, char[] second) {
-
- if (first == null && second == null) {
- return true;
- }
- if (first == null || second == null) {
- return false;
- }
- if (first.length != second.length) {
- return false;
- }
- for (int i = 0; i < first.length; i++) {
- if (first[i] != second[i]) {
- return false;
- }
- }
- return true;
- }
-
-
- /**
- * Test an object if this URI is equal to another.
- *
- * @param obj an object to compare
- * @return true if two URI objects are equal
- */
- public boolean equals(Object obj) {
-
- // normalize and test each components
- if (obj == this) {
- return true;
- }
- if (!(obj instanceof URI)) {
- return false;
- }
- URI another = (URI) obj;
- // scheme
- if (!equals(_scheme, another._scheme)) {
- return false;
- }
- // is_opaque_part or is_hier_part? and opaque
- if (!equals(_opaque, another._opaque)) {
- return false;
- }
- // is_hier_part
- // has_authority
- if (!equals(_authority, another._authority)) {
- return false;
- }
- // path
- if (!equals(_path, another._path)) {
- return false;
- }
- // has_query
- if (!equals(_query, another._query)) {
- return false;
- }
- // has_fragment? should be careful of the only fragment case.
- if (!equals(_fragment, another._fragment)) {
- return false;
- }
- return true;
- }
-
- // ---------------------------------------------------------- Serialization
-
- /**
- * Write the content of this URI.
- *
- * @param oos the object-output stream
- */
- protected void writeObject(java.io.ObjectOutputStream oos)
- throws IOException {
-
- oos.defaultWriteObject();
- }
-
-
- /**
- * Read a URI.
- *
- * @param ois the object-input stream
- */
- protected void readObject(java.io.ObjectInputStream ois)
- throws ClassNotFoundException, IOException {
-
- ois.defaultReadObject();
- }
-
- // ------------------------------------------------------------- Comparison
-
- /**
- * Compare this URI to another object.
- *
- * @param obj the object to be compared.
- * @return 0, if it's same,
- * -1, if failed, first being compared with in the authority component
- * @exception ClassCastException not URI argument
- * @throws NullPointerException null object
- */
- public int compareTo(Object obj) {
-
- URI another = (URI) obj;
- if (!equals(_authority, another.getRawAuthority())) return -1;
- return toString().compareTo(another.toString());
- }
-
- // ------------------------------------------------------------------ Clone
-
- /**
- * Create and return a copy of this object, the URI-reference containing
- * the userinfo component. Notice that the whole URI-reference including
- * the userinfo component counld not be gotten as a <code>String</code>.
- * <p>
- * To copy the identical <code>URI</code> object including the userinfo
- * component, it should be used.
- *
- * @return a clone of this instance
- */
- public synchronized Object clone() {
-
- URI instance = new URI();
-
- instance._uri = _uri;
- instance._scheme = _scheme;
- instance._opaque = _opaque;
- instance._authority = _authority;
- instance._userinfo = _userinfo;
- instance._host = _host;
- instance._port = _port;
- instance._path = _path;
- instance._query = _query;
- instance._fragment = _fragment;
- // flags
- instance._is_hier_part = _is_hier_part;
- instance._is_opaque_part = _is_opaque_part;
- instance._is_net_path = _is_net_path;
- instance._is_abs_path = _is_abs_path;
- instance._is_rel_path = _is_rel_path;
- instance._is_reg_name = _is_reg_name;
- instance._is_server = _is_server;
- instance._is_hostname = _is_hostname;
- instance._is_IPv4address = _is_IPv4address;
- instance._is_IPv6reference = _is_IPv6reference;
-
- return instance;
- }
-
- // ------------------------------------------------------------ Get the URI
-
- /**
- * It can be gotten the URI character sequence. It's raw-escaped.
- * For the purpose of the protocol to be transported, it will be useful.
- * <p>
- * It is clearly unwise to use a URL that contains a password which is
- * intended to be secret. In particular, the use of a password within
- * the 'userinfo' component of a URL is strongly disrecommended except
- * in those rare cases where the 'password' parameter is intended to be
- * public.
- * <p>
- * When you want to get each part of the userinfo, you need to use the
- * specific methods in the specific URL. It depends on the specific URL.
- *
- * @return URI character sequence
- */
- public char[] getRawURI() {
- return _uri;
- }
-
-
- /**
- * It can be gotten the URI character sequence. It's escaped.
- * For the purpose of the protocol to be transported, it will be useful.
- *
- * @return the URI string
- */
- public String getEscapedURI() {
- return (_uri == null) ? null : new String(_uri);
- }
-
-
- /**
- * It can be gotten the URI character sequence.
- *
- * @return the URI string
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @see #decode
- */
- public String getURI() throws IOException {
- return (_uri == null) ? null : decode(_uri);
- }
-
-
- /**
- * Get the escaped URI string.
- * <p>
- * On the document, the URI-reference form is only used without the userinfo
- * component like http://jakarta.apache.org/ by the security reason.
- * But the URI-reference form with the userinfo component could be parsed.
- * <p>
- * In other words, this URI and any its subclasses must not expose the
- * URI-reference expression with the userinfo component like
- * http://user:password@hostport/restricted_zone.<br>
- * It means that the API client programmer should extract each user and
- * password to access manually. Probably it will be supported in the each
- * subclass, however, not a whole URI-reference expression.
- *
- * @return the URI string
- * @see #clone()
- */
- public String toString() {
- return getEscapedURI();
- }
-
-
- // ------------------------------------------------------------ Inner class
-
- /**
- * A mapping to determine the (somewhat arbitrarily) preferred charset for
- * a given locale. Supports all locales recognized in JDK 1.1.
- * <p>
- * The distribution of this class is Servlets.com. It was originally
- * written by Jason Hunter [jhunter at acm.org] and used by with permission.
- */
- public static class LocaleToCharsetMap {
-
- private static Hashtable map;
- static {
- map = new Hashtable();
- map.put("ar", "ISO-8859-6");
- map.put("be", "ISO-8859-5");
- map.put("bg", "ISO-8859-5");
- map.put("ca", "ISO-8859-1");
- map.put("cs", "ISO-8859-2");
- map.put("da", "ISO-8859-1");
- map.put("de", "ISO-8859-1");
- map.put("el", "ISO-8859-7");
- map.put("en", "ISO-8859-1");
- map.put("es", "ISO-8859-1");
- map.put("et", "ISO-8859-1");
- map.put("fi", "ISO-8859-1");
- map.put("fr", "ISO-8859-1");
- map.put("hr", "ISO-8859-2");
- map.put("hu", "ISO-8859-2");
- map.put("is", "ISO-8859-1");
- map.put("it", "ISO-8859-1");
- map.put("iw", "ISO-8859-8");
- map.put("ja", "Shift_JIS");
- map.put("ko", "EUC-KR");
- map.put("lt", "ISO-8859-2");
- map.put("lv", "ISO-8859-2");
- map.put("mk", "ISO-8859-5");
- map.put("nl", "ISO-8859-1");
- map.put("no", "ISO-8859-1");
- map.put("pl", "ISO-8859-2");
- map.put("pt", "ISO-8859-1");
- map.put("ro", "ISO-8859-2");
- map.put("ru", "ISO-8859-5");
- map.put("sh", "ISO-8859-5");
- map.put("sk", "ISO-8859-2");
- map.put("sl", "ISO-8859-2");
- map.put("sq", "ISO-8859-2");
- map.put("sr", "ISO-8859-5");
- map.put("sv", "ISO-8859-1");
- map.put("tr", "ISO-8859-9");
- map.put("uk", "ISO-8859-5");
- map.put("zh", "GB2312");
- map.put("zh_TW", "Big5");
- }
-
- /**
- * Get the preferred charset for the given locale.
- *
- * @param locale the locale
- * @return the preferred charset
- * or null if the locale is not recognized
- */
- public static String getCharset(Locale locale) {
- // try for an full name match (may include country)
- String charset = (String) map.get(locale.toString());
- if (charset != null) return charset;
-
- // if a full name didn't match, try just the language
- charset = (String) map.get(locale.getLanguage());
- return charset; // may be null
- }
-
- }
+ // ----------------------------------------------------------- Constructors
+
+ protected URI() {
+ }
+
+ /**
+ * Construct a URI as an escaped form of a character array. An URI can be placed
+ * within double-quotes or angle brackets like "http://test.com/" and
+ * &lt;http://test.com/&gt;
+ *
+ * @param escaped the URI character sequence
+ * @exception IOException
+ * @throws NullPointerException if <code>escaped</code> is <code>null</code>
+ */
+ public URI(char[] escaped) throws IOException {
+ parseUriReference(new String(escaped), true);
+ }
+
+ /**
+ * Construct a URI from the given string.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * An URI can be placed within double-quotes or angle brackets like
+ * "http://test.com/" and &lt;http://test.com/&gt;
+ *
+ * @param original the string to be represented to URI character sequence It is
+ * one of absoluteURI and relativeURI.
+ * @exception IOException
+ */
+ public URI(String original) throws IOException {
+ parseUriReference(original, false);
+ }
+
+ /**
+ * Construct a URI from a URL.
+ *
+ * @param url a valid URL.
+ * @throws IOException
+ * @since 2.0
+ */
+ public URI(URL url) throws IOException {
+ this(url.toString());
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ * absoluteURI = scheme ":" ( hier_part | opaque_part )
+ * opaque_part = uric_no_slash *uric
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * It's for absolute URI = &lt;scheme&gt;:&lt;scheme-specific-part&gt;#
+ * &lt;fragment&gt;.
+ *
+ * @param scheme the scheme string
+ * @param scheme_specific_part scheme_specific_part
+ * @param fragment the fragment string
+ * @exception IOException
+ */
+ public URI(String scheme, String scheme_specific_part, String fragment) throws IOException {
+
+ // validate and contruct the URI character sequence
+ if (scheme == null) {
+ throw new IOException(/* IOException.PARSING, */ "URI: scheme required");
+ }
+ char[] s = scheme.toLowerCase().toCharArray();
+ if (validate(s, URI.scheme)) {
+ _scheme = s; // is_absoluteURI
+ } else {
+ throw new IOException(/* IOException.PARSING, */ "URI: incorrect scheme");
+ }
+ _opaque = encode(scheme_specific_part, allowed_opaque_part);
+ // Set flag
+ _is_opaque_part = true;
+ setUriReference();
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ * absoluteURI = scheme ":" ( hier_part | opaque_part )
+ * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ * hier_part = ( net_path | abs_path ) [ "?" query ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * It's for absolute URI = &lt;scheme&gt;:&lt;path&gt;?&lt;query&gt;#&lt;
+ * fragment&gt; and relative URI = &lt;path&gt;?&lt;query&gt;#&lt;fragment &gt;.
+ *
+ * @param scheme the scheme string
+ * @param authority the authority string
+ * @param path the path string
+ * @param query the query string
+ * @param fragment the fragment string
+ * @exception IOException
+ */
+ public URI(String scheme, String authority, String path, String query, String fragment) throws IOException {
+
+ // validate and contruct the URI character sequence
+ StringBuffer buff = new StringBuffer();
+ if (scheme != null) {
+ buff.append(scheme);
+ buff.append(':');
+ }
+ if (authority != null) {
+ buff.append("//");
+ buff.append(authority);
+ }
+ if (path != null) { // accept empty path
+ if ((scheme != null || authority != null) && !path.startsWith("/")) {
+ throw new IOException(/* IOException.PARSING*, */
+ "URI: abs_path requested");
+ }
+ buff.append(path);
+ }
+ if (query != null) {
+ buff.append('?');
+ buff.append(query);
+ }
+ if (fragment != null) {
+ buff.append('#');
+ buff.append(fragment);
+ }
+ parseUriReference(buff.toString(), false);
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ *
+ * @param scheme the scheme string
+ * @param userinfo the userinfo string
+ * @param host the host string
+ * @param port the port number
+ * @exception IOException
+ */
+ public URI(String scheme, String userinfo, String host, int port) throws IOException {
+
+ this(scheme, userinfo, host, port, null, null, null);
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ *
+ * @param scheme the scheme string
+ * @param userinfo the userinfo string
+ * @param host the host string
+ * @param port the port number
+ * @param path the path string
+ * @exception IOException
+ */
+ public URI(String scheme, String userinfo, String host, int port, String path) throws IOException {
+
+ this(scheme, userinfo, host, port, path, null, null);
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ *
+ * @param scheme the scheme string
+ * @param userinfo the userinfo string
+ * @param host the host string
+ * @param port the port number
+ * @param path the path string
+ * @param query the query string
+ * @exception IOException
+ */
+ public URI(String scheme, String userinfo, String host, int port, String path, String query) throws IOException {
+
+ this(scheme, userinfo, host, port, path, query, null);
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ *
+ * @param scheme the scheme string
+ * @param userinfo the userinfo string
+ * @param host the host string
+ * @param port the port number
+ * @param path the path string
+ * @param query the query string
+ * @param fragment the fragment string
+ * @exception IOException
+ */
+ public URI(String scheme, String userinfo, String host, int port, String path, String query, String fragment)
+ throws IOException {
+
+ this(scheme,
+ (host == null) ? null
+ : ((userinfo != null) ? userinfo + '@' : "") + host + ((port != -1) ? ":" + port : ""),
+ path, query, fragment);
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ *
+ * @param scheme the scheme string
+ * @param host the host string
+ * @param path the path string
+ * @param fragment the fragment string
+ * @exception IOException
+ */
+ public URI(String scheme, String host, String path, String fragment) throws IOException {
+
+ this(scheme, host, path, null, fragment);
+ }
+
+ /**
+ * Construct a general URI with the given relative URI string.
+ *
+ * @param base the base URI
+ * @param relative the relative URI string
+ * @exception IOException
+ */
+ public URI(URI base, String relative) throws IOException {
+ this(base, new URI(relative));
+ }
+
+ /**
+ * Construct a general URI with the given relative URI.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * Resolving Relative References to Absolute Form.
+ *
+ * <strong>Examples of Resolving Relative URI References</strong>
+ *
+ * Within an object with a well-defined base URI of
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * http://a/b/c/d;p?q
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * the relative URI would be resolved as follows:
+ *
+ * Normal Examples
+ *
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * g:h = g:h
+ * g = http://a/b/c/g
+ * ./g = http://a/b/c/g
+ * g/ = http://a/b/c/g/
+ * /g = http://a/g
+ * //g = http://g
+ * ?y = http://a/b/c/?y
+ * g?y = http://a/b/c/g?y
+ * #s = (current document)#s
+ * g#s = http://a/b/c/g#s
+ * g?y#s = http://a/b/c/g?y#s
+ * ;x = http://a/b/c/;x
+ * g;x = http://a/b/c/g;x
+ * g;x?y#s = http://a/b/c/g;x?y#s
+ * . = http://a/b/c/
+ * ./ = http://a/b/c/
+ * .. = http://a/b/
+ * ../ = http://a/b/
+ * ../g = http://a/b/g
+ * ../.. = http://a/
+ * ../../ = http://a/
+ * ../../g = http://a/g
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * Some URI schemes do not allow a hierarchical syntax matching the <hier_part>
+ * syntax, and thus cannot use relative references.
+ *
+ * @param base the base URI
+ * @param relative the relative URI
+ * @exception IOException
+ */
+ public URI(URI base, URI relative) throws IOException {
+
+ if (base._scheme == null) {
+ throw new IOException(/* IOException.PARSING, */ "URI: base URI required");
+ }
+ if (base._scheme != null) {
+ this._scheme = base._scheme;
+ this._authority = base._authority;
+ }
+ if (base._is_opaque_part || relative._is_opaque_part) {
+ this._scheme = base._scheme;
+ this._is_opaque_part = relative._is_opaque_part;
+ this._opaque = relative._opaque;
+ this._fragment = relative._fragment;
+ this.setUriReference();
+ return;
+ }
+ if (relative._scheme != null) {
+ this._scheme = relative._scheme;
+ this._is_net_path = relative._is_net_path;
+ this._authority = relative._authority;
+ if (relative._is_server) {
+ this._userinfo = relative._userinfo;
+ this._host = relative._host;
+ this._port = relative._port;
+ } else if (relative._is_reg_name) {
+ this._is_reg_name = relative._is_reg_name;
+ }
+ this._is_abs_path = relative._is_abs_path;
+ this._is_rel_path = relative._is_rel_path;
+ this._path = relative._path;
+ } else if (base._authority != null && relative._scheme == null) {
+ this._is_net_path = base._is_net_path;
+ this._authority = base._authority;
+ if (base._is_server) {
+ this._userinfo = base._userinfo;
+ this._host = base._host;
+ this._port = base._port;
+ } else if (base._is_reg_name) {
+ this._is_reg_name = base._is_reg_name;
+ }
+ }
+ if (relative._authority != null) {
+ this._is_net_path = relative._is_net_path;
+ this._authority = relative._authority;
+ if (relative._is_server) {
+ this._is_server = relative._is_server;
+ this._userinfo = relative._userinfo;
+ this._host = relative._host;
+ this._port = relative._port;
+ } else if (relative._is_reg_name) {
+ this._is_reg_name = relative._is_reg_name;
+ }
+ this._is_abs_path = relative._is_abs_path;
+ this._is_rel_path = relative._is_rel_path;
+ this._path = relative._path;
+ }
+ // resolve the path
+ if (relative._scheme == null && relative._authority == null || equals(base._scheme, relative._scheme)) {
+ this._path = resolvePath(base._path, relative._path);
+ }
+ // base._query removed
+ if (relative._query != null) {
+ this._query = relative._query;
+ }
+ // base._fragment removed
+ if (relative._fragment != null) {
+ this._fragment = relative._fragment;
+ }
+ this.setUriReference();
+ }
+
+ // --------------------------------------------------- Instance Variables
+
+ static final long serialVersionUID = 604752400577948726L;
+
+ /**
+ * This Uniform Resource Identifier (URI). The URI is always in an "escaped"
+ * form, since escaping or unescaping a completed URI might change its
+ * semantics.
+ */
+ protected char[] _uri = null;
+
+ /**
+ * The default charset of the protocol. RFC 2277, 2396
+ */
+ protected static String _protocolCharset = "UTF-8";
+
+ /**
+ * The default charset of the document. RFC 2277, 2396 The platform's charset is
+ * used for the document by default.
+ */
+ protected static String _documentCharset = null;
+ // Static initializer for _documentCharset
+ static {
+ Locale locale = Locale.getDefault();
+ if (locale != null) {
+ // in order to support backward compatiblity
+ _documentCharset = LocaleToCharsetMap.getCharset(locale);
+ } else {
+ _documentCharset = (String) AccessController.doPrivileged(new GetPropertyAction("file.encoding"));
+ }
+ }
+
+ /**
+ * The scheme.
+ */
+ protected char[] _scheme = null;
+
+ /**
+ * The opaque.
+ */
+ protected char[] _opaque = null;
+
+ /**
+ * The authority.
+ */
+ protected char[] _authority = null;
+
+ /**
+ * The userinfo.
+ */
+ protected char[] _userinfo = null;
+
+ /**
+ * The host.
+ */
+ protected char[] _host = null;
+
+ /**
+ * The port.
+ */
+ protected int _port = -1;
+
+ /**
+ * The path.
+ */
+ protected char[] _path = null;
+
+ /**
+ * The query.
+ */
+ protected char[] _query = null;
+
+ /**
+ * The fragment.
+ */
+ protected char[] _fragment = null;
+
+ /**
+ * The root path.
+ */
+ protected static char[] rootPath = { '/' };
+
+ // ---------------------- Generous characters for each component validation
+
+ /**
+ * The percent "%" character always has the reserved purpose of being the escape
+ * indicator, it must be escaped as "%25" in order to be used as data within a
+ * URI.
+ */
+ protected static final BitSet percent = new BitSet(256);
+ // Static initializer for percent
+ static {
+ percent.set('%');
+ }
+
+ /**
+ * BitSet for digit.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet digit = new BitSet(256);
+ // Static initializer for digit
+ static {
+ for (int i = '0'; i <= '9'; i++) {
+ digit.set(i);
+ }
+ }
+
+ /**
+ * BitSet for alpha.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * alpha = lowalpha | upalpha
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet alpha = new BitSet(256);
+ // Static initializer for alpha
+ static {
+ for (int i = 'a'; i <= 'z'; i++) {
+ alpha.set(i);
+ }
+ for (int i = 'A'; i <= 'Z'; i++) {
+ alpha.set(i);
+ }
+ }
+
+ /**
+ * BitSet for alphanum (join of alpha &amp; digit).
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * alphanum = alpha | digit
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet alphanum = new BitSet(256);
+ // Static initializer for alphanum
+ static {
+ alphanum.or(alpha);
+ alphanum.or(digit);
+ }
+
+ /**
+ * BitSet for hex.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f"
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet hex = new BitSet(256);
+ // Static initializer for hex
+ static {
+ hex.or(digit);
+ for (int i = 'a'; i <= 'f'; i++) {
+ hex.set(i);
+ }
+ for (int i = 'A'; i <= 'F'; i++) {
+ hex.set(i);
+ }
+ }
+
+ /**
+ * BitSet for escaped.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * escaped = "%" hex hex
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet escaped = new BitSet(256);
+ // Static initializer for escaped
+ static {
+ escaped.or(percent);
+ escaped.or(hex);
+ }
+
+ /**
+ * BitSet for mark.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet mark = new BitSet(256);
+ // Static initializer for mark
+ static {
+ mark.set('-');
+ mark.set('_');
+ mark.set('.');
+ mark.set('!');
+ mark.set('~');
+ mark.set('*');
+ mark.set('\'');
+ mark.set('(');
+ mark.set(')');
+ }
+
+ /**
+ * Data characters that are allowed in a URI but do not have a reserved purpose
+ * are called unreserved.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * unreserved = alphanum | mark
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet unreserved = new BitSet(256);
+ // Static initializer for unreserved
+ static {
+ unreserved.or(alphanum);
+ unreserved.or(mark);
+ }
+
+ /**
+ * BitSet for reserved.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * reserved = ";" | "/" | "?" | ":" | "@" | "&amp;" | "=" | "+" | "$" | ","
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet reserved = new BitSet(256);
+ // Static initializer for reserved
+ static {
+ reserved.set(';');
+ reserved.set('/');
+ reserved.set('?');
+ reserved.set(':');
+ reserved.set('@');
+ reserved.set('&');
+ reserved.set('=');
+ reserved.set('+');
+ reserved.set('$');
+ reserved.set(',');
+ }
+
+ /**
+ * BitSet for uric.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * uric = reserved | unreserved | escaped
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet uric = new BitSet(256);
+ // Static initializer for uric
+ static {
+ uric.or(reserved);
+ uric.or(unreserved);
+ uric.or(escaped);
+ }
+
+ /**
+ * BitSet for fragment (alias for uric).
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * fragment = *uric
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet fragment = uric;
+
+ /**
+ * BitSet for query (alias for uric).
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * query = *uric
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet query = uric;
+
+ /**
+ * BitSet for pchar.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * pchar = unreserved | escaped | ":" | "@" | "&amp;" | "=" | "+" | "$" | ","
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet pchar = new BitSet(256);
+ // Static initializer for pchar
+ static {
+ pchar.or(unreserved);
+ pchar.or(escaped);
+ pchar.set(':');
+ pchar.set('@');
+ pchar.set('&');
+ pchar.set('=');
+ pchar.set('+');
+ pchar.set('$');
+ pchar.set(',');
+ }
+
+ /**
+ * BitSet for param (alias for pchar).
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * param = *pchar
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet param = pchar;
+
+ /**
+ * BitSet for segment.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * segment = *pchar *( ";" param )
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet segment = new BitSet(256);
+ // Static initializer for segment
+ static {
+ segment.or(pchar);
+ segment.set(';');
+ segment.or(param);
+ }
+
+ /**
+ * BitSet for path segments.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path_segments = segment *( "/" segment )
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet path_segments = new BitSet(256);
+ // Static initializer for path_segments
+ static {
+ path_segments.set('/');
+ path_segments.or(segment);
+ }
+
+ /**
+ * URI absolute path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * abs_path = "/" path_segments
+ * </pre>
+ *
+ * <blockquote>
+ * <p>
+ */
+ protected static final BitSet abs_path = new BitSet(256);
+ // Static initializer for abs_path
+ static {
+ abs_path.set('/');
+ abs_path.or(path_segments);
+ }
+
+ /**
+ * URI bitset for encoding typical non-slash characters.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" | "&amp;" | "=" | "+" | "$" | ","
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet uric_no_slash = new BitSet(256);
+ // Static initializer for uric_no_slash
+ static {
+ uric_no_slash.or(unreserved);
+ uric_no_slash.or(escaped);
+ uric_no_slash.set(';');
+ uric_no_slash.set('?');
+ uric_no_slash.set(';');
+ uric_no_slash.set('@');
+ uric_no_slash.set('&');
+ uric_no_slash.set('=');
+ uric_no_slash.set('+');
+ uric_no_slash.set('$');
+ uric_no_slash.set(',');
+ }
+
+ /**
+ * URI bitset that combines uric_no_slash and uric.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * opaque_part = uric_no_slash * uric
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet opaque_part = new BitSet(256);
+ // Static initializer for opaque_part
+ static {
+ opaque_part.or(uric_no_slash);
+ opaque_part.or(uric);
+ }
+
+ /**
+ * URI bitset that combines absolute path and opaque part.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path = [ abs_path | opaque_part ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet path = new BitSet(256);
+ // Static initializer for path
+ static {
+ path.or(abs_path);
+ path.or(opaque_part);
+ }
+
+ /**
+ * Port, a logical alias for digit.
+ */
+ protected static final BitSet port = digit;
+
+ /**
+ * Bitset that combines digit and dot fo IPv$address.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet IPv4address = new BitSet(256);
+ // Static initializer for IPv4address
+ static {
+ IPv4address.or(digit);
+ IPv4address.set('.');
+ }
+
+ /**
+ * RFC 2373.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * IPv6address = hexpart [ ":" IPv4address ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet IPv6address = new BitSet(256);
+ // Static initializer for IPv6address reference
+ static {
+ IPv6address.or(hex); // hexpart
+ IPv6address.set(':');
+ IPv6address.or(IPv4address);
+ }
+
+ /**
+ * RFC 2732, 2373.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * IPv6reference = "[" IPv6address "]"
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet IPv6reference = new BitSet(256);
+ // Static initializer for IPv6reference
+ static {
+ IPv6reference.set('[');
+ IPv6reference.or(IPv6address);
+ IPv6reference.set(']');
+ }
+
+ /**
+ * BitSet for toplabel.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * toplabel = alpha | alpha *( alphanum | "-" ) alphanum
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet toplabel = new BitSet(256);
+ // Static initializer for toplabel
+ static {
+ toplabel.or(alphanum);
+ toplabel.set('-');
+ }
+
+ /**
+ * BitSet for domainlabel.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet domainlabel = toplabel;
+
+ /**
+ * BitSet for hostname.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * hostname = *( domainlabel "." ) toplabel [ "." ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet hostname = new BitSet(256);
+ // Static initializer for hostname
+ static {
+ hostname.or(toplabel);
+ // hostname.or(domainlabel);
+ hostname.set('.');
+ }
+
+ /**
+ * BitSet for host.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * host = hostname | IPv4address | IPv6reference
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet host = new BitSet(256);
+ // Static initializer for host
+ static {
+ host.or(hostname);
+ // host.or(IPv4address);
+ host.or(IPv6reference); // IPv4address
+ }
+
+ /**
+ * BitSet for hostport.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * hostport = host [ ":" port ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet hostport = new BitSet(256);
+ // Static initializer for hostport
+ static {
+ hostport.or(host);
+ hostport.set(':');
+ hostport.or(port);
+ }
+
+ /**
+ * Bitset for userinfo.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * userinfo = *( unreserved | escaped |
+ * ";" | ":" | "&amp;" | "=" | "+" | "$" | "," )
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet userinfo = new BitSet(256);
+ // Static initializer for userinfo
+ static {
+ userinfo.or(unreserved);
+ userinfo.or(escaped);
+ userinfo.set(';');
+ userinfo.set(':');
+ userinfo.set('&');
+ userinfo.set('=');
+ userinfo.set('+');
+ userinfo.set('$');
+ userinfo.set(',');
+ }
+
+ /**
+ * BitSet for within the userinfo component like user and password.
+ */
+ public static final BitSet within_userinfo = new BitSet(256);
+ // Static initializer for within_userinfo
+ static {
+ within_userinfo.or(userinfo);
+ within_userinfo.clear(';'); // reserved within authority
+ within_userinfo.clear(':');
+ within_userinfo.clear('@');
+ within_userinfo.clear('?');
+ within_userinfo.clear('/');
+ }
+
+ /**
+ * Bitset for server.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * server = [ [ userinfo "@" ] hostport ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet server = new BitSet(256);
+ // Static initializer for server
+ static {
+ server.or(userinfo);
+ server.set('@');
+ server.or(hostport);
+ }
+
+ /**
+ * BitSet for reg_name.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * reg_name = 1 * (unreserved | escaped | "$" | "," | ";" | ":" | "@" | "&amp;" | "=" | "+")
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet reg_name = new BitSet(256);
+ // Static initializer for reg_name
+ static {
+ reg_name.or(unreserved);
+ reg_name.or(escaped);
+ reg_name.set('$');
+ reg_name.set(',');
+ reg_name.set(';');
+ reg_name.set(':');
+ reg_name.set('@');
+ reg_name.set('&');
+ reg_name.set('=');
+ reg_name.set('+');
+ }
+
+ /**
+ * BitSet for authority.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * authority = server | reg_name
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet authority = new BitSet(256);
+ // Static initializer for authority
+ static {
+ authority.or(server);
+ authority.or(reg_name);
+ }
+
+ /**
+ * BitSet for scheme.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * scheme = alpha * (alpha | digit | "+" | "-" | ".")
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet scheme = new BitSet(256);
+ // Static initializer for scheme
+ static {
+ scheme.or(alpha);
+ scheme.or(digit);
+ scheme.set('+');
+ scheme.set('-');
+ scheme.set('.');
+ }
+
+ /**
+ * BitSet for rel_segment.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * rel_segment = 1 * (unreserved | escaped | ";" | "@" | "&amp;" | "=" | "+" | "$" | ",")
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet rel_segment = new BitSet(256);
+ // Static initializer for rel_segment
+ static {
+ rel_segment.or(unreserved);
+ rel_segment.or(escaped);
+ rel_segment.set(';');
+ rel_segment.set('@');
+ rel_segment.set('&');
+ rel_segment.set('=');
+ rel_segment.set('+');
+ rel_segment.set('$');
+ rel_segment.set(',');
+ }
+
+ /**
+ * BitSet for rel_path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * rel_path = rel_segment[abs_path]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet rel_path = new BitSet(256);
+ // Static initializer for rel_path
+ static {
+ rel_path.or(rel_segment);
+ rel_path.or(abs_path);
+ }
+
+ /**
+ * BitSet for net_path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * net_path = "//" authority [ abs_path ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet net_path = new BitSet(256);
+ // Static initializer for net_path
+ static {
+ net_path.set('/');
+ net_path.or(authority);
+ net_path.or(abs_path);
+ }
+
+ /**
+ * BitSet for hier_part.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * hier_part = ( net_path | abs_path ) [ "?" query ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet hier_part = new BitSet(256);
+ // Static initializer for hier_part
+ static {
+ hier_part.or(net_path);
+ hier_part.or(abs_path);
+ // hier_part.set('?'); aleady included
+ hier_part.or(query);
+ }
+
+ /**
+ * BitSet for relativeURI.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet relativeURI = new BitSet(256);
+ // Static initializer for relativeURI
+ static {
+ relativeURI.or(net_path);
+ relativeURI.or(abs_path);
+ relativeURI.or(rel_path);
+ // relativeURI.set('?'); aleady included
+ relativeURI.or(query);
+ }
+
+ /**
+ * BitSet for absoluteURI.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * absoluteURI = scheme ":" ( hier_part | opaque_part )
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet absoluteURI = new BitSet(256);
+ // Static initializer for absoluteURI
+ static {
+ absoluteURI.or(scheme);
+ absoluteURI.set(':');
+ absoluteURI.or(hier_part);
+ absoluteURI.or(opaque_part);
+ }
+
+ /**
+ * BitSet for URI-reference.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet URI_reference = new BitSet(256);
+ // Static initializer for URI_reference
+ static {
+ URI_reference.or(absoluteURI);
+ URI_reference.or(relativeURI);
+ URI_reference.set('#');
+ URI_reference.or(fragment);
+ }
+
+ // ---------------------------- Characters disallowed within the URI syntax
+ // Excluded US-ASCII Characters are like control, space, delims and unwise
+
+ /**
+ * BitSet for control.
+ */
+ public static final BitSet control = new BitSet(256);
+ // Static initializer for control
+ static {
+ for (int i = 0; i <= 0x1F; i++) {
+ control.set(i);
+ }
+ control.set(0x7F);
+ }
+
+ /**
+ * BitSet for space.
+ */
+ public static final BitSet space = new BitSet(256);
+ // Static initializer for space
+ static {
+ space.set(0x20);
+ }
+
+ /**
+ * BitSet for delims.
+ */
+ public static final BitSet delims = new BitSet(256);
+ // Static initializer for delims
+ static {
+ delims.set('<');
+ delims.set('>');
+ delims.set('#');
+ delims.set('%');
+ delims.set('"');
+ }
+
+ /**
+ * BitSet for unwise.
+ */
+ public static final BitSet unwise = new BitSet(256);
+ // Static initializer for unwise
+ static {
+ unwise.set('{');
+ unwise.set('}');
+ unwise.set('|');
+ unwise.set('\\');
+ unwise.set('^');
+ unwise.set('[');
+ unwise.set(']');
+ unwise.set('`');
+ }
+
+ /**
+ * Disallowed rel_path before escaping.
+ */
+ public static final BitSet disallowed_rel_path = new BitSet(256);
+ // Static initializer for disallowed_rel_path
+ static {
+ disallowed_rel_path.or(uric);
+ disallowed_rel_path.andNot(rel_path);
+ }
+
+ /**
+ * Disallowed opaque_part before escaping.
+ */
+ public static final BitSet disallowed_opaque_part = new BitSet(256);
+ // Static initializer for disallowed_opaque_part
+ static {
+ disallowed_opaque_part.or(uric);
+ disallowed_opaque_part.andNot(opaque_part);
+ }
+
+ // ----------------------- Characters allowed within and for each component
+
+ /**
+ * Those characters that are allowed for the authority component.
+ */
+ public static final BitSet allowed_authority = new BitSet(256);
+ // Static initializer for allowed_authority
+ static {
+ allowed_authority.or(authority);
+ allowed_authority.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed for the opaque_part.
+ */
+ public static final BitSet allowed_opaque_part = new BitSet(256);
+ // Static initializer for allowed_opaque_part
+ static {
+ allowed_opaque_part.or(opaque_part);
+ allowed_opaque_part.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed for the reg_name.
+ */
+ public static final BitSet allowed_reg_name = new BitSet(256);
+ // Static initializer for allowed_reg_name
+ static {
+ allowed_reg_name.or(reg_name);
+ // allowed_reg_name.andNot(percent);
+ allowed_reg_name.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed for the userinfo component.
+ */
+ public static final BitSet allowed_userinfo = new BitSet(256);
+ // Static initializer for allowed_userinfo
+ static {
+ allowed_userinfo.or(userinfo);
+ // allowed_userinfo.andNot(percent);
+ allowed_userinfo.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed for within the userinfo component.
+ */
+ public static final BitSet allowed_within_userinfo = new BitSet(256);
+ // Static initializer for allowed_within_userinfo
+ static {
+ allowed_within_userinfo.or(within_userinfo);
+ allowed_within_userinfo.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed for the IPv6reference component. The
+ * characters '[', ']' in IPv6reference should be excluded.
+ */
+ public static final BitSet allowed_IPv6reference = new BitSet(256);
+ // Static initializer for allowed_IPv6reference
+ static {
+ allowed_IPv6reference.or(IPv6reference);
+ // allowed_IPv6reference.andNot(unwise);
+ allowed_IPv6reference.clear('[');
+ allowed_IPv6reference.clear(']');
+ }
+
+ /**
+ * Those characters that are allowed for the host component. The characters '[',
+ * ']' in IPv6reference should be excluded.
+ */
+ public static final BitSet allowed_host = new BitSet(256);
+ // Static initializer for allowed_host
+ static {
+ allowed_host.or(hostname);
+ allowed_host.or(allowed_IPv6reference);
+ }
+
+ /**
+ * Those characters that are allowed for the authority component.
+ */
+ public static final BitSet allowed_within_authority = new BitSet(256);
+ // Static initializer for allowed_within_authority
+ static {
+ allowed_within_authority.or(server);
+ allowed_within_authority.or(reg_name);
+ allowed_within_authority.clear(';');
+ allowed_within_authority.clear(':');
+ allowed_within_authority.clear('@');
+ allowed_within_authority.clear('?');
+ allowed_within_authority.clear('/');
+ }
+
+ /**
+ * Those characters that are allowed for the abs_path.
+ */
+ public static final BitSet allowed_abs_path = new BitSet(256);
+ // Static initializer for allowed_abs_path
+ static {
+ allowed_abs_path.or(abs_path);
+ // allowed_abs_path.set('/'); // aleady included
+ allowed_abs_path.andNot(percent);
+ }
+
+ /**
+ * Those characters that are allowed for the rel_path.
+ */
+ public static final BitSet allowed_rel_path = new BitSet(256);
+ // Static initializer for allowed_rel_path
+ static {
+ allowed_rel_path.or(rel_path);
+ allowed_rel_path.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed within the path.
+ */
+ public static final BitSet allowed_within_path = new BitSet(256);
+ // Static initializer for allowed_within_path
+ static {
+ allowed_within_path.or(abs_path);
+ allowed_within_path.clear('/');
+ allowed_within_path.clear(';');
+ allowed_within_path.clear('=');
+ allowed_within_path.clear('?');
+ }
+
+ /**
+ * Those characters that are allowed for the query component.
+ */
+ public static final BitSet allowed_query = new BitSet(256);
+ // Static initializer for allowed_query
+ static {
+ allowed_query.or(uric);
+ allowed_query.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed within the query component.
+ */
+ public static final BitSet allowed_within_query = new BitSet(256);
+ // Static initializer for allowed_within_query
+ static {
+ allowed_within_query.or(allowed_query);
+ allowed_within_query.andNot(reserved); // excluded 'reserved'
+ allowed_within_query.clear('#'); // avoid confict with the fragment
+ }
+
+ /**
+ * Those characters that are allowed for the fragment component.
+ */
+ public static final BitSet allowed_fragment = new BitSet(256);
+ // Static initializer for allowed_fragment
+ static {
+ allowed_fragment.or(uric);
+ allowed_fragment.clear('%');
+ }
+
+ // ------------------------------------------- Flags for this URI-reference
+
+ // URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ // absoluteURI = scheme ":" ( hier_part | opaque_part )
+ protected boolean _is_hier_part;
+ protected boolean _is_opaque_part;
+ // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ // hier_part = ( net_path | abs_path ) [ "?" query ]
+ protected boolean _is_net_path;
+ protected boolean _is_abs_path;
+ protected boolean _is_rel_path;
+ // net_path = "//" authority [ abs_path ]
+ // authority = server | reg_name
+ protected boolean _is_reg_name;
+ protected boolean _is_server; // = _has_server
+ // server = [ [ userinfo "@" ] hostport ]
+ // host = hostname | IPv4address | IPv6reference
+ protected boolean _is_hostname;
+ protected boolean _is_IPv4address;
+ protected boolean _is_IPv6reference;
+
+ // ------------------------------------------ Character and escape encoding
+
+ /**
+ * Encode with the default protocol charset.
+ *
+ * @param original the original character sequence
+ * @param allowed those characters that are allowed within a component
+ * @return URI character sequence
+ * @exception IOException null component or unsupported character encoding
+ */
+ protected static char[] encode(String original, BitSet allowed) throws IOException {
+
+ return encode(original, allowed, _protocolCharset);
+ }
+
+ /**
+ * Encodes URI string.
+ *
+ * This is a two mapping, one from original characters to octets, and
+ * subsequently a second from octets to URI characters:
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * original character sequence->octet sequence->URI character sequence
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * An escaped octet is encoded as a character triplet, consisting of the percent
+ * character "%" followed by the two hexadecimal digits representing the octet
+ * code. For example, "%20" is the escaped encoding for the US-ASCII space
+ * character.
+ * <p>
+ * Conversion from the local filesystem character set to UTF-8 will normally
+ * involve a two step process. First convert the local character set to the UCS;
+ * then convert the UCS to UTF-8. The first step in the process can be performed
+ * by maintaining a mapping table that includes the local character set code and
+ * the corresponding UCS code. The next step is to convert the UCS character
+ * code to the UTF-8 encoding.
+ * <p>
+ * Mapping between vendor codepages can be done in a very similar manner as
+ * described above.
+ * <p>
+ * The only time escape encodings can allowedly be made is when a URI is being
+ * created from its component parts. The escape and validate methods are
+ * internally performed within this method.
+ *
+ * @param original the original character sequence
+ * @param allowed those characters that are allowed within a component
+ * @param charset the protocol charset
+ * @return URI character sequence
+ * @exception IOException null component or unsupported character encoding
+ */
+ protected static char[] encode(String original, BitSet allowed, String charset) throws IOException {
+
+ // encode original to uri characters.
+ if (original == null) {
+ throw new IOException(/* IOException.PARSING, */ "URI: null");
+ }
+ // escape octet to uri characters.
+ if (allowed == null) {
+ throw new IOException(/* IOException.PARSING, */
+ "URI: null allowed characters");
+ }
+ byte[] octets;
+ try {
+ octets = original.getBytes(charset);
+ } catch (UnsupportedEncodingException error) {
+ throw new IOException(/* IOException.UNSUPPORTED_ENCODING, */ "Unsupported Encoding: " + charset);
+ }
+ StringBuffer buf = new StringBuffer(octets.length);
+ for (int i = 0; i < octets.length; i++) {
+ char c = (char) octets[i];
+ if (allowed.get(c)) {
+ buf.append(c);
+ } else {
+ buf.append('%');
+ byte b = octets[i]; // use the original byte value
+ char hexadecimal = Character.forDigit((b >> 4) & 0xF, 16);
+ buf.append(Character.toUpperCase(hexadecimal)); // high
+ hexadecimal = Character.forDigit(b & 0xF, 16);
+ buf.append(Character.toUpperCase(hexadecimal)); // low
+ }
+ }
+
+ return buf.toString().toCharArray();
+ }
+
+ /**
+ * Decode with the default protocol charset.
+ *
+ * @param component the URI character sequence
+ * @return original character sequence
+ * @exception IOException incomplete trailing escape pattern or unsupported
+ * character encoding
+ */
+ protected static String decode(char[] component) throws IOException {
+ return decode(component, _protocolCharset);
+ }
+
+ /**
+ * Decodes URI encoded string.
+ *
+ * This is a two mapping, one from URI characters to octets, and subsequently a
+ * second from octets to original characters:
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI character sequence->octet sequence->original character sequence
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * A URI must be separated into its components before the escaped characters
+ * within those components can be allowedly decoded.
+ * <p>
+ * Notice that there is a chance that URI characters that are non UTF-8 may be
+ * parsed as valid UTF-8. A recent non-scientific analysis found that EUC
+ * encoded Japanese words had a 2.7% false reading; SJIS had a 0.0005% false
+ * reading; other encoding such as ASCII or KOI-8 have a 0% false reading.
+ * <p>
+ * The percent "%" character always has the reserved purpose of being the escape
+ * indicator, it must be escaped as "%25" in order to be used as data within a
+ * URI.
+ * <p>
+ * The unescape method is internally performed within this method.
+ *
+ * @param component the URI character sequence
+ * @param charset the protocol charset
+ * @return original character sequence
+ * @exception IOException incomplete trailing escape pattern or unsupported
+ * character encoding
+ */
+ protected static String decode(char[] component, String charset) throws IOException {
+
+ // unescape uri characters to octets
+ if (component == null)
+ return null;
+
+ byte[] octets;
+ try {
+ octets = new String(component).getBytes(charset);
+ } catch (UnsupportedEncodingException error) {
+ throw new IOException(/* IOException.UNSUPPORTED_ENCODING, */
+ "URI: not supported " + charset + " encoding");
+ }
+ int length = octets.length;
+ int oi = 0; // output index
+ for (int ii = 0; ii < length; oi++) {
+ byte aByte = (byte) octets[ii++];
+ if (aByte == '%' && ii + 2 <= length) {
+ byte high = (byte) Character.digit((char) octets[ii++], 16);
+ byte low = (byte) Character.digit((char) octets[ii++], 16);
+ if (high == -1 || low == -1) {
+ throw new IOException(/* IOException.ESCAPING, */
+ "URI: incomplete trailing escape pattern");
+
+ }
+ aByte = (byte) ((high << 4) + low);
+ }
+ octets[oi] = (byte) aByte;
+ }
+
+ String result;
+ try {
+ result = new String(octets, 0, oi, charset);
+ } catch (UnsupportedEncodingException error) {
+ throw new IOException(/* IOException.UNSUPPORTED_ENCODING, */
+ "URI: not supported " + charset + " encoding");
+ }
+
+ return result;
+ }
+
+ /**
+ * Pre-validate the unescaped URI string within a specific component.
+ *
+ * @param component the component string within the component
+ * @param disallowed those characters disallowed within the component
+ * @return if true, it doesn't have the disallowed characters if false, the
+ * component is undefined or an incorrect one
+ */
+ protected boolean prevalidate(String component, BitSet disallowed) {
+ // prevalidate the given component by disallowed characters
+ if (component == null) {
+ return false; // undefined
+ }
+ char[] target = component.toCharArray();
+ for (int i = 0; i < target.length; i++) {
+ if (disallowed.get(target[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Validate the URI characters within a specific component. The component must
+ * be performed after escape encoding. Or it doesn't include escaped characters.
+ *
+ * @param component the characters sequence within the component
+ * @param generous those characters that are allowed within a component
+ * @return if true, it's the correct URI character sequence
+ */
+ protected boolean validate(char[] component, BitSet generous) {
+ // validate each component by generous characters
+ return validate(component, 0, -1, generous);
+ }
+
+ /**
+ * Validate the URI characters within a specific component. The component must
+ * be performed after escape encoding. Or it doesn't include escaped characters.
+ * <p>
+ * It's not that much strict, generous. The strict validation might be performed
+ * before being called this method.
+ *
+ * @param component the characters sequence within the component
+ * @param soffset the starting offset of the given component
+ * @param eoffset the ending offset of the given component if -1, it means the
+ * length of the component
+ * @param generous those characters that are allowed within a component
+ * @return if true, it's the correct URI character sequence
+ * @throws NullPointerException null component
+ */
+ protected boolean validate(char[] component, int soffset, int eoffset, BitSet generous) {
+ // validate each component by generous characters
+ if (eoffset == -1) {
+ eoffset = component.length - 1;
+ }
+ for (int i = soffset; i <= eoffset; i++) {
+ if (!generous.get(component[i]))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * In order to avoid any possilbity of conflict with non-ASCII characters, Parse
+ * a URI reference as a <code>String</code> with the character encoding of the
+ * local system or the document.
+ * <p>
+ * The following line is the regular expression for breaking-down a URI
+ * reference into its components.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * 12 3 4 5 6 7 8 9
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * For example, matching the above expression to
+ * http://jakarta.apache.org/ietf/uri/#Related results in the following
+ * subexpression matches:
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * $1 = http:
+ * scheme = $2 = http
+ * $3 = //jakarta.apache.org
+ * authority = $4 = jakarta.apache.org
+ * path = $5 = /ietf/uri/
+ * $6 = <undefined>
+ * query = $7 = <undefined>
+ * $8 = #Related
+ * fragment = $9 = Related
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @param original the original character sequence
+ * @param escaped <code>true</code> if <code>original</code> is escaped
+ * @return the original character sequence
+ * @exception IOException
+ */
+ protected void parseUriReference(String original, boolean escaped) throws IOException {
+
+ // validate and contruct the URI character sequence
+ if (original == null || original.length() == 0) {
+ throw new IOException("URI-Reference required");
+ }
+
+ /**
+ * @ ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ */
+ String tmp = original.trim();
+
+ /**
+ * The length of the string sequence of characters. It may not be equal to the
+ * length of the byte array.
+ */
+ int length = tmp.length();
+
+ /**
+ * Remove the delimiters like angle brackets around an URI.
+ */
+ char[] firstDelimiter = { tmp.charAt(0) };
+ if (validate(firstDelimiter, delims)) {
+ if (length >= 2) {
+ char[] lastDelimiter = { tmp.charAt(length - 1) };
+ if (validate(lastDelimiter, delims)) {
+ tmp = tmp.substring(1, length - 1);
+ length = length - 2;
+ }
+ }
+ }
+
+ /**
+ * The starting index
+ */
+ int from = 0;
+
+ /**
+ * The test flag whether the URI is started from the path component.
+ */
+ boolean isStartedFromPath = false;
+ int atColon = tmp.indexOf(':');
+ int atSlash = tmp.indexOf('/');
+ if (atColon < 0 || (atSlash >= 0 && atSlash < atColon)) {
+ isStartedFromPath = true;
+ }
+
+ /**
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * &#64;@@@@@@@
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ int at = indexFirstOf(tmp, isStartedFromPath ? "/?#" : ":/?#", from);
+ if (at == -1)
+ at = 0;
+
+ /**
+ * Parse the scheme.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * scheme = $2 = http
+ * &#64;
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ if (at < length && tmp.charAt(at) == ':') {
+ char[] target = tmp.substring(0, at).toLowerCase().toCharArray();
+ if (validate(target, scheme)) {
+ _scheme = target;
+ } else {
+ throw new IOException("incorrect scheme");
+ }
+ from = ++at;
+ }
+
+ /**
+ * Parse the authority component.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * authority = $4 = jakarta.apache.org
+ * &#64;@
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ // Reset flags
+ _is_net_path = _is_abs_path = _is_rel_path = _is_hier_part = false;
+ if (0 <= at && at < length && tmp.charAt(at) == '/') {
+ // Set flag
+ _is_hier_part = true;
+ if (at + 2 < length && tmp.charAt(at + 1) == '/') {
+ // the temporary index to start the search from
+ int next = indexFirstOf(tmp, "/?#", at + 2);
+ if (next == -1) {
+ next = (tmp.substring(at + 2).length() == 0) ? at + 2 : tmp.length();
+ }
+ parseAuthority(tmp.substring(at + 2, next), escaped);
+ from = at = next;
+ // Set flag
+ _is_net_path = true;
+ }
+ if (from == at) {
+ // Set flag
+ _is_abs_path = true;
+ }
+ }
+
+ /**
+ * Parse the path component.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path = $5 = /ietf/uri/
+ * &#64;@@@@@
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ if (from < length) {
+ // rel_path = rel_segment [ abs_path ]
+ int next = indexFirstOf(tmp, "?#", from);
+ if (next == -1) {
+ next = tmp.length();
+ }
+ if (!_is_abs_path) {
+ if (!escaped && prevalidate(tmp.substring(from, next), disallowed_rel_path)
+ || escaped && validate(tmp.substring(from, next).toCharArray(), rel_path)) {
+ // Set flag
+ _is_rel_path = true;
+ } else if (!escaped && prevalidate(tmp.substring(from, next), disallowed_opaque_part)
+ || escaped && validate(tmp.substring(from, next).toCharArray(), opaque_part)) {
+ // Set flag
+ _is_opaque_part = true;
+ } else {
+ // the path component may be empty
+ _path = null;
+ }
+ }
+ setPath(tmp.substring(from, next));
+ at = next;
+ }
+
+ /**
+ * Parse the query component.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * query = $7 = <undefined>
+ * &#64;@@@@@@@@
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ if (0 <= at && at + 1 < length && tmp.charAt(at) == '?') {
+ int next = tmp.indexOf('#', at + 1);
+ if (next == -1) {
+ next = tmp.length();
+ }
+ _query = (escaped) ? tmp.substring(at + 1, next).toCharArray()
+ : encode(tmp.substring(at + 1, next), allowed_query);
+ at = next;
+ }
+
+ /**
+ * Parse the fragment component.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * fragment = $9 = Related
+ * &#64;@@@@@@@
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ if (0 <= at && at + 1 < length && tmp.charAt(at) == '#') {
+ _fragment = (escaped) ? tmp.substring(at + 1).toCharArray()
+ : encode(tmp.substring(at + 1), allowed_fragment);
+ }
+
+ // set this URI.
+ setUriReference();
+ }
+
+ /**
+ * Get the earlier index that to be searched for the first occurrance in one of
+ * any of the given string.
+ *
+ * @param s the string to be indexed
+ * @param delims the delimiters used to index
+ * @return the earlier index if there are delimiters
+ */
+ protected int indexFirstOf(String s, String delims) {
+ return indexFirstOf(s, delims, -1);
+ }
+
+ /**
+ * Get the earlier index that to be searched for the first occurrance in one of
+ * any of the given string.
+ *
+ * @param s the string to be indexed
+ * @param delims the delimiters used to index
+ * @param offset the from index
+ * @return the earlier index if there are delimiters
+ */
+ protected int indexFirstOf(String s, String delims, int offset) {
+ if (s == null || s.length() == 0) {
+ return -1;
+ }
+ if (delims == null || delims.length() == 0) {
+ return -1;
+ }
+ // check boundaries
+ if (offset < 0) {
+ offset = 0;
+ } else if (offset > s.length()) {
+ return -1;
+ }
+ // s is never null
+ int min = s.length();
+ char[] delim = delims.toCharArray();
+ for (int i = 0; i < delim.length; i++) {
+ int at = s.indexOf(delim[i], offset);
+ if (at >= 0 && at < min) {
+ min = at;
+ }
+ }
+ return (min == s.length()) ? -1 : min;
+ }
+
+ /**
+ * Get the earlier index that to be searched for the first occurrance in one of
+ * any of the given array.
+ *
+ * @param s the character array to be indexed
+ * @param delim the delimiter used to index
+ * @return the ealier index if there are a delimiter
+ */
+ protected int indexFirstOf(char[] s, char delim) {
+ return indexFirstOf(s, delim, 0);
+ }
+
+ /**
+ * Get the earlier index that to be searched for the first occurrance in one of
+ * any of the given array.
+ *
+ * @param s the character array to be indexed
+ * @param delim the delimiter used to index
+ * @return the ealier index if there is a delimiter
+ */
+ protected int indexFirstOf(char[] s, char delim, int offset) {
+ if (s == null || s.length == 0) {
+ return -1;
+ }
+ // check boundaries
+ if (offset < 0) {
+ offset = 0;
+ } else if (offset > s.length) {
+ return -1;
+ }
+ for (int i = offset; i < s.length; i++) {
+ if (s[i] == delim) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Parse the authority component.
+ *
+ * @param original the original character sequence of authority component
+ * @param escaped <code>true</code> if <code>original</code> is escaped
+ * @exception IOException
+ */
+ protected void parseAuthority(String original, boolean escaped) throws IOException {
+
+ // Reset flags
+ _is_reg_name = _is_server = _is_hostname = _is_IPv4address = _is_IPv6reference = false;
+
+ boolean has_port = true;
+ int from = 0;
+ int next = original.indexOf('@');
+ if (next != -1) { // neither -1 and 0
+ // each protocol extented from URI supports the specific userinfo
+ _userinfo = (escaped) ? original.substring(0, next).toCharArray()
+ : encode(original.substring(0, next), allowed_userinfo);
+ from = next + 1;
+ }
+ next = original.indexOf('[', from);
+ if (next >= from) {
+ next = original.indexOf(']', from);
+ if (next == -1) {
+ throw new IOException(/* IOException.PARSING, */ "URI: IPv6reference");
+ } else {
+ next++;
+ }
+ // In IPv6reference, '[', ']' should be excluded
+ _host = (escaped) ? original.substring(from, next).toCharArray()
+ : encode(original.substring(from, next), allowed_IPv6reference);
+ // Set flag
+ _is_IPv6reference = true;
+ } else { // only for !_is_IPv6reference
+ next = original.indexOf(':', from);
+ if (next == -1) {
+ next = original.length();
+ has_port = false;
+ }
+ // REMINDME: it doesn't need the pre-validation
+ _host = original.substring(from, next).toCharArray();
+ if (validate(_host, IPv4address)) {
+ // Set flag
+ _is_IPv4address = true;
+ } else if (validate(_host, hostname)) {
+ // Set flag
+ _is_hostname = true;
+ } else {
+ // Set flag
+ _is_reg_name = true;
+ }
+ }
+ if (_is_reg_name) {
+ // Reset flags for a server-based naming authority
+ _is_server = _is_hostname = _is_IPv4address = _is_IPv6reference = false;
+ // set a registry-based naming authority
+ _authority = (escaped) ? original.toString().toCharArray() : encode(original.toString(), allowed_reg_name);
+ } else {
+ if (original.length() - 1 > next && has_port && original.charAt(next) == ':') { // not empty
+ from = next + 1;
+ try {
+ _port = Integer.parseInt(original.substring(from));
+ } catch (NumberFormatException error) {
+ throw new IOException(/* IOException.PARSING, */
+ "URI: invalid port number");
+ }
+ }
+ // set a server-based naming authority
+ StringBuffer buf = new StringBuffer();
+ if (_userinfo != null) { // has_userinfo
+ buf.append(_userinfo);
+ buf.append('@');
+ }
+ if (_host != null) {
+ buf.append(_host);
+ if (_port != -1) {
+ buf.append(':');
+ buf.append(_port);
+ }
+ }
+ _authority = buf.toString().toCharArray();
+ // Set flag
+ _is_server = true;
+ }
+ }
+
+ /**
+ * Once it's parsed successfully, set this URI.
+ *
+ * @see #getRawURI
+ */
+ protected void setUriReference() {
+ // set _uri
+ StringBuffer buf = new StringBuffer();
+ // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ if (_scheme != null) {
+ buf.append(_scheme);
+ buf.append(':');
+ }
+ if (_is_net_path) {
+ buf.append("//");
+ if (_authority != null) { // has_authority
+ if (_userinfo != null) { // by default, remove userinfo part
+ if (_host != null) {
+ buf.append(_host);
+ if (_port != -1) {
+ buf.append(':');
+ buf.append(_port);
+ }
+ }
+ } else {
+ buf.append(_authority);
+ }
+ }
+ }
+ if (_opaque != null && _is_opaque_part) {
+ buf.append(_opaque);
+ } else if (_path != null) {
+ // _is_hier_part or _is_relativeURI
+ if (_path.length != 0) {
+ buf.append(_path);
+ }
+ }
+ if (_query != null) { // has_query
+ buf.append('?');
+ buf.append(_query);
+ }
+ if (_fragment != null) { // has_fragment
+ buf.append('#');
+ buf.append(_fragment);
+ }
+
+ _uri = buf.toString().toCharArray();
+ }
+
+ // ----------------------------------------------------------- Test methods
+
+ /**
+ * Tell whether or not this URI is absolute.
+ *
+ * @return true iif this URI is absoluteURI
+ */
+ public boolean isAbsoluteURI() {
+ return (_scheme != null);
+ }
+
+ /**
+ * Tell whether or not this URI is relative.
+ *
+ * @return true iif this URI is relativeURI
+ */
+ public boolean isRelativeURI() {
+ return (_scheme == null);
+ }
+
+ /**
+ * Tell whether or not the absoluteURI of this URI is hier_part.
+ *
+ * @return true iif the absoluteURI is hier_part
+ */
+ public boolean isHierPart() {
+ return _is_hier_part;
+ }
+
+ /**
+ * Tell whether or not the absoluteURI of this URI is opaque_part.
+ *
+ * @return true iif the absoluteURI is opaque_part
+ */
+ public boolean isOpaquePart() {
+ return _is_opaque_part;
+ }
+
+ /**
+ * Tell whether or not the relativeURI or heir_part of this URI is net_path.
+ * It's the same function as the has_authority() method.
+ *
+ * @return true iif the relativeURI or heir_part is net_path
+ * @see #hasAuthority
+ */
+ public boolean isNetPath() {
+ return _is_net_path || (_authority != null);
+ }
+
+ /**
+ * Tell whether or not the relativeURI or hier_part of this URI is abs_path.
+ *
+ * @return true iif the relativeURI or hier_part is abs_path
+ */
+ public boolean isAbsPath() {
+ return _is_abs_path;
+ }
+
+ /**
+ * Tell whether or not the relativeURI of this URI is rel_path.
+ *
+ * @return true iif the relativeURI is rel_path
+ */
+ public boolean isRelPath() {
+ return _is_rel_path;
+ }
+
+ /**
+ * Tell whether or not this URI has authority. It's the same function as the
+ * is_net_path() method.
+ *
+ * @return true iif this URI has authority
+ * @see #isNetPath
+ */
+ public boolean hasAuthority() {
+ return (_authority != null) || _is_net_path;
+ }
+
+ /**
+ * Tell whether or not the authority component of this URI is reg_name.
+ *
+ * @return true iif the authority component is reg_name
+ */
+ public boolean isRegName() {
+ return _is_reg_name;
+ }
+
+ /**
+ * Tell whether or not the authority component of this URI is server.
+ *
+ * @return true iif the authority component is server
+ */
+ public boolean isServer() {
+ return _is_server;
+ }
+
+ /**
+ * Tell whether or not this URI has userinfo.
+ *
+ * @return true iif this URI has userinfo
+ */
+ public boolean hasUserinfo() {
+ return (_userinfo != null);
+ }
+
+ /**
+ * Tell whether or not the host part of this URI is hostname.
+ *
+ * @return true iif the host part is hostname
+ */
+ public boolean isHostname() {
+ return _is_hostname;
+ }
+
+ /**
+ * Tell whether or not the host part of this URI is IPv4address.
+ *
+ * @return true iif the host part is IPv4address
+ */
+ public boolean isIPv4address() {
+ return _is_IPv4address;
+ }
+
+ /**
+ * Tell whether or not the host part of this URI is IPv6reference.
+ *
+ * @return true iif the host part is IPv6reference
+ */
+ public boolean isIPv6reference() {
+ return _is_IPv6reference;
+ }
+
+ /**
+ * Tell whether or not this URI has query.
+ *
+ * @return true iif this URI has query
+ */
+ public boolean hasQuery() {
+ return (_query != null);
+ }
+
+ /**
+ * Tell whether or not this URI has fragment.
+ *
+ * @return true iif this URI has fragment
+ */
+ public boolean hasFragment() {
+ return (_fragment != null);
+ }
+
+ // ---------------------------------------------------------------- Charset
+
+ /**
+ * Set the default charset of the protocol.
+ * <p>
+ * The character set used to store files SHALL remain a local decision and MAY
+ * depend on the capability of local operating systems. Prior to the exchange of
+ * URIs they SHOULD be converted into a ISO/IEC 10646 format and UTF-8 encoded.
+ * This approach, while allowing international exchange of URIs, will still
+ * allow backward compatibility with older systems because the code set
+ * positions for ASCII characters are identical to the one byte sequence in
+ * UTF-8.
+ * <p>
+ * An individual URI scheme may require a single charset, define a default
+ * charset, or provide a way to indicate the charset used.
+ *
+ * @param charset the default charset for each protocol
+ */
+ public static void setProtocolCharset(String charset) {
+ _protocolCharset = charset;
+ }
+
+ /**
+ * Get the default charset of the protocol.
+ * <p>
+ * An individual URI scheme may require a single charset, define a default
+ * charset, or provide a way to indicate the charset used.
+ * <p>
+ * To work globally either requires support of a number of character sets and to
+ * be able to convert between them, or the use of a single preferred character
+ * set. For support of global compatibility it is STRONGLY RECOMMENDED that
+ * clients and servers use UTF-8 encoding when exchanging URIs.
+ *
+ * @return the charset string
+ */
+ public static String getProtocolCharset() {
+ return _protocolCharset;
+ }
+
+ /**
+ * Set the default charset of the document.
+ * <p>
+ * Notice that it will be possible to contain mixed characters (e.g.
+ * ftp://host/KoreanNamespace/ChineseResource). To handle the Bi-directional
+ * display of these character sets, the protocol charset could be simply used
+ * again. Because it's not yet implemented that the insertion of BIDI control
+ * characters at different points during composition is extracted.
+ *
+ * @param charset the default charset for the document
+ */
+ public static void setDocumentCharset(String charset) {
+ _documentCharset = charset;
+ }
+
+ /**
+ * Get the default charset of the document.
+ *
+ * @return the charset string
+ */
+ public static String getDocumentCharset() {
+ return _documentCharset;
+ }
+
+ // ------------------------------------------------------------- The scheme
+
+ /**
+ * Get the scheme.
+ *
+ * @return the scheme
+ */
+ public char[] getRawScheme() {
+ return _scheme;
+ }
+
+ /**
+ * Get the scheme.
+ *
+ * @return the scheme null if undefined scheme
+ */
+ public String getScheme() {
+ return (_scheme == null) ? null : new String(_scheme);
+ }
+
+ // ---------------------------------------------------------- The authority
+
+ /**
+ * Set the authority. It can be one type of server, hostport, hostname,
+ * IPv4address, IPv6reference and reg_name.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * authority = server | reg_name
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @param escapedAuthority the raw escaped authority
+ * @exception IOException
+ * @throws NullPointerException null authority
+ */
+ public void setRawAuthority(char[] escapedAuthority) throws IOException {
+ parseAuthority(new String(escapedAuthority), true);
+ setUriReference();
+ }
+
+ /**
+ * Set the authority. It can be one type of server, hostport, hostname,
+ * IPv4address, IPv6reference and reg_name. Note that there is no setAuthority
+ * method by the escape encoding reason.
+ *
+ * @param escapedAuthority the escaped authority string
+ * @exception IOException
+ */
+ public void setEscapedAuthority(String escapedAuthority) throws IOException {
+
+ parseAuthority(escapedAuthority, true);
+ setUriReference();
+ }
+
+ /**
+ * Get the raw-escaped authority.
+ *
+ * @return the raw-escaped authority
+ */
+ public char[] getRawAuthority() {
+ return _authority;
+ }
+
+ /**
+ * Get the escaped authority.
+ *
+ * @return the escaped authority
+ */
+ public String getEscapedAuthority() {
+ return (_authority == null) ? null : new String(_authority);
+ }
+
+ /**
+ * Get the authority.
+ *
+ * @return the authority
+ * @exception IOException
+ * @see #decode
+ */
+ public String getAuthority() throws IOException {
+ return (_authority == null) ? null : decode(_authority);
+ }
+
+ // ----------------------------------------------------------- The userinfo
+
+ /**
+ * Get the raw-escaped userinfo.
+ *
+ * @return the raw-escaped userinfo
+ * @see #getAuthority
+ */
+ public char[] getRawUserinfo() {
+ return _userinfo;
+ }
+
+ /**
+ * Get the escaped userinfo.
+ *
+ * @return the escaped userinfo
+ * @see #getAuthority
+ */
+ public String getEscapedUserinfo() {
+ return (_userinfo == null) ? null : new String(_userinfo);
+ }
+
+ /**
+ * Get the userinfo.
+ *
+ * @return the userinfo
+ * @exception IOException
+ * @see #decode
+ * @see #getAuthority
+ */
+ public String getUserinfo() throws IOException {
+ return (_userinfo == null) ? null : decode(_userinfo);
+ }
+
+ // --------------------------------------------------------------- The host
+
+ /**
+ * Get the host.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * host = hostname | IPv4address | IPv6reference
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @return the host
+ * @see #getAuthority
+ */
+ public char[] getRawHost() {
+ return _host;
+ }
+
+ /**
+ * Get the host.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * host = hostname | IPv4address | IPv6reference
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @return the host
+ * @exception IOException
+ * @see #decode
+ * @see #getAuthority
+ */
+ public String getHost() throws IOException {
+ return decode(_host);
+ }
+
+ // --------------------------------------------------------------- The port
+
+ /**
+ * Get the port. In order to get the specfic default port, the specific
+ * protocol-supported class extended from the URI class should be used. It has
+ * the server-based naming authority.
+ *
+ * @return the port if -1, it has the default port for the scheme or the
+ * server-based naming authority is not supported in the specific URI.
+ */
+ public int getPort() {
+ return _port;
+ }
+
+ // --------------------------------------------------------------- The path
+
+ /**
+ * Set the path. The method couldn't be used by API programmers.
+ *
+ * @param path the path string
+ * @exception IOException set incorrectly or fragment only
+ * @see #encode
+ */
+ protected void setPath(String path) throws IOException {
+
+ // set path
+ if (_is_net_path || _is_abs_path) {
+ _path = encode(path, allowed_abs_path);
+ } else if (_is_rel_path) {
+ StringBuffer buff = new StringBuffer(path.length());
+ int at = path.indexOf('/');
+ if (at > 0) { // never 0
+ buff.append(encode(path.substring(0, at), allowed_rel_path));
+ buff.append(encode(path.substring(at), allowed_abs_path));
+ } else {
+ buff.append(encode(path, allowed_rel_path));
+ }
+ _path = buff.toString().toCharArray();
+ } else if (_is_opaque_part) {
+ _opaque = encode(path, allowed_opaque_part);
+ } else {
+ throw new IOException(/* IOException.PARSING, */"URI: incorrect path");
+ }
+ }
+
+ /**
+ * Resolve the base and relative path.
+ *
+ * @param base_path a character array of the base_path
+ * @param rel_path a character array of the rel_path
+ * @return the resolved path
+ */
+ protected char[] resolvePath(char[] base_path, char[] rel_path) {
+
+ // REMINDME: paths are never null
+ String base = (base_path == null) ? "" : new String(base_path);
+ int at = base.lastIndexOf('/');
+ if (at != -1) {
+ base_path = base.substring(0, at + 1).toCharArray();
+ }
+ // _path could be empty
+ if (rel_path == null || rel_path.length == 0) {
+ return normalize(base_path);
+ } else if (rel_path[0] == '/') {
+ return rel_path;
+ } else {
+ StringBuffer buff = new StringBuffer(base.length() + rel_path.length);
+ if (at != -1) {
+ buff.append(base.substring(0, at + 1));
+ buff.append(rel_path);
+ }
+ return normalize(buff.toString().toCharArray());
+ }
+ }
+
+ /**
+ * Get the raw-escaped current hierarchy level in the given path. If the last
+ * namespace is a collection, the slash mark ('/') should be ended with at the
+ * last character of the path string.
+ *
+ * @param path the path
+ * @return the current hierarchy level
+ * @exception IOException no hierarchy level
+ */
+ protected char[] getRawCurrentHierPath(char[] path) throws IOException {
+
+ if (_is_opaque_part) {
+ throw new IOException(/* IOException.PARSING, */ "URI: no hierarchy level");
+ }
+ if (path == null) {
+ throw new IOException(/* IOException.PARSING, */ "URI: emtpy path");
+ }
+ String buff = new String(path);
+ int first = buff.indexOf('/');
+ int last = buff.lastIndexOf('/');
+ if (last == 0) {
+ return rootPath;
+ } else if (first != last && last != -1) {
+ return buff.substring(0, last).toCharArray();
+ }
+ // FIXME: it could be a document on the server side
+ return path;
+ }
+
+ /**
+ * Get the raw-escaped current hierarchy level.
+ *
+ * @return the raw-escaped current hierarchy level
+ * @exception IOException no hierarchy level
+ */
+ public char[] getRawCurrentHierPath() throws IOException {
+ return (_path == null) ? null : getRawCurrentHierPath(_path);
+ }
+
+ /**
+ * Get the escaped current hierarchy level.
+ *
+ * @return the escaped current hierarchy level
+ * @exception IOException no hierarchy level
+ */
+ public String getEscapedCurrentHierPath() throws IOException {
+ char[] path = getRawCurrentHierPath();
+ return (path == null) ? null : new String(path);
+ }
+
+ /**
+ * Get the current hierarchy level.
+ *
+ * @return the current hierarchy level
+ * @exception IOException
+ * @see #decode
+ */
+ public String getCurrentHierPath() throws IOException {
+ char[] path = getRawCurrentHierPath();
+ return (path == null) ? null : decode(path);
+ }
+
+ /**
+ * Get the level above the this hierarchy level.
+ *
+ * @return the raw above hierarchy level
+ * @exception IOException
+ */
+ public char[] getRawAboveHierPath() throws IOException {
+ char[] path = getRawCurrentHierPath();
+ return (path == null) ? null : getRawCurrentHierPath(path);
+ }
+
+ /**
+ * Get the level above the this hierarchy level.
+ *
+ * @return the raw above hierarchy level
+ * @exception IOException
+ */
+ public String getEscapedAboveHierPath() throws IOException {
+ char[] path = getRawAboveHierPath();
+ return (path == null) ? null : new String(path);
+ }
+
+ /**
+ * Get the level above the this hierarchy level.
+ *
+ * @return the above hierarchy level
+ * @exception IOException
+ * @see #decode
+ */
+ public String getAboveHierPath() throws IOException {
+ char[] path = getRawAboveHierPath();
+ return (path == null) ? null : decode(path);
+ }
+
+ /**
+ * Get the raw-escaped path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path = [ abs_path | opaque_part ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @return the raw-escaped path
+ */
+ public char[] getRawPath() {
+ return _is_opaque_part ? _opaque : _path;
+ }
+
+ /**
+ * Get the escaped path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path = [ abs_path | opaque_part ]
+ * abs_path = "/" path_segments
+ * opaque_part = uric_no_slash *uric
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @return the escaped path string
+ */
+ public String getEscapedPath() {
+ char[] path = getRawPath();
+ return (path == null) ? null : new String(path);
+ }
+
+ /**
+ * Get the path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path = [ abs_path | opaque_part ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @return the path string
+ * @exception IOException
+ * @see #decode
+ */
+ public String getPath() throws IOException {
+ char[] path = getRawPath();
+ return (path == null) ? null : decode(path);
+ }
+
+ /**
+ * Get the raw-escaped basename of the path.
+ *
+ * @return the raw-escaped basename
+ */
+ public char[] getRawName() {
+ if (_path == null)
+ return null;
+
+ int at = 0;
+ for (int i = _path.length - 1; i >= 0; i--) {
+ if (_path[i] == '/') {
+ at = i + 1;
+ break;
+ }
+ }
+ int len = _path.length - at;
+ char[] basename = new char[len];
+ System.arraycopy(_path, at, basename, 0, len);
+ return basename;
+ }
+
+ /**
+ * Get the escaped basename of the path.
+ *
+ * @return the escaped basename string
+ */
+ public String getEscapedName() {
+ char[] basename = getRawName();
+ return (basename == null) ? null : new String(basename);
+ }
+
+ /**
+ * Get the basename of the path.
+ *
+ * @return the basename string
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @see #decode
+ */
+ public String getName() throws IOException {
+ char[] basename = getRawName();
+ return (basename == null) ? null : decode(getRawName());
+ }
+
+ // ----------------------------------------------------- The path and query
+
+ /**
+ * Get the raw-escaped path and query.
+ *
+ * @return the raw-escaped path and query
+ */
+ public char[] getRawPathQuery() {
+
+ if (_path == null && _query == null) {
+ return null;
+ }
+ StringBuffer buff = new StringBuffer();
+ if (_path != null) {
+ buff.append(_path);
+ }
+ if (_query != null) {
+ buff.append('?');
+ buff.append(_query);
+ }
+ return buff.toString().toCharArray();
+ }
+
+ /**
+ * Get the escaped query.
+ *
+ * @return the escaped path and query string
+ */
+ public String getEscapedPathQuery() {
+ char[] rawPathQuery = getRawPathQuery();
+ return (rawPathQuery == null) ? null : new String(rawPathQuery);
+ }
+
+ /**
+ * Get the path and query.
+ *
+ * @return the path and query string.
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @see #decode
+ */
+ public String getPathQuery() throws IOException {
+ char[] rawPathQuery = getRawPathQuery();
+ return (rawPathQuery == null) ? null : decode(rawPathQuery);
+ }
+
+ // -------------------------------------------------------------- The query
+
+ /**
+ * Set the raw-escaped query.
+ *
+ * @param escapedQuery the raw-escaped query
+ * @exception IOException escaped query not valid
+ * @throws NullPointerException null query
+ */
+ public void setRawQuery(char[] escapedQuery) throws IOException {
+ if (!validate(escapedQuery, query))
+ throw new IOException(/* IOException.ESCAPING, */
+ "URI: escaped query not valid");
+ _query = escapedQuery;
+ setUriReference();
+ }
+
+ /**
+ * Set the escaped query string.
+ *
+ * @param escapedQuery the escaped query string
+ * @exception IOException escaped query not valid
+ * @throws NullPointerException null query
+ */
+ public void setEscapedQuery(String escapedQuery) throws IOException {
+ setRawQuery(escapedQuery.toCharArray());
+ }
+
+ /**
+ * Set the query. When a query string is not misunderstood the reserved special
+ * characters ("&amp;", "=", "+", ",", and "$") within a query component, it is
+ * recommended to use in encoding the whole query with this method.
+ *
+ * @param query the query string.
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @throws NullPointerException null query
+ * @see #encode
+ */
+ public void setQuery(String query) throws IOException {
+ setRawQuery(encode(query, allowed_query));
+ }
+
+ /**
+ * Get the raw-escaped query.
+ *
+ * @return the raw-escaped query
+ */
+ public char[] getRawQuery() {
+ return _query;
+ }
+
+ /**
+ * Get the escaped query.
+ *
+ * @return the escaped query string
+ */
+ public String getEscapedQuery() {
+ return (_query == null) ? null : new String(_query);
+ }
+
+ /**
+ * Get the query.
+ *
+ * @return the query string.
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @see #decode
+ */
+ public String getQuery() throws IOException {
+ return (_query == null) ? null : decode(_query);
+ }
+
+ // ----------------------------------------------------------- The fragment
+
+ /**
+ * Set the raw-escaped fragment.
+ *
+ * @param escapedFragment the raw-escaped fragment
+ * @exception IOException escaped fragment not valid
+ * @throws NullPointerException null fragment
+ */
+ public void setRawFragment(char[] escapedFragment) throws IOException {
+ if (!validate(escapedFragment, fragment))
+ throw new IOException(/* IOException.ESCAPING, */
+ "URI: escaped fragment not valid");
+ _fragment = escapedFragment;
+ setUriReference();
+ }
+
+ /**
+ * Set the escaped fragment string.
+ *
+ * @param escapedFragment the escaped fragment string
+ * @exception IOException escaped fragment not valid
+ * @throws NullPointerException null fragment
+ */
+ public void setEscapedFragment(String escapedFragment) throws IOException {
+ char[] fragmentSequence = escapedFragment.toCharArray();
+ if (!validate(fragmentSequence, fragment))
+ throw new IOException(/* IOException.ESCAPING, */
+ "URI: escaped fragment not valid");
+ _fragment = fragmentSequence;
+ setUriReference();
+ }
+
+ /**
+ * Set the fragment.
+ *
+ * @param the fragment string.
+ * @exception IOException Or unsupported character encoding
+ * @throws NullPointerException null fragment
+ */
+ public void setFragment(String fragment) throws IOException {
+ _fragment = encode(fragment, allowed_fragment);
+ setUriReference();
+ }
+
+ /**
+ * Get the raw-escaped fragment.
+ * <p>
+ * The optional fragment identifier is not part of a URI, but is often used in
+ * conjunction with a URI.
+ * <p>
+ * The format and interpretation of fragment identifiers is dependent on the
+ * media type [RFC2046] of the retrieval result.
+ * <p>
+ * A fragment identifier is only meaningful when a URI reference is intended for
+ * retrieval and the result of that retrieval is a document for which the
+ * identified fragment is consistently defined.
+ *
+ * @return the raw-escaped fragment
+ */
+ public char[] getRawFragment() {
+ return _fragment;
+ }
+
+ /**
+ * Get the escaped fragment.
+ *
+ * @return the escaped fragment string
+ */
+ public String getEscapedFragment() {
+ return (_fragment == null) ? null : new String(_fragment);
+ }
+
+ /**
+ * Get the fragment.
+ *
+ * @return the fragment string
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @see #decode
+ */
+ public String getFragment() throws IOException {
+ return (_fragment == null) ? null : decode(_fragment);
+ }
+
+ // ------------------------------------------------------------- Utilities
+
+ /**
+ * Normalize the given hier path part.
+ *
+ * @param path the path to normalize
+ * @return the normalized path
+ */
+ protected char[] normalize(char[] path) {
+
+ if (path == null)
+ return null;
+
+ String normalized = new String(path);
+ boolean endsWithSlash = true;
+ // precondition
+ if (!normalized.endsWith("/")) {
+ normalized += '/';
+ endsWithSlash = false;
+ }
+ if (normalized.endsWith("/./") || normalized.endsWith("/../")) {
+ endsWithSlash = true;
+ }
+ // Resolve occurrences of "/./" in the normalized path
+ while (true) {
+ int at = normalized.indexOf("/./");
+ if (at == -1) {
+ break;
+ }
+ normalized = normalized.substring(0, at) + normalized.substring(at + 2);
+ }
+ // Resolve occurrences of "/../" in the normalized path
+ while (true) {
+ int at = normalized.indexOf("/../");
+ if (at == -1) {
+ break;
+ }
+ if (at == 0) {
+ normalized = "/";
+ break;
+ }
+ int backward = normalized.lastIndexOf('/', at - 1);
+ if (backward == -1) {
+ // consider the rel_path
+ normalized = normalized.substring(at + 4);
+ } else {
+ normalized = normalized.substring(0, backward) + normalized.substring(at + 3);
+ }
+ }
+ // Resolve occurrences of "//" in the normalized path
+ while (true) {
+ int at = normalized.indexOf("//");
+ if (at == -1) {
+ break;
+ }
+ normalized = normalized.substring(0, at) + normalized.substring(at + 1);
+ }
+ if (!endsWithSlash && normalized.endsWith("/")) {
+ normalized = normalized.substring(0, normalized.length() - 1);
+ } else if (endsWithSlash && !normalized.endsWith("/")) {
+ normalized = normalized + "/";
+ }
+ // Set the normalized path that we have completed
+ return normalized.toCharArray();
+ }
+
+ /**
+ * Normalize the path part of this URI.
+ */
+ public void normalize() {
+ _path = normalize(_path);
+ }
+
+ /**
+ * Test if the first array is equal to the second array.
+ *
+ * @param first the first character array
+ * @param second the second character array
+ * @return true if they're equal
+ */
+ protected boolean equals(char[] first, char[] second) {
+
+ if (first == null && second == null) {
+ return true;
+ }
+ if (first == null || second == null) {
+ return false;
+ }
+ if (first.length != second.length) {
+ return false;
+ }
+ for (int i = 0; i < first.length; i++) {
+ if (first[i] != second[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Test an object if this URI is equal to another.
+ *
+ * @param obj an object to compare
+ * @return true if two URI objects are equal
+ */
+ public boolean equals(Object obj) {
+
+ // normalize and test each components
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof URI)) {
+ return false;
+ }
+ URI another = (URI) obj;
+ // scheme
+ if (!equals(_scheme, another._scheme)) {
+ return false;
+ }
+ // is_opaque_part or is_hier_part? and opaque
+ if (!equals(_opaque, another._opaque)) {
+ return false;
+ }
+ // is_hier_part
+ // has_authority
+ if (!equals(_authority, another._authority)) {
+ return false;
+ }
+ // path
+ if (!equals(_path, another._path)) {
+ return false;
+ }
+ // has_query
+ if (!equals(_query, another._query)) {
+ return false;
+ }
+ // has_fragment? should be careful of the only fragment case.
+ if (!equals(_fragment, another._fragment)) {
+ return false;
+ }
+ return true;
+ }
+
+ // ---------------------------------------------------------- Serialization
+
+ /**
+ * Write the content of this URI.
+ *
+ * @param oos the object-output stream
+ */
+ protected void writeObject(java.io.ObjectOutputStream oos) throws IOException {
+
+ oos.defaultWriteObject();
+ }
+
+ /**
+ * Read a URI.
+ *
+ * @param ois the object-input stream
+ */
+ protected void readObject(java.io.ObjectInputStream ois) throws ClassNotFoundException, IOException {
+
+ ois.defaultReadObject();
+ }
+
+ // ------------------------------------------------------------- Comparison
+
+ /**
+ * Compare this URI to another object.
+ *
+ * @param obj the object to be compared.
+ * @return 0, if it's same, -1, if failed, first being compared with in the
+ * authority component
+ * @exception ClassCastException not URI argument
+ * @throws NullPointerException null object
+ */
+ public int compareTo(Object obj) {
+
+ URI another = (URI) obj;
+ if (!equals(_authority, another.getRawAuthority()))
+ return -1;
+ return toString().compareTo(another.toString());
+ }
+
+ // ------------------------------------------------------------------ Clone
+
+ /**
+ * Create and return a copy of this object, the URI-reference containing the
+ * userinfo component. Notice that the whole URI-reference including the
+ * userinfo component counld not be gotten as a <code>String</code>.
+ * <p>
+ * To copy the identical <code>URI</code> object including the userinfo
+ * component, it should be used.
+ *
+ * @return a clone of this instance
+ */
+ public synchronized Object clone() {
+
+ URI instance = new URI();
+
+ instance._uri = _uri;
+ instance._scheme = _scheme;
+ instance._opaque = _opaque;
+ instance._authority = _authority;
+ instance._userinfo = _userinfo;
+ instance._host = _host;
+ instance._port = _port;
+ instance._path = _path;
+ instance._query = _query;
+ instance._fragment = _fragment;
+ // flags
+ instance._is_hier_part = _is_hier_part;
+ instance._is_opaque_part = _is_opaque_part;
+ instance._is_net_path = _is_net_path;
+ instance._is_abs_path = _is_abs_path;
+ instance._is_rel_path = _is_rel_path;
+ instance._is_reg_name = _is_reg_name;
+ instance._is_server = _is_server;
+ instance._is_hostname = _is_hostname;
+ instance._is_IPv4address = _is_IPv4address;
+ instance._is_IPv6reference = _is_IPv6reference;
+
+ return instance;
+ }
+
+ // ------------------------------------------------------------ Get the URI
+
+ /**
+ * It can be gotten the URI character sequence. It's raw-escaped. For the
+ * purpose of the protocol to be transported, it will be useful.
+ * <p>
+ * It is clearly unwise to use a URL that contains a password which is intended
+ * to be secret. In particular, the use of a password within the 'userinfo'
+ * component of a URL is strongly disrecommended except in those rare cases
+ * where the 'password' parameter is intended to be public.
+ * <p>
+ * When you want to get each part of the userinfo, you need to use the specific
+ * methods in the specific URL. It depends on the specific URL.
+ *
+ * @return URI character sequence
+ */
+ public char[] getRawURI() {
+ return _uri;
+ }
+
+ /**
+ * It can be gotten the URI character sequence. It's escaped. For the purpose of
+ * the protocol to be transported, it will be useful.
+ *
+ * @return the URI string
+ */
+ public String getEscapedURI() {
+ return (_uri == null) ? null : new String(_uri);
+ }
+
+ /**
+ * It can be gotten the URI character sequence.
+ *
+ * @return the URI string
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @see #decode
+ */
+ public String getURI() throws IOException {
+ return (_uri == null) ? null : decode(_uri);
+ }
+
+ /**
+ * Get the escaped URI string.
+ * <p>
+ * On the document, the URI-reference form is only used without the userinfo
+ * component like http://jakarta.apache.org/ by the security reason. But the
+ * URI-reference form with the userinfo component could be parsed.
+ * <p>
+ * In other words, this URI and any its subclasses must not expose the
+ * URI-reference expression with the userinfo component like
+ * http://user:password@hostport/restricted_zone.<br>
+ * It means that the API client programmer should extract each user and password
+ * to access manually. Probably it will be supported in the each subclass,
+ * however, not a whole URI-reference expression.
+ *
+ * @return the URI string
+ * @see #clone()
+ */
+ public String toString() {
+ return getEscapedURI();
+ }
+
+ // ------------------------------------------------------------ Inner class
+
+ /**
+ * A mapping to determine the (somewhat arbitrarily) preferred charset for a
+ * given locale. Supports all locales recognized in JDK 1.1.
+ * <p>
+ * The distribution of this class is Servlets.com. It was originally written by
+ * Jason Hunter [jhunter at acm.org] and used by with permission.
+ */
+ public static class LocaleToCharsetMap {
+
+ private static Hashtable map;
+ static {
+ map = new Hashtable();
+ map.put("ar", "ISO-8859-6");
+ map.put("be", "ISO-8859-5");
+ map.put("bg", "ISO-8859-5");
+ map.put("ca", "ISO-8859-1");
+ map.put("cs", "ISO-8859-2");
+ map.put("da", "ISO-8859-1");
+ map.put("de", "ISO-8859-1");
+ map.put("el", "ISO-8859-7");
+ map.put("en", "ISO-8859-1");
+ map.put("es", "ISO-8859-1");
+ map.put("et", "ISO-8859-1");
+ map.put("fi", "ISO-8859-1");
+ map.put("fr", "ISO-8859-1");
+ map.put("hr", "ISO-8859-2");
+ map.put("hu", "ISO-8859-2");
+ map.put("is", "ISO-8859-1");
+ map.put("it", "ISO-8859-1");
+ map.put("iw", "ISO-8859-8");
+ map.put("ja", "Shift_JIS");
+ map.put("ko", "EUC-KR");
+ map.put("lt", "ISO-8859-2");
+ map.put("lv", "ISO-8859-2");
+ map.put("mk", "ISO-8859-5");
+ map.put("nl", "ISO-8859-1");
+ map.put("no", "ISO-8859-1");
+ map.put("pl", "ISO-8859-2");
+ map.put("pt", "ISO-8859-1");
+ map.put("ro", "ISO-8859-2");
+ map.put("ru", "ISO-8859-5");
+ map.put("sh", "ISO-8859-5");
+ map.put("sk", "ISO-8859-2");
+ map.put("sl", "ISO-8859-2");
+ map.put("sq", "ISO-8859-2");
+ map.put("sr", "ISO-8859-5");
+ map.put("sv", "ISO-8859-1");
+ map.put("tr", "ISO-8859-9");
+ map.put("uk", "ISO-8859-5");
+ map.put("zh", "GB2312");
+ map.put("zh_TW", "Big5");
+ }
+
+ /**
+ * Get the preferred charset for the given locale.
+ *
+ * @param locale the locale
+ * @return the preferred charset or null if the locale is not recognized
+ */
+ public static String getCharset(Locale locale) {
+ // try for an full name match (may include country)
+ String charset = (String) map.get(locale.toString());
+ if (charset != null)
+ return charset;
+
+ // if a full name didn't match, try just the language
+ charset = (String) map.get(locale.getLanguage());
+ return charset; // may be null
+ }
+
+ }
}
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionResults.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionResults.java
index 377345c..cc95697 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionResults.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionResults.java
@@ -19,33 +19,27 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web;
/**
-* An interface defining the results of a DirectAction.
-* Implemented by both WOResponse and WOComponent so both
-* can be returned from a DirectAction.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public interface WOActionResults
-{
-/**
-* Returns a response object as appropriate for the target.
-*/
- WOResponse generateResponse ();
+ * An interface defining the results of a DirectAction. Implemented by both
+ * WOResponse and WOComponent so both can be returned from a DirectAction.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public interface WOActionResults {
+ /**
+ * Returns a response object as appropriate for the target.
+ */
+ WOResponse generateResponse();
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:52:44 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:44 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionURL.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionURL.java
index 78191b6..86e7807 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionURL.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionURL.java
@@ -21,20 +21,23 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
- * This dynamic element renders only the URL of a hyperlink.
- * Bindings are:
+ * This dynamic element renders only the URL of a hyperlink. Bindings are:
* <ul>
* <li>href: The URL that the hyperlink should point to.</li>
- * <li>pageName: The name of the WOComponent that the hyperlink should point to.</li>
- * <li>directActionName: The name of the direct action to call when the link is activated.</li>
- * <li>actionClass: The name of the WODirectAction subclass where the direct action resides.</li>
- * <li>action: A pointer to a method on the component that contains this element. If the link is activated,
- * the method will be called.
+ * <li>pageName: The name of the WOComponent that the hyperlink should point
+ * to.</li>
+ * <li>directActionName: The name of the direct action to call when the link is
+ * activated.</li>
+ * <li>actionClass: The name of the WODirectAction subclass where the direct
+ * action resides.</li>
+ * <li>action: A pointer to a method on the component that contains this
+ * element. If the link is activated, the method will be called.
* <li>ref: The name of the anchor to go to inside the resulting page.</li>
* </ul>
*
- * The href, pageName and directActionName/actionClass and name properties are mutually exclusive and you should
- * only use at most one of them simultaneously.
+ * The href, pageName and directActionName/actionClass and name properties are
+ * mutually exclusive and you should only use at most one of them
+ * simultaneously.
*
* @author ezamudio@nasoft.com
* @author $Author: cgruber $
@@ -42,16 +45,16 @@ import net.wotonomy.foundation.NSDictionary;
*/
public class WOActionURL extends WOHyperlink {
- public WOActionURL() {
- super();
- }
+ public WOActionURL() {
+ super();
+ }
- public WOActionURL(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOActionURL(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString(actionURL(c));
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString(actionURL(c));
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActiveImage.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActiveImage.java
index cad6f64..bf80b3e 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActiveImage.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActiveImage.java
@@ -7,8 +7,9 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableDictionary;
/**
- * WOActiveImage renders a dynamically generated IMG tag, enclosed in a hyperlink.
- * Internally, it uses a WOImage and a WOHyperlink to do the actual work.
+ * WOActiveImage renders a dynamically generated IMG tag, enclosed in a
+ * hyperlink. Internally, it uses a WOImage and a WOHyperlink to do the actual
+ * work.
*
* The bindings are those of WOImage and WOHyperlink combined.
*
@@ -18,64 +19,64 @@ import net.wotonomy.foundation.NSMutableDictionary;
*/
public class WOActiveImage extends WODynamicElement {
- protected WOActiveImage() {
- super();
- }
+ protected WOActiveImage() {
+ super();
+ }
- public WOActiveImage(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
+ public WOActiveImage(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- NSMutableDictionary atribs = new NSMutableDictionary(5);
- if (associations.objectForKey("mimeType") != null)
- atribs.setObjectForKey(associations.objectForKey("mimeType"), "mimeType");
- if (associations.objectForKey("data") != null)
- atribs.setObjectForKey(associations.objectForKey("data"), "data");
- if (associations.objectForKey("src") != null)
- atribs.setObjectForKey(associations.objectForKey("src"), "src");
- if (associations.objectForKey("framework") != null)
- atribs.setObjectForKey(associations.objectForKey("framework"), "framework");
- if (associations.objectForKey("filename") != null)
- atribs.setObjectForKey(associations.objectForKey("filename"), "filename");
- if (associations.objectForKey("alt") != null)
- atribs.setObjectForKey(associations.objectForKey("alt"), "alt");
- if (associations.objectForKey("border") != null)
- atribs.setObjectForKey(associations.objectForKey("border"), "border");
- if (associations.objectForKey("width") != null)
- atribs.setObjectForKey(associations.objectForKey("width"), "width");
- if (associations.objectForKey("height") != null)
- atribs.setObjectForKey(associations.objectForKey("height"), "height");
- WODynamicElement img = new WOImage("WOImage_" + name, atribs, null);
- NSMutableDictionary uf = new NSMutableDictionary();
- Enumeration enumeration = associations.keyEnumerator();
- while (enumeration.hasMoreElements()) {
- String key = (String)enumeration.nextElement();
- if (key.startsWith("?"))
- uf.setObjectForKey(associations.objectForKey(key), key);
- }
- createLink(img).appendToResponse(r, c);
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ NSMutableDictionary atribs = new NSMutableDictionary(5);
+ if (associations.objectForKey("mimeType") != null)
+ atribs.setObjectForKey(associations.objectForKey("mimeType"), "mimeType");
+ if (associations.objectForKey("data") != null)
+ atribs.setObjectForKey(associations.objectForKey("data"), "data");
+ if (associations.objectForKey("src") != null)
+ atribs.setObjectForKey(associations.objectForKey("src"), "src");
+ if (associations.objectForKey("framework") != null)
+ atribs.setObjectForKey(associations.objectForKey("framework"), "framework");
+ if (associations.objectForKey("filename") != null)
+ atribs.setObjectForKey(associations.objectForKey("filename"), "filename");
+ if (associations.objectForKey("alt") != null)
+ atribs.setObjectForKey(associations.objectForKey("alt"), "alt");
+ if (associations.objectForKey("border") != null)
+ atribs.setObjectForKey(associations.objectForKey("border"), "border");
+ if (associations.objectForKey("width") != null)
+ atribs.setObjectForKey(associations.objectForKey("width"), "width");
+ if (associations.objectForKey("height") != null)
+ atribs.setObjectForKey(associations.objectForKey("height"), "height");
+ WODynamicElement img = new WOImage("WOImage_" + name, atribs, null);
+ NSMutableDictionary uf = new NSMutableDictionary();
+ Enumeration enumeration = associations.keyEnumerator();
+ while (enumeration.hasMoreElements()) {
+ String key = (String) enumeration.nextElement();
+ if (key.startsWith("?"))
+ uf.setObjectForKey(associations.objectForKey(key), key);
+ }
+ createLink(img).appendToResponse(r, c);
+ }
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- return createLink(null).invokeAction(r, c);
- }
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ return createLink(null).invokeAction(r, c);
+ }
- protected WOHyperlink createLink(WOElement e) {
- NSMutableDictionary atribs = new NSMutableDictionary(5);
- if (associations.objectForKey("href") != null)
- atribs.setObjectForKey(associations.objectForKey("href"), "href");
- if (associations.objectForKey("pageName") != null)
- atribs.setObjectForKey(associations.objectForKey("pageName"), "pageName");
- if (associations.objectForKey("action") != null)
- atribs.setObjectForKey(associations.objectForKey("action"), "action");
- if (associations.objectForKey("directActionName") != null)
- atribs.setObjectForKey(associations.objectForKey("directActionName"), "directActionName");
- if (associations.objectForKey("actionClass") != null)
- atribs.setObjectForKey(associations.objectForKey("actionClass"), "actionClass");
- if (associations.objectForKey("target") != null)
- atribs.setObjectForKey(associations.objectForKey("target"), "target");
- return new WOHyperlink(name, atribs, e);
- }
+ protected WOHyperlink createLink(WOElement e) {
+ NSMutableDictionary atribs = new NSMutableDictionary(5);
+ if (associations.objectForKey("href") != null)
+ atribs.setObjectForKey(associations.objectForKey("href"), "href");
+ if (associations.objectForKey("pageName") != null)
+ atribs.setObjectForKey(associations.objectForKey("pageName"), "pageName");
+ if (associations.objectForKey("action") != null)
+ atribs.setObjectForKey(associations.objectForKey("action"), "action");
+ if (associations.objectForKey("directActionName") != null)
+ atribs.setObjectForKey(associations.objectForKey("directActionName"), "directActionName");
+ if (associations.objectForKey("actionClass") != null)
+ atribs.setObjectForKey(associations.objectForKey("actionClass"), "actionClass");
+ if (associations.objectForKey("target") != null)
+ atribs.setObjectForKey(associations.objectForKey("target"), "target");
+ return new WOHyperlink(name, atribs, e);
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOApplication.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOApplication.java
index 90e40c6..46b598c 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOApplication.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOApplication.java
@@ -37,1157 +37,982 @@ import org.mortbay.jetty.servlet.ServletHandler;
import org.mortbay.util.InetAddrPort;
/**
-* A pure java implementation of WOApplication. <br><br>
-*
-* The application is responsible for creating and managing sessions
-* and dispatching requests to the appropriate handlers. <br><br>
-*
-* This implementation extends HttpServlet, so the application itself
-* is a servlet and can be configured and managed as such by the servlet
-* container.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOApplication
- extends HttpServlet
-{
- /**
- * A tricky way to allow multiple WOApplications
- * in the same servlet container.
- */
- static private ThreadLocal threadLocal;
- //static private WOApplication application;
-
- /**
- * Determines application-wide page caching.
- * Pages may individually prevent caching.
- */
- static private boolean cachingEnabled = false;
- private static boolean autoOpenInBrowser = true;
-
- private String name;
+ * A pure java implementation of WOApplication. <br>
+ * <br>
+ *
+ * The application is responsible for creating and managing sessions and
+ * dispatching requests to the appropriate handlers. <br>
+ * <br>
+ *
+ * This implementation extends HttpServlet, so the application itself is a
+ * servlet and can be configured and managed as such by the servlet container.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOApplication extends HttpServlet {
+ /**
+ * A tricky way to allow multiple WOApplications in the same servlet container.
+ */
+ static private ThreadLocal threadLocal;
+ // static private WOApplication application;
+
+ /**
+ * Determines application-wide page caching. Pages may individually prevent
+ * caching.
+ */
+ static private boolean cachingEnabled = false;
+ private static boolean autoOpenInBrowser = true;
+
+ private String name;
private WORequestHandler defaultRequestHandler;
- private NSMutableDictionary requestHandlers;
- private WOSessionStore sessionStore;
- private WOResourceManager resourceManager;
- private boolean pageRefreshOnBacktrack;
- private int pageCacheSize;
- private int permanentPageCacheSize;
-
- public static final String WOApplicationWillFinishLaunchingNotification
- = "WOApplicationWillFinishLaunchingNotification";
- public static final String WOApplicationDidFinishLaunchingNotification
- = "WOApplicationDidFinishLaunchingNotification";
- public static final String WOGarbageCollectionPeriodKey
- = "WOGarbageCollectionPeriodKey";
-
- static String _DirectActionRequestHandlerKey = "_DirectActionRequestHandlerKey";
- static String _ComponentRequestHandlerKey = "_ComponentRequestHandlerKey";
- static String _ResourceRequestHandlerKey = "_ResourceRequestHandlerKey";
- static String WOPort = "WOPort";
- static String WOSMTPHost = "WOSMTPHost";
- static final String ELEMENT_CLASS = "elementClass";
-
- public WOApplication ()
- {
- if ( threadLocal == null )
- {
- threadLocal = new ThreadLocal();
- }
- threadLocal.set( this );
-
- //application = this;
- resourceManager = createResourceManager();
- requestHandlers = new NSMutableDictionary();
- defaultRequestHandler = new WODirectActionRequestHandler();
- registerRequestHandler( defaultRequestHandler, directActionRequestHandlerKey() );
- registerRequestHandler( new WOComponentRequestHandler(), componentRequestHandlerKey() );
- registerRequestHandler( new WOResourceRequestHandler(), resourceRequestHandlerKey() );
- sessionStore = WOSessionStore.serverSessionStore();
-
- pageRefreshOnBacktrack = true;
- pageCacheSize = 30;
- permanentPageCacheSize = 30;
-
- threadLocal.set( null );
- }
-
+ private NSMutableDictionary requestHandlers;
+ private WOSessionStore sessionStore;
+ private WOResourceManager resourceManager;
+ private boolean pageRefreshOnBacktrack;
+ private int pageCacheSize;
+ private int permanentPageCacheSize;
+
+ public static final String WOApplicationWillFinishLaunchingNotification = "WOApplicationWillFinishLaunchingNotification";
+ public static final String WOApplicationDidFinishLaunchingNotification = "WOApplicationDidFinishLaunchingNotification";
+ public static final String WOGarbageCollectionPeriodKey = "WOGarbageCollectionPeriodKey";
+
+ static String _DirectActionRequestHandlerKey = "_DirectActionRequestHandlerKey";
+ static String _ComponentRequestHandlerKey = "_ComponentRequestHandlerKey";
+ static String _ResourceRequestHandlerKey = "_ResourceRequestHandlerKey";
+ static String WOPort = "WOPort";
+ static String WOSMTPHost = "WOSMTPHost";
+ static final String ELEMENT_CLASS = "elementClass";
+
+ public WOApplication() {
+ if (threadLocal == null) {
+ threadLocal = new ThreadLocal();
+ }
+ threadLocal.set(this);
+
+ // application = this;
+ resourceManager = createResourceManager();
+ requestHandlers = new NSMutableDictionary();
+ defaultRequestHandler = new WODirectActionRequestHandler();
+ registerRequestHandler(defaultRequestHandler, directActionRequestHandlerKey());
+ registerRequestHandler(new WOComponentRequestHandler(), componentRequestHandlerKey());
+ registerRequestHandler(new WOResourceRequestHandler(), resourceRequestHandlerKey());
+ sessionStore = WOSessionStore.serverSessionStore();
+
+ pageRefreshOnBacktrack = true;
+ pageCacheSize = 30;
+ permanentPageCacheSize = 30;
+
+ threadLocal.set(null);
+ }
+
/**
- * Dispatches the request and updates the specified response
- * as appropriate. This implementation creates a new WORequest
- * and WOContext from the request, sends the response to the
- * appropriate WORequestHandler, and then updates the servlet
- * response from the resulting WOResponse.
- */
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, java.io.IOException
- {
- threadLocal.set( this );
-
- WORequest request = new WORequest( req, this );
- WOResponse response = dispatchRequest( request );
- response.generateServletResponse( resp );
- }
+ * Dispatches the request and updates the specified response as appropriate.
+ * This implementation creates a new WORequest and WOContext from the request,
+ * sends the response to the appropriate WORequestHandler, and then updates the
+ * servlet response from the resulting WOResponse.
+ */
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, java.io.IOException {
+ threadLocal.set(this);
+
+ WORequest request = new WORequest(req, this);
+ WOResponse response = dispatchRequest(request);
+ response.generateServletResponse(resp);
+ }
/**
- * Handles post requests by calling doGet(), since the framework
- * handles both gets and posts similarly. Override to handle
- * post requests in a different manner.
- */
- protected void doPost(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, java.io.IOException
- {
- doGet( req, resp );
+ * Handles post requests by calling doGet(), since the framework handles both
+ * gets and posts similarly. Override to handle post requests in a different
+ * manner.
+ */
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, java.io.IOException {
+ doGet(req, resp);
}
-
+
// obtaining attributes
-
+
+ /**
+ * Returns the singleton instance of this application.
+ */
+ public static WOApplication application() {
+ return (WOApplication) threadLocal.get();
+ // return application;
+ }
+
+ /**
+ * Returns the name of the application. This implementation returns the name the
+ * jar file or directory from which the class was loaded, with no extensions.
+ */
+ public String name() {
+ if (name == null) {
+ name = path();
+ int i;
+ if (name.endsWith("/")) { // path
+ name = name.substring(0, name.length() - 1);
+ } else { // jar file
+ i = name.lastIndexOf('.');
+ if (i != -1)
+ name = name.substring(0, i);
+ }
+ i = name.lastIndexOf('/');
+ if (i != -1)
+ name = name.substring(i + 1);
+ }
+ return name;
+ }
+
/**
- * Returns the singleton instance of this application.
- */
- public static WOApplication application()
- {
- return (WOApplication) threadLocal.get();
- //return application;
- }
-
+ * Returns the absolute path to the application on the local file system. Note
+ * that the application might be embedded inside of a jar file.
+ */
+ public String path() {
+ return getClass().getProtectionDomain().getCodeSource().getLocation().toString();
+ }
+
/**
- * Returns the name of the application. This implementation returns
- * the name the jar file or directory from which the class was loaded,
- * with no extensions.
- */
- public String name()
- {
- if ( name == null )
- {
- name = path();
- int i;
- if ( name.endsWith( "/" ) )
- { // path
- name = name.substring( 0, name.length() - 1 );
- }
- else
- { // jar file
- i = name.lastIndexOf( '.' );
- if ( i != -1 ) name = name.substring( 0, i );
- }
- i = name.lastIndexOf( '/' );
- if ( i != -1 ) name = name.substring( i+1 );
- }
- return name;
- }
-
- /**
- * Returns the absolute path to the application on the local file system.
- * Note that the application might be embedded inside of a jar file.
- */
- public String path ()
- {
- return getClass().getProtectionDomain().getCodeSource().getLocation().toString();
- }
-
- /**
- * Returns the path to the application on the local file system
- * relative to the server's document root.
- */
- public String baseURL ()
- {
- String root = getServletContext().getRealPath( "/" );
- String result = path();
- if ( result.endsWith("/") )
- { // path
- if ( result.startsWith( root ) )
- { // relative to root
- result = result.substring( root.length() );
- }
- // else leave as absolute reference
- }
- // jar or war file: leave as absolute reference
- return result;
- }
-
- // concurrent request handling
-
- /**
- * Returns whether this application allows request
- * to be handled concurrently.
- * This implementation returns true.
- * Subclasses may override to return false to force
- * single-threaded request handling, although this
- * is not implemented.
- */
- public boolean allowsConcurrentRequestHandling ()
- {
- return true;
- }
-
- /**
- * Returns whether this application allows request
- * to be handled concurrently.
- * This implementation returns true.
- */
- public boolean adaptorsDispatchRequestsConcurrently ()
- {
- return true;
- }
-
- /**
- * Returns whether this application allows request
- * to be handled concurrently.
- * This implementation returns true.
- */
- public boolean isConcurrentRequestHandlingEnabled ()
- {
- return true;
- }
-
- // handling requests
+ * Returns the path to the application on the local file system relative to the
+ * server's document root.
+ */
+ public String baseURL() {
+ String root = getServletContext().getRealPath("/");
+ String result = path();
+ if (result.endsWith("/")) { // path
+ if (result.startsWith(root)) { // relative to root
+ result = result.substring(root.length());
+ }
+ // else leave as absolute reference
+ }
+ // jar or war file: leave as absolute reference
+ return result;
+ }
+
+ // concurrent request handling
/**
- * Invoked first in the request-response cycle.
- * Override to perform any kind of initialization at the
- * start of a request. This implementation does nothing.
- */
- public void awake ()
- {
-
- }
-
- /**
- * Invoked to start the first phase of the request-response cycle,
- * after all calls to awake() have been completed.
- */
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
- aContext.session().takeValuesFromRequest( aRequest, aContext );
+ * Returns whether this application allows request to be handled concurrently.
+ * This implementation returns true. Subclasses may override to return false to
+ * force single-threaded request handling, although this is not implemented.
+ */
+ public boolean allowsConcurrentRequestHandling() {
+ return true;
}
- /**
- * Invoked to start the second phase of the request-response cycle,
- * after all calls to takeValuesFromRequest have finished.
- */
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- return aContext.session().invokeAction( aRequest, aContext );
- }
-
- /**
- * Invoked to start the third phase of the request-response cycle,
- * after invokeAction() has completed and returned a WOResponse.
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- aContext.session().appendToResponse( aResponse, aContext );
- }
-
- /**
- * Invoked last in the request-response cycle.
- * Override to perform any kind of clean-up at the
- * end of a request. This implementation does nothing.
- */
- public void sleep ()
- {
-
- }
-
- /**
- * Dispatches the request to the appropriate handler.
- */
- public WOResponse dispatchRequest (WORequest aRequest)
- {
- return handlerForRequest( aRequest ).handleRequest( aRequest );
- }
-
- // request handling
-
- /**
- * Returns the default request handler used if the requested
- * handler isn't specified or cannot be found. (This defaults
- * to the WODirectActionRequestHandler.)
- */
- public WORequestHandler defaultRequestHandler ()
- {
- return defaultRequestHandler;
- }
-
- /**
- * Sets the default request handler used if the requested
- * handler isn't specified or cannot be found.
- */
- public void setDefaultRequestHandler (WORequestHandler aRequestHandler)
- {
- defaultRequestHandler = aRequestHandler;
- }
-
- /**
- * Registers the specified request handler for the specified key.
- */
- public void registerRequestHandler (WORequestHandler aRequestHandler, String aKey)
- {
- requestHandlers.setObjectForKey( aRequestHandler, aKey );
- }
-
- /**
- * Unregisters any existing request handler for the specified key
- * returning the existing request handler, if any.
- */
- public WORequestHandler removeRequestHandlerForKey (String aKey)
- {
- WORequestHandler result = requestHandlerForKey( aKey );
- requestHandlers.removeObjectForKey( aKey );
- return result;
- }
-
- /**
- * Returns the keys under which request handlers are registered.
- */
- public NSArray registeredRequestHandlerKeys ()
- {
- return requestHandlers.allKeys();
- }
-
- /**
- * Returns the request handler registered for the specified key,
- * or null if no request handler is registered for that key.
- */
- public WORequestHandler requestHandlerForKey (String aKey)
- {
- return (WORequestHandler) requestHandlers.objectForKey( aKey );
- }
-
- /**
- * Returns the request handler that would best service the specified request.
- */
- public WORequestHandler handlerForRequest (WORequest aRequest)
- {
- WORequestHandler result = requestHandlerForKey( aRequest.requestHandlerKey() );
- if ( aRequest == null ) result = defaultRequestHandler();
- return result;
- }
-
- // handling errors
-
- public WOResponse handleSessionCreationErrorInContext( WOContext aContext )
- {
- WOResponse response = new WOResponse();
- response.setStatus( 500 ); // internal server error
- //TODO: add more useful information to the response
- System.err.println( "Failed to create session: " + aContext );
-new RuntimeException().printStackTrace(); // remove me
- return response;
- }
-
- public WOResponse handleSessionRestorationErrorInContext( WOContext aContext )
- {
- WOResponse response = new WOResponse();
- response.setStatus( 500 ); // internal server error
- //TODO: add more useful information to the response
- System.err.println( "Failed to restore session: " + aContext );
-new RuntimeException().printStackTrace(); // remove me
- return response;
- }
-
- public WOResponse handlePageRestorationErrorInContext( WOContext aContext )
- {
- WOResponse response = new WOResponse();
- response.setStatus( 500 ); // internal server error
- //TODO: add more useful information to the response
- System.err.println( "Failed to restore page: " + aContext );
-new RuntimeException().printStackTrace(); // remove me
- return response;
- }
-
- public WOResponse handleException( Throwable aThrowable, WOContext aContext )
- {
- WOResponse response = new WOResponse();
- response.setStatus( 500 ); // internal server error
- System.err.println( "Exception occurred: " + aContext );
- if ( aThrowable.getMessage() != null )
- {
- response.appendContentString( aThrowable.getMessage() );
- aThrowable.printStackTrace();
- }
- else
- {
- response.appendContentString( aThrowable.toString() );
- aThrowable.printStackTrace();
- }
- aThrowable.printStackTrace();
- return response;
- }
-
- // managing pages
-
- /**
- * Sets the number of pages that will be retained
- * in the user's session. Set to zero to disable page caching.
- */
- public void setPageCacheSize (int aPositiveInt)
- {
- pageCacheSize = aPositiveInt;
- }
-
- /**
- * Returns the number of pages that will be retained
- * in the user's session. The default page cache size is 30.
- */
- public int pageCacheSize ()
- {
- return pageCacheSize;
- }
-
- /**
- * Returns the number of pages that will be retained in the
- * longer-term "permanent" page cache in the user's session,
- * which is typically used for navigation bars in frames, etc.
- * The default permanent page cache size is 30.
- */
- public int permanentPageCacheSize ()
- {
- return permanentPageCacheSize;
- }
-
- /**
- * Returns the number of pages that will be retained in the
- * longer-term "permanent" page cache in the user's session,
- * which is typically used for navigation bars in frames, etc.
- * Set to zero to disable permanent page caching.
- */
- public void setPermanentPageCacheSize (int aPositiveInt)
- {
- permanentPageCacheSize = aPositiveInt;
- }
-
- /**
- * Returns whether a "backtrack" for an existing page should
- * simply call generateResponse() on the existing page instance.
- * If false, a new page is created instead. The default is true.
- */
- public void setPageRefreshOnBacktrackEnabled (boolean enabled)
- {
- pageRefreshOnBacktrack = enabled;
- }
-
- /**
- * Returns whether a "backtrack" for an existing page should
- * simply call generateResponse() on the existing page instance.
- * If false, a new page is created instead. The default is true.
- */
- public boolean isPageRefreshOnBacktrackEnabled ()
- {
- return pageRefreshOnBacktrack;
- }
-
- // managing sessions
-
- /**
- * Sets the session store used by this application to persist
- * sessions between request-response transactions.
- */
- public void setSessionStore(WOSessionStore aSessionStore)
- {
- sessionStore = aSessionStore;
- }
-
- /**
- * Returns the session store used by this application to persist
- * sessions between request-response transactions.
- */
- public WOSessionStore sessionStore()
- {
- return sessionStore;
- }
-
- /**
- * Called at the end of the request-response cycle
- * to persist the current session until the user's next request.
- */
- public void saveSessionForContext(WOContext aContext)
- {
- sessionStore.saveSessionForContext( aContext );
- }
-
- /**
- * Called at the beginning of the request-response cycle
- * to obtain the current session from the user's last request.
- * Returns null if no such session has been created.
- * This method sets the context of the session to the specified context.
- */
- public WOSession restoreSessionWithID(String aSessionID, WOContext aContext)
- {
- WORequest request = aContext.request();
- WOSession session = sessionStore.restoreSessionWithID( aSessionID, request );
- if ( session != null )
- {
- session.setContext( aContext );
- session.setServletSession( request.servletRequest().getSession() );
- }
- return session;
- }
-
- /**
- * Called to create a session for a new request. This implementation
- * looks for a class in the same package as the application class
- * called "Session" and failing that returns a WOSession.
- */
- public WOSession createSessionForRequest(WORequest aRequest)
- {
- WOSession result = null;
- try
- {
+ /**
+ * Returns whether this application allows request to be handled concurrently.
+ * This implementation returns true.
+ */
+ public boolean adaptorsDispatchRequestsConcurrently() {
+ return true;
+ }
+
+ /**
+ * Returns whether this application allows request to be handled concurrently.
+ * This implementation returns true.
+ */
+ public boolean isConcurrentRequestHandlingEnabled() {
+ return true;
+ }
+
+ // handling requests
+
+ /**
+ * Invoked first in the request-response cycle. Override to perform any kind of
+ * initialization at the start of a request. This implementation does nothing.
+ */
+ public void awake() {
+
+ }
+
+ /**
+ * Invoked to start the first phase of the request-response cycle, after all
+ * calls to awake() have been completed.
+ */
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ aContext.session().takeValuesFromRequest(aRequest, aContext);
+ }
+
+ /**
+ * Invoked to start the second phase of the request-response cycle, after all
+ * calls to takeValuesFromRequest have finished.
+ */
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ return aContext.session().invokeAction(aRequest, aContext);
+ }
+
+ /**
+ * Invoked to start the third phase of the request-response cycle, after
+ * invokeAction() has completed and returned a WOResponse.
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ aContext.session().appendToResponse(aResponse, aContext);
+ }
+
+ /**
+ * Invoked last in the request-response cycle. Override to perform any kind of
+ * clean-up at the end of a request. This implementation does nothing.
+ */
+ public void sleep() {
+
+ }
+
+ /**
+ * Dispatches the request to the appropriate handler.
+ */
+ public WOResponse dispatchRequest(WORequest aRequest) {
+ return handlerForRequest(aRequest).handleRequest(aRequest);
+ }
+
+ // request handling
+
+ /**
+ * Returns the default request handler used if the requested handler isn't
+ * specified or cannot be found. (This defaults to the
+ * WODirectActionRequestHandler.)
+ */
+ public WORequestHandler defaultRequestHandler() {
+ return defaultRequestHandler;
+ }
+
+ /**
+ * Sets the default request handler used if the requested handler isn't
+ * specified or cannot be found.
+ */
+ public void setDefaultRequestHandler(WORequestHandler aRequestHandler) {
+ defaultRequestHandler = aRequestHandler;
+ }
+
+ /**
+ * Registers the specified request handler for the specified key.
+ */
+ public void registerRequestHandler(WORequestHandler aRequestHandler, String aKey) {
+ requestHandlers.setObjectForKey(aRequestHandler, aKey);
+ }
+
+ /**
+ * Unregisters any existing request handler for the specified key returning the
+ * existing request handler, if any.
+ */
+ public WORequestHandler removeRequestHandlerForKey(String aKey) {
+ WORequestHandler result = requestHandlerForKey(aKey);
+ requestHandlers.removeObjectForKey(aKey);
+ return result;
+ }
+
+ /**
+ * Returns the keys under which request handlers are registered.
+ */
+ public NSArray registeredRequestHandlerKeys() {
+ return requestHandlers.allKeys();
+ }
+
+ /**
+ * Returns the request handler registered for the specified key, or null if no
+ * request handler is registered for that key.
+ */
+ public WORequestHandler requestHandlerForKey(String aKey) {
+ return (WORequestHandler) requestHandlers.objectForKey(aKey);
+ }
+
+ /**
+ * Returns the request handler that would best service the specified request.
+ */
+ public WORequestHandler handlerForRequest(WORequest aRequest) {
+ WORequestHandler result = requestHandlerForKey(aRequest.requestHandlerKey());
+ if (aRequest == null)
+ result = defaultRequestHandler();
+ return result;
+ }
+
+ // handling errors
+
+ public WOResponse handleSessionCreationErrorInContext(WOContext aContext) {
+ WOResponse response = new WOResponse();
+ response.setStatus(500); // internal server error
+ // TODO: add more useful information to the response
+ System.err.println("Failed to create session: " + aContext);
+ new RuntimeException().printStackTrace(); // remove me
+ return response;
+ }
+
+ public WOResponse handleSessionRestorationErrorInContext(WOContext aContext) {
+ WOResponse response = new WOResponse();
+ response.setStatus(500); // internal server error
+ // TODO: add more useful information to the response
+ System.err.println("Failed to restore session: " + aContext);
+ new RuntimeException().printStackTrace(); // remove me
+ return response;
+ }
+
+ public WOResponse handlePageRestorationErrorInContext(WOContext aContext) {
+ WOResponse response = new WOResponse();
+ response.setStatus(500); // internal server error
+ // TODO: add more useful information to the response
+ System.err.println("Failed to restore page: " + aContext);
+ new RuntimeException().printStackTrace(); // remove me
+ return response;
+ }
+
+ public WOResponse handleException(Throwable aThrowable, WOContext aContext) {
+ WOResponse response = new WOResponse();
+ response.setStatus(500); // internal server error
+ System.err.println("Exception occurred: " + aContext);
+ if (aThrowable.getMessage() != null) {
+ response.appendContentString(aThrowable.getMessage());
+ aThrowable.printStackTrace();
+ } else {
+ response.appendContentString(aThrowable.toString());
+ aThrowable.printStackTrace();
+ }
+ aThrowable.printStackTrace();
+ return response;
+ }
+
+ // managing pages
+
+ /**
+ * Sets the number of pages that will be retained in the user's session. Set to
+ * zero to disable page caching.
+ */
+ public void setPageCacheSize(int aPositiveInt) {
+ pageCacheSize = aPositiveInt;
+ }
+
+ /**
+ * Returns the number of pages that will be retained in the user's session. The
+ * default page cache size is 30.
+ */
+ public int pageCacheSize() {
+ return pageCacheSize;
+ }
+
+ /**
+ * Returns the number of pages that will be retained in the longer-term
+ * "permanent" page cache in the user's session, which is typically used for
+ * navigation bars in frames, etc. The default permanent page cache size is 30.
+ */
+ public int permanentPageCacheSize() {
+ return permanentPageCacheSize;
+ }
+
+ /**
+ * Returns the number of pages that will be retained in the longer-term
+ * "permanent" page cache in the user's session, which is typically used for
+ * navigation bars in frames, etc. Set to zero to disable permanent page
+ * caching.
+ */
+ public void setPermanentPageCacheSize(int aPositiveInt) {
+ permanentPageCacheSize = aPositiveInt;
+ }
+
+ /**
+ * Returns whether a "backtrack" for an existing page should simply call
+ * generateResponse() on the existing page instance. If false, a new page is
+ * created instead. The default is true.
+ */
+ public void setPageRefreshOnBacktrackEnabled(boolean enabled) {
+ pageRefreshOnBacktrack = enabled;
+ }
+
+ /**
+ * Returns whether a "backtrack" for an existing page should simply call
+ * generateResponse() on the existing page instance. If false, a new page is
+ * created instead. The default is true.
+ */
+ public boolean isPageRefreshOnBacktrackEnabled() {
+ return pageRefreshOnBacktrack;
+ }
+
+ // managing sessions
+
+ /**
+ * Sets the session store used by this application to persist sessions between
+ * request-response transactions.
+ */
+ public void setSessionStore(WOSessionStore aSessionStore) {
+ sessionStore = aSessionStore;
+ }
+
+ /**
+ * Returns the session store used by this application to persist sessions
+ * between request-response transactions.
+ */
+ public WOSessionStore sessionStore() {
+ return sessionStore;
+ }
+
+ /**
+ * Called at the end of the request-response cycle to persist the current
+ * session until the user's next request.
+ */
+ public void saveSessionForContext(WOContext aContext) {
+ sessionStore.saveSessionForContext(aContext);
+ }
+
+ /**
+ * Called at the beginning of the request-response cycle to obtain the current
+ * session from the user's last request. Returns null if no such session has
+ * been created. This method sets the context of the session to the specified
+ * context.
+ */
+ public WOSession restoreSessionWithID(String aSessionID, WOContext aContext) {
+ WORequest request = aContext.request();
+ WOSession session = sessionStore.restoreSessionWithID(aSessionID, request);
+ if (session != null) {
+ session.setContext(aContext);
+ session.setServletSession(request.servletRequest().getSession());
+ }
+ return session;
+ }
+
+ /**
+ * Called to create a session for a new request. This implementation looks for a
+ * class in the same package as the application class called "Session" and
+ * failing that returns a WOSession.
+ */
+ public WOSession createSessionForRequest(WORequest aRequest) {
+ WOSession result = null;
+ try {
// using our class loader, which is hopefully dynamic.
- result = (WOSession) getLocalClass( "Session" ).newInstance();
- }
- catch ( Throwable t )
- {
- // ignore: fall back to WOSession
- //t.printStackTrace();
- }
-
- if ( result == null )
- {
- result = new WOSession();
- }
-
- result.setServletSession( aRequest.servletRequest().getSession( true ) );
- return result;
- }
-
+ result = (WOSession) getLocalClass("Session").newInstance();
+ } catch (Throwable t) {
+ // ignore: fall back to WOSession
+ // t.printStackTrace();
+ }
+
+ if (result == null) {
+ result = new WOSession();
+ }
+
+ result.setServletSession(aRequest.servletRequest().getSession(true));
+ return result;
+ }
+
+ /**
+ * Returns the page component with the specified name. A context is created with
+ * the specified request, along with a session if necessary.
+ */
+ public WOComponent pageWithName(String aName, WORequest aRequest) {
+ return pageWithName(aName, WOContext.contextWithRequest(aRequest));
+ }
+
/**
- * Returns the page component with the specified name.
- * A context is created with the specified request,
- * along with a session if necessary.
- */
- public WOComponent pageWithName (String aName, WORequest aRequest)
- {
- return pageWithName( aName, WOContext.contextWithRequest( aRequest ) );
- }
-
- /**
- * Called to retrieve a component for the specified context.
- */
- public WOComponent pageWithName (String aName, WOContext aContext)
- {
- if ( aName == null )
- {
- throw new IllegalArgumentException(
- "WOApplication.pageWithName: name is null" );
- }
-
- WOComponent result = null;
- try
- {
+ * Called to retrieve a component for the specified context.
+ */
+ public WOComponent pageWithName(String aName, WOContext aContext) {
+ if (aName == null) {
+ throw new IllegalArgumentException("WOApplication.pageWithName: name is null");
+ }
+
+ WOComponent result = null;
+ try {
// using our class loader, which is hopefully dynamic.
- Class c = getLocalClass( aName );
-
- if ( c != null )
- {
- // get constructor
- Constructor ctor;
- try
- {
- ctor = c.getConstructor( new Class[] { WOContext.class } );
- }
- catch ( NoSuchMethodException nsme )
- {
- ctor = null;
- }
-
- // create instance of class
- if ( ctor != null )
- {
- result = (WOComponent) ctor.newInstance( new Object[] { aContext } );
- }
- else // call back on default constructor (deprecated)
- {
- result = (WOComponent) c.newInstance();
- }
- }
- }
- catch ( Throwable t )
- {
- // ignore for now
- //TODO: Throw appropriate exception here
- //System.err.println( "Not found: pageWithName: " + aName );
- t.printStackTrace();
- }
-
- if ( result != null && aContext != null )
- {
- // this is where components get their context
- result.ensureAwakeInContext( aContext );
- }
- else
- if ( result == null )
- {
- System.err.println( "Not found: pageWithName: " + aName );
- }
-
- return result;
- }
-
- /**
- * Returns a class in the same package as the Application class,
- * or, failing that, from the WOApplication package, or finally
- * from the root of the class path. Returns null if not found.
- */
- Class getLocalClass( String aName )
- {
- Class result = null;
- if ( getClass() != WOApplication.class )
- {
- result = loadLocalClass( getClass(), aName );
- }
- if ( result == null )
- {
- result = loadLocalClass( WOApplication.class, aName );
- }
- if ( result == null )
- {
- result = loadLocalClass( null, aName );
- }
- return result;
- }
-
- private static final Class loadLocalClass( Class aClass, String aName )
- {
- ClassLoader loader;
- String packageName = "";
- if ( aClass != null )
- {
- loader = aClass.getClassLoader();
- packageName = aClass.getName();
- int index = packageName.lastIndexOf( "." );
- if ( index > -1 )
- {
- packageName = packageName.substring( 0, index+1 );
- }
- else
- {
- packageName = "";
- }
- }
- else
- {
- loader = WOApplication.class.getClassLoader();
- }
-
- try
- {
- return loader.loadClass( packageName + aName );
- }
- catch ( ClassNotFoundException e )
- {
- return null;
- }
- }
-
- // creating elements
-
- /**
- * Returns either a dynamic element or a component
- * for the specified name.
- */
- public WOElement dynamicElementWithName(
- String anElementName, NSDictionary anAssociationMap,
- WOElement aBodyElement, List aLanguageList)
- {
- WOElement element = null;
- Class c = null;
- try
- {
- c = getLocalClass( anElementName );
- if ( c == null )
- {
- System.out.println( "Not found: dynamicElementWithName: " +
- "could not find WODynamicElement subclass: " + anElementName );
- c = WODynamicElement.class;
- }
-
- // get constructor
- Class[] params = new Class[]
- { String.class, NSDictionary.class, WOElement.class };
- Constructor ctor = c.getConstructor( params );
-
- // create instance of class
- if ( ctor != null )
- {
- element = (WODynamicElement) ctor.newInstance(
- new Object[] { anElementName, anAssociationMap, aBodyElement } );
- }
- }
- catch ( Throwable t )
- {
- // ignore: not a dynamic element
- //System.out.println( "Not a dynamic element: dynamicElementWithName: " + t );
- //exc.printStackTrace();
- }
-
- // no dynamic element found: look for a component
- if ( element == null )
- {
- WOComponent component = (WOComponent) pageWithName( anElementName, (WOContext) null );
-
- // this seems hackish:
- // I don't see another way of setting the bindings.
- component.associations = anAssociationMap;
- component.rootElement = aBodyElement;
-
- element = component;
- }
-
- return element;
- }
-
- // resource handling
-
- /**
- * Called to create the application's resource manager.
- * Override to create a custom resource manager.
- */
- public WOResourceManager createResourceManager()
- {
- return new WOResourceManager();
- }
-
- /**
- * Returns the application's current resource manager.
- */
- public WOResourceManager resourceManager()
- {
- return resourceManager;
- }
-
- /**
- * Installs a custom resource manager into the current application.
- * @deprecated Override createResourceManager() instead.
- */
- public void setResourceManager(WOResourceManager aResourceManager)
- {
- resourceManager = aResourceManager;
- }
+ Class c = getLocalClass(aName);
+
+ if (c != null) {
+ // get constructor
+ Constructor ctor;
+ try {
+ ctor = c.getConstructor(new Class[] { WOContext.class });
+ } catch (NoSuchMethodException nsme) {
+ ctor = null;
+ }
+
+ // create instance of class
+ if (ctor != null) {
+ result = (WOComponent) ctor.newInstance(new Object[] { aContext });
+ } else // call back on default constructor (deprecated)
+ {
+ result = (WOComponent) c.newInstance();
+ }
+ }
+ } catch (Throwable t) {
+ // ignore for now
+ // TODO: Throw appropriate exception here
+ // System.err.println( "Not found: pageWithName: " + aName );
+ t.printStackTrace();
+ }
+
+ if (result != null && aContext != null) {
+ // this is where components get their context
+ result.ensureAwakeInContext(aContext);
+ } else if (result == null) {
+ System.err.println("Not found: pageWithName: " + aName);
+ }
+
+ return result;
+ }
-/*
- // request handling undocumented
-
- public WOComponent pageWithName (String);
- public void savePage (WOComponent);
- public WOComponent restorePageForContextID (String);
- public WOContext context ();
- public WOSession session ();
- public WOSession createSession ();
- public WOSession restoreSession ();
- public void saveSession (WOSession);
-
- public WOResponse handleRequest (WORequest aRequest)
- {
- }
-
- // error handling undocumented
-
- WOResponse handleSessionCreationError ();
- WOResponse handleSessionRestorationError ();
- WOResponse handlePageRestorationError ();
- WOResponse handleException (Throwable);
-
- // running
-
- public NSRunLoop runLoop ();
- public void run ();
- public void setTimeOut (double);
- public double timeOut ();
- public void terminate ();
- public boolean isTerminating ();
-
- // script debugging
-
- public void traceScriptedMessages (boolean);
- public void traceAssignments (boolean);
- public void traceStatements (boolean);
- public void traceObjectiveCMessages (boolean);
- public void trace (boolean);
- public void logTakeValueForDeclarationNamed (String, String, String, String, Object);
- public void logSetValueForDeclarationNamed (String, String, String, String, Object);
-
- // script handling
-
- public String scriptedClassNameWithPath (String);
- public String scriptedClassNameWithPathEncoding (String, int);
-
- // statistics report
-
- public void setStatisticsStore (WOStatisticsStore);
- public WOStatisticsStore statisticsStore ();
- public NSDictionary statistics ();
-
- // managing adaptors
-
- public WOAdaptor adaptorWithName (String, NSDictionary);
- public NSArray adaptors ();
-
- // monitor support
-
- public boolean monitoringEnabled ();
- public int activeSessionsCount ();
- public void refuseNewSessions (boolean);
- public boolean isRefusingNewSessions ();
- public void setMinimumActiveSessionsCount (int);
- public int minimumActiveSessionsCount ();
- public void terminateAfterTimeInterval (double);
-
- // garbage collection undocumented
-
- int garbageCollectionPeriod ();
- void setGarbageCollectionPeriod (int);
-
- // backwards compatibility
-
- public boolean requiresWOF35RequestHandling ();
- public boolean requiresWOF35TemplateParser ();
-
- public void setPrintsHTMLParserDiagnostics (boolean);
- public boolean printsHTMLParserDiagnostics ();
-
- // configuration and defaults
-
- public static NSArray loadFrameworks ();
- public static void setLoadFrameworks (NSArray);
-*/
- static boolean debuggingEnabled = false;
- /**
- * Returns whether the application is in "debug mode".
- */
- public static boolean isDebuggingEnabled()
- {
- return debuggingEnabled;
- }
-
- /**
- * Sets whether the application is in "debug mode".
- */
- public static void setDebuggingEnabled( boolean enabled )
- {
- debuggingEnabled = enabled;
- }
-
- /**
- * Sets whether templates are cached. If true, templates will
- * only be read once per application lifetime. Otherwise, templates
- * will be read each time this class is instantiated. Defaults to false.
- */
- public static void setCachingEnabled (boolean enabled)
- {
+ /**
+ * Returns a class in the same package as the Application class, or, failing
+ * that, from the WOApplication package, or finally from the root of the class
+ * path. Returns null if not found.
+ */
+ Class getLocalClass(String aName) {
+ Class result = null;
+ if (getClass() != WOApplication.class) {
+ result = loadLocalClass(getClass(), aName);
+ }
+ if (result == null) {
+ result = loadLocalClass(WOApplication.class, aName);
+ }
+ if (result == null) {
+ result = loadLocalClass(null, aName);
+ }
+ return result;
+ }
+
+ private static final Class loadLocalClass(Class aClass, String aName) {
+ ClassLoader loader;
+ String packageName = "";
+ if (aClass != null) {
+ loader = aClass.getClassLoader();
+ packageName = aClass.getName();
+ int index = packageName.lastIndexOf(".");
+ if (index > -1) {
+ packageName = packageName.substring(0, index + 1);
+ } else {
+ packageName = "";
+ }
+ } else {
+ loader = WOApplication.class.getClassLoader();
+ }
+
+ try {
+ return loader.loadClass(packageName + aName);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ // creating elements
+
+ /**
+ * Returns either a dynamic element or a component for the specified name.
+ */
+ public WOElement dynamicElementWithName(String anElementName, NSDictionary anAssociationMap, WOElement aBodyElement,
+ List aLanguageList) {
+ WOElement element = null;
+ Class c = null;
+ try {
+ c = getLocalClass(anElementName);
+ if (c == null) {
+ System.out.println("Not found: dynamicElementWithName: " + "could not find WODynamicElement subclass: "
+ + anElementName);
+ c = WODynamicElement.class;
+ }
+
+ // get constructor
+ Class[] params = new Class[] { String.class, NSDictionary.class, WOElement.class };
+ Constructor ctor = c.getConstructor(params);
+
+ // create instance of class
+ if (ctor != null) {
+ element = (WODynamicElement) ctor
+ .newInstance(new Object[] { anElementName, anAssociationMap, aBodyElement });
+ }
+ } catch (Throwable t) {
+ // ignore: not a dynamic element
+ // System.out.println( "Not a dynamic element: dynamicElementWithName: " + t );
+ // exc.printStackTrace();
+ }
+
+ // no dynamic element found: look for a component
+ if (element == null) {
+ WOComponent component = (WOComponent) pageWithName(anElementName, (WOContext) null);
+
+ // this seems hackish:
+ // I don't see another way of setting the bindings.
+ component.associations = anAssociationMap;
+ component.rootElement = aBodyElement;
+
+ element = component;
+ }
+
+ return element;
+ }
+
+ // resource handling
+
+ /**
+ * Called to create the application's resource manager. Override to create a
+ * custom resource manager.
+ */
+ public WOResourceManager createResourceManager() {
+ return new WOResourceManager();
+ }
+
+ /**
+ * Returns the application's current resource manager.
+ */
+ public WOResourceManager resourceManager() {
+ return resourceManager;
+ }
+
+ /**
+ * Installs a custom resource manager into the current application.
+ *
+ * @deprecated Override createResourceManager() instead.
+ */
+ public void setResourceManager(WOResourceManager aResourceManager) {
+ resourceManager = aResourceManager;
+ }
+
+ /*
+ * // request handling undocumented
+ *
+ * public WOComponent pageWithName (String); public void savePage (WOComponent);
+ * public WOComponent restorePageForContextID (String); public WOContext context
+ * (); public WOSession session (); public WOSession createSession (); public
+ * WOSession restoreSession (); public void saveSession (WOSession);
+ *
+ * public WOResponse handleRequest (WORequest aRequest) { }
+ *
+ * // error handling undocumented
+ *
+ * WOResponse handleSessionCreationError (); WOResponse
+ * handleSessionRestorationError (); WOResponse handlePageRestorationError ();
+ * WOResponse handleException (Throwable);
+ *
+ * // running
+ *
+ * public NSRunLoop runLoop (); public void run (); public void setTimeOut
+ * (double); public double timeOut (); public void terminate (); public boolean
+ * isTerminating ();
+ *
+ * // script debugging
+ *
+ * public void traceScriptedMessages (boolean); public void traceAssignments
+ * (boolean); public void traceStatements (boolean); public void
+ * traceObjectiveCMessages (boolean); public void trace (boolean); public void
+ * logTakeValueForDeclarationNamed (String, String, String, String, Object);
+ * public void logSetValueForDeclarationNamed (String, String, String, String,
+ * Object);
+ *
+ * // script handling
+ *
+ * public String scriptedClassNameWithPath (String); public String
+ * scriptedClassNameWithPathEncoding (String, int);
+ *
+ * // statistics report
+ *
+ * public void setStatisticsStore (WOStatisticsStore); public WOStatisticsStore
+ * statisticsStore (); public NSDictionary statistics ();
+ *
+ * // managing adaptors
+ *
+ * public WOAdaptor adaptorWithName (String, NSDictionary); public NSArray
+ * adaptors ();
+ *
+ * // monitor support
+ *
+ * public boolean monitoringEnabled (); public int activeSessionsCount ();
+ * public void refuseNewSessions (boolean); public boolean isRefusingNewSessions
+ * (); public void setMinimumActiveSessionsCount (int); public int
+ * minimumActiveSessionsCount (); public void terminateAfterTimeInterval
+ * (double);
+ *
+ * // garbage collection undocumented
+ *
+ * int garbageCollectionPeriod (); void setGarbageCollectionPeriod (int);
+ *
+ * // backwards compatibility
+ *
+ * public boolean requiresWOF35RequestHandling (); public boolean
+ * requiresWOF35TemplateParser ();
+ *
+ * public void setPrintsHTMLParserDiagnostics (boolean); public boolean
+ * printsHTMLParserDiagnostics ();
+ *
+ * // configuration and defaults
+ *
+ * public static NSArray loadFrameworks (); public static void setLoadFrameworks
+ * (NSArray);
+ */
+ static boolean debuggingEnabled = false;
+
+ /**
+ * Returns whether the application is in "debug mode".
+ */
+ public static boolean isDebuggingEnabled() {
+ return debuggingEnabled;
+ }
+
+ /**
+ * Sets whether the application is in "debug mode".
+ */
+ public static void setDebuggingEnabled(boolean enabled) {
+ debuggingEnabled = enabled;
+ }
+
+ /**
+ * Sets whether templates are cached. If true, templates will only be read once
+ * per application lifetime. Otherwise, templates will be read each time this
+ * class is instantiated. Defaults to false.
+ */
+ public static void setCachingEnabled(boolean enabled) {
cachingEnabled = enabled;
}
- /**
- * Returns whether templates are cached. If true, templates are
- * read once per application lifetime. Otherwise, templates are
- * read each time this class is instantiated.
- */
- public static boolean isCachingEnabled ()
- {
- return cachingEnabled;
- }
-
- // configuration
-
- /**
- * Returns the component request handler key,
- * which is defined by the system property _ComponentRequestHandlerKey.
- * The default is "wo".
- */
- public static String componentRequestHandlerKey()
- {
- return System.getProperty( _ComponentRequestHandlerKey, "wo" );
- }
-
- /**
- * Sets the component request handler key.
- * @deprecated Set the system property _ComponentRequestHandlerKey.
- */
- public static void setComponentRequestHandlerKey(String aKey)
- {
- System.setProperty( _ComponentRequestHandlerKey, aKey );
- }
-
- /**
- * Returns the direct action request handler key,
- * which is defined by the system property _DirectActionRequestHandlerKey.
- * The default is "wa".
- */
- public static String directActionRequestHandlerKey()
- {
- return System.getProperty( _DirectActionRequestHandlerKey, "wa" );
- }
-
- /**
- * Sets the direct action request handler key.
- * @deprecated Set the system property _DirectActionRequestHandlerKey.
- */
- public static void setDirectActionRequestHandlerKey(String aKey)
- {
- System.setProperty( _DirectActionRequestHandlerKey, aKey );
- }
-
- /**
- * Returns the resource request handler key,
- * which is defined by the system property _ResourceRequestHandlerKey.
- * The default is "wr".
- */
- public static String resourceRequestHandlerKey()
- {
- return System.getProperty( _ResourceRequestHandlerKey, "wr" );
- }
-
- /**
- * Sets the resource request handler key.
- * @deprecated Set the system property _ResourceRequestHandlerKey.
- */
- public static void setResourceRequestHandlerKey(String aKey)
- {
- System.setProperty( _ResourceRequestHandlerKey, aKey );
- }
-
- /**
- * Returns whether this application should attempt to open
- * a web browser on the host machine when launched standalone.
- * The default is true.
- */
- public static boolean autoOpenInBrowser()
- {
- return autoOpenInBrowser;
- }
-
- /**
- * Sets whether this application should attempt to open
- * a web browser on the host machine when launched standalone.
- */
- public static void setAutoOpenInBrowser(boolean autoOpen)
- {
- autoOpenInBrowser = autoOpen;
- }
-
- /**
- * Gets the port used when run as a standalone server.
- * Returns the value of the system property WOPort.
- * By default, this is zero, which causes the application
- * to automatically select an available port.
- */
- public static Number port ()
- {
- return Integer.getInteger( WOPort, 0 );
- }
-
- /**
- * Gets the smtp server that will be used to send email.
- * Returns the system property WOSMTPHost.
- */
- public static String SMTPHost()
- {
- return System.getProperty( WOSMTPHost );
- }
-
- /**
- * Sets the smtp server that will be used to send email.
- * @deprecated Set the system property WOSMTPHost.
- */
- public static void setSMTPHost( String aHost )
- {
- System.setProperty( WOSMTPHost, aHost );
- }
-/*
- public static boolean isDirectConnectEnabled ();
- public static void setDirectConnectEnabled (boolean);
- public static String cgiAdaptorURL ();
- public static void setCGIAdaptorURL (String);
- public static String applicationBaseURL ();
- public static void setApplicationBaseURL (String);
- public static String frameworksBaseURL ();
- public static void setFrameworksBaseURL (String);
- public static String recordingPath ();
- public static void setRecordingPath (String);
- public static NSArray projectSearchPath ();
- public static void setProjectSearchPath (NSArray);
- public static boolean isMonitorEnabled ();
- public static void setMonitorEnabled (boolean);
- public static String monitorHost ();
- public static String adaptor ();
- public String number (); // deprecated
- public static Number listenQueueSize ();
- public static void setListenQueueSize (Number);
- public static NSArray additionalAdaptors ();
- public static void setAdditionalAdaptors (NSArray);
- public static boolean includeCommentsInResponses ();
- public static void setIncludeCommentsInResponses (boolean);
- public static void setSessionTimeOut (Number);
- public static Number sessionTimeOut ();
- public static void logString (String);
- public static void debugString (String);
- public static void logToMonitorString (String);
-*/
+ /**
+ * Returns whether templates are cached. If true, templates are read once per
+ * application lifetime. Otherwise, templates are read each time this class is
+ * instantiated.
+ */
+ public static boolean isCachingEnabled() {
+ return cachingEnabled;
+ }
+
+ // configuration
+
+ /**
+ * Returns the component request handler key, which is defined by the system
+ * property _ComponentRequestHandlerKey. The default is "wo".
+ */
+ public static String componentRequestHandlerKey() {
+ return System.getProperty(_ComponentRequestHandlerKey, "wo");
+ }
+
+ /**
+ * Sets the component request handler key.
+ *
+ * @deprecated Set the system property _ComponentRequestHandlerKey.
+ */
+ public static void setComponentRequestHandlerKey(String aKey) {
+ System.setProperty(_ComponentRequestHandlerKey, aKey);
+ }
+
+ /**
+ * Returns the direct action request handler key, which is defined by the system
+ * property _DirectActionRequestHandlerKey. The default is "wa".
+ */
+ public static String directActionRequestHandlerKey() {
+ return System.getProperty(_DirectActionRequestHandlerKey, "wa");
+ }
+
+ /**
+ * Sets the direct action request handler key.
+ *
+ * @deprecated Set the system property _DirectActionRequestHandlerKey.
+ */
+ public static void setDirectActionRequestHandlerKey(String aKey) {
+ System.setProperty(_DirectActionRequestHandlerKey, aKey);
+ }
+
+ /**
+ * Returns the resource request handler key, which is defined by the system
+ * property _ResourceRequestHandlerKey. The default is "wr".
+ */
+ public static String resourceRequestHandlerKey() {
+ return System.getProperty(_ResourceRequestHandlerKey, "wr");
+ }
- /**
- * Main entry point for applications that do not subclass WOApplication.
- */
- public static void main( String[] argv )
- {
- main( argv, WOApplication.class );
- }
-
- /**
- * Subclasses may call this method to start a self-hosted
- * web server to serve themselves directly (for testing).
- */
- public static void main( String[] argv, Class subclass )
- {
- try
- {
- int port = 0;
- boolean open = false;
- try
- {
- port = ((Number)subclass.getMethod( "port",
- new Class[0]).invoke(subclass,new Object[0])).intValue();
- open = ((Boolean)subclass.getMethod( "autoOpenInBrowser",
- new Class[0]).invoke(subclass,new Object[0])).booleanValue();
- }
- catch ( Throwable t )
- {
- System.err.print("Error reading configuration:" );
- t.printStackTrace();
- }
-
- HttpServer server = new HttpServer();
- HttpListener listener = server.addListener(new InetAddrPort(port));
- org.mortbay.http.HttpContext context = server.getContext("/");
- ServletHandler handler = new ServletHandler();
- handler.addServlet("/",subclass.getName());
- context.addHandler(handler);
- server.start();
- port = listener.getPort();
- System.out.println("Waiting for requests: http://127.0.0.1:" + port);
- if ( open )
- {
- BrowserLauncher.openURL( "http://127.0.0.1:" + port );
- }
- }
- catch ( Throwable t )
- {
- t.printStackTrace();
- }
- }
+ /**
+ * Sets the resource request handler key.
+ *
+ * @deprecated Set the system property _ResourceRequestHandlerKey.
+ */
+ public static void setResourceRequestHandlerKey(String aKey) {
+ System.setProperty(_ResourceRequestHandlerKey, aKey);
+ }
+
+ /**
+ * Returns whether this application should attempt to open a web browser on the
+ * host machine when launched standalone. The default is true.
+ */
+ public static boolean autoOpenInBrowser() {
+ return autoOpenInBrowser;
+ }
+
+ /**
+ * Sets whether this application should attempt to open a web browser on the
+ * host machine when launched standalone.
+ */
+ public static void setAutoOpenInBrowser(boolean autoOpen) {
+ autoOpenInBrowser = autoOpen;
+ }
+
+ /**
+ * Gets the port used when run as a standalone server. Returns the value of the
+ * system property WOPort. By default, this is zero, which causes the
+ * application to automatically select an available port.
+ */
+ public static Number port() {
+ return Integer.getInteger(WOPort, 0);
+ }
+
+ /**
+ * Gets the smtp server that will be used to send email. Returns the system
+ * property WOSMTPHost.
+ */
+ public static String SMTPHost() {
+ return System.getProperty(WOSMTPHost);
+ }
+
+ /**
+ * Sets the smtp server that will be used to send email.
+ *
+ * @deprecated Set the system property WOSMTPHost.
+ */
+ public static void setSMTPHost(String aHost) {
+ System.setProperty(WOSMTPHost, aHost);
+ }
+ /*
+ * public static boolean isDirectConnectEnabled (); public static void
+ * setDirectConnectEnabled (boolean); public static String cgiAdaptorURL ();
+ * public static void setCGIAdaptorURL (String); public static String
+ * applicationBaseURL (); public static void setApplicationBaseURL (String);
+ * public static String frameworksBaseURL (); public static void
+ * setFrameworksBaseURL (String); public static String recordingPath (); public
+ * static void setRecordingPath (String); public static NSArray
+ * projectSearchPath (); public static void setProjectSearchPath (NSArray);
+ * public static boolean isMonitorEnabled (); public static void
+ * setMonitorEnabled (boolean); public static String monitorHost (); public
+ * static String adaptor (); public String number (); // deprecated public
+ * static Number listenQueueSize (); public static void setListenQueueSize
+ * (Number); public static NSArray additionalAdaptors (); public static void
+ * setAdditionalAdaptors (NSArray); public static boolean
+ * includeCommentsInResponses (); public static void
+ * setIncludeCommentsInResponses (boolean); public static void setSessionTimeOut
+ * (Number); public static Number sessionTimeOut (); public static void
+ * logString (String); public static void debugString (String); public static
+ * void logToMonitorString (String);
+ */
+
+ /**
+ * Main entry point for applications that do not subclass WOApplication.
+ */
+ public static void main(String[] argv) {
+ main(argv, WOApplication.class);
+ }
+
+ /**
+ * Subclasses may call this method to start a self-hosted web server to serve
+ * themselves directly (for testing).
+ */
+ public static void main(String[] argv, Class subclass) {
+ try {
+ int port = 0;
+ boolean open = false;
+ try {
+ port = ((Number) subclass.getMethod("port", new Class[0]).invoke(subclass, new Object[0])).intValue();
+ open = ((Boolean) subclass.getMethod("autoOpenInBrowser", new Class[0]).invoke(subclass, new Object[0]))
+ .booleanValue();
+ } catch (Throwable t) {
+ System.err.print("Error reading configuration:");
+ t.printStackTrace();
+ }
+
+ HttpServer server = new HttpServer();
+ HttpListener listener = server.addListener(new InetAddrPort(port));
+ org.mortbay.http.HttpContext context = server.getContext("/");
+ ServletHandler handler = new ServletHandler();
+ handler.addServlet("/", subclass.getName());
+ context.addHandler(handler);
+ server.start();
+ port = listener.getPort();
+ System.out.println("Waiting for requests: http://127.0.0.1:" + port);
+ if (open) {
+ BrowserLauncher.openURL("http://127.0.0.1:" + port);
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.30 2003/03/28 18:01:19 mpowers
- * Now defaulting port to zero.
+ * Revision 1.30 2003/03/28 18:01:19 mpowers Now defaulting port to zero.
*
- * Revision 1.29 2003/03/28 17:31:58 mpowers
- * Implemented support for autoselection of free port. (thanks gmuth!)
+ * Revision 1.29 2003/03/28 17:31:58 mpowers Implemented support for
+ * autoselection of free port. (thanks gmuth!)
*
- * Revision 1.28 2003/03/28 17:26:17 mpowers
- * Implemented package support: Applications can now live in packages.
- * Better support for locating package local classes.
+ * Revision 1.28 2003/03/28 17:26:17 mpowers Implemented package support:
+ * Applications can now live in packages. Better support for locating package
+ * local classes.
*
- * Revision 1.27 2003/02/21 16:40:22 mpowers
- * Now reading port and smtp host from system properties.
- * Implemented WOApplication.main.
+ * Revision 1.27 2003/02/21 16:40:22 mpowers Now reading port and smtp host from
+ * system properties. Implemented WOApplication.main.
*
- * Revision 1.26 2003/02/14 22:33:18 mpowers
- * Better handling for standalone mode.
+ * Revision 1.26 2003/02/14 22:33:18 mpowers Better handling for standalone
+ * mode.
*
- * Revision 1.25 2003/02/14 15:18:27 mpowers
- * Now launching standalone app as a servlet, not a webapp.
- * Disabled jetty's event logging.
+ * Revision 1.25 2003/02/14 15:18:27 mpowers Now launching standalone app as a
+ * servlet, not a webapp. Disabled jetty's event logging.
*
- * Revision 1.24 2003/02/13 22:41:04 mpowers
- * WOApplications can now be self-serving. Added configuration params too.
+ * Revision 1.24 2003/02/13 22:41:04 mpowers WOApplications can now be
+ * self-serving. Added configuration params too.
*
- * Revision 1.23 2003/01/28 19:33:51 mpowers
- * Implemented the rest of WOResourceManager.
- * Implemented support for java-style i18n.
- * Components now use the resource manager to load templates.
+ * Revision 1.23 2003/01/28 19:33:51 mpowers Implemented the rest of
+ * WOResourceManager. Implemented support for java-style i18n. Components now
+ * use the resource manager to load templates.
*
- * Revision 1.22 2003/01/27 15:08:00 mpowers
- * Implemented WOResourceManager, using java resources for now.
+ * Revision 1.22 2003/01/27 15:08:00 mpowers Implemented WOResourceManager,
+ * using java resources for now.
*
- * Revision 1.21 2003/01/24 20:13:22 mpowers
- * Now accepting immutable NSDictionary in constructor, not Map.
+ * Revision 1.21 2003/01/24 20:13:22 mpowers Now accepting immutable
+ * NSDictionary in constructor, not Map.
*
- * Revision 1.20 2003/01/20 17:50:11 mpowers
- * Caught a loop condition when same declaration was used twice.
+ * Revision 1.20 2003/01/20 17:50:11 mpowers Caught a loop condition when same
+ * declaration was used twice.
*
- * Revision 1.19 2003/01/19 22:33:25 mpowers
- * Fixed problems with classpath and dynamic class loading.
- * Dynamic elements now pass on ensureAwakeInContext.
+ * Revision 1.19 2003/01/19 22:33:25 mpowers Fixed problems with classpath and
+ * dynamic class loading. Dynamic elements now pass on ensureAwakeInContext.
* Parser how handles <standalone/> tags.
*
- * Revision 1.18 2003/01/18 23:54:50 mpowers
- * Implemented debugging enabled.
+ * Revision 1.18 2003/01/18 23:54:50 mpowers Implemented debugging enabled.
*
- * Revision 1.17 2003/01/17 20:58:18 mpowers
- * Fixed up WOHyperlink.
+ * Revision 1.17 2003/01/17 20:58:18 mpowers Fixed up WOHyperlink.
*
- * Revision 1.16 2003/01/17 20:34:17 mpowers
- * Rudimentary support for resource requests.
+ * Revision 1.16 2003/01/17 20:34:17 mpowers Rudimentary support for resource
+ * requests.
*
- * Revision 1.15 2003/01/17 15:31:56 mpowers
- * Removed spurious error message.
+ * Revision 1.15 2003/01/17 15:31:56 mpowers Removed spurious error message.
*
- * Revision 1.14 2003/01/17 14:39:00 mpowers
- * Now calling preferred constructor: WOComponent(WOContext)
+ * Revision 1.14 2003/01/17 14:39:00 mpowers Now calling preferred constructor:
+ * WOComponent(WOContext)
*
- * Revision 1.13 2003/01/16 20:10:46 mpowers
- * - components now synchronize bindings
- * - support for WOComponentContent
- * - implemented performParentAction
+ * Revision 1.13 2003/01/16 20:10:46 mpowers - components now synchronize
+ * bindings - support for WOComponentContent - implemented performParentAction
*
- * Revision 1.12 2003/01/16 15:50:43 mpowers
- * More robust declaration parsing.
- * Subcomponents are now supported.
- * dynamicElementWithName can now return subcomponents.
+ * Revision 1.12 2003/01/16 15:50:43 mpowers More robust declaration parsing.
+ * Subcomponents are now supported. dynamicElementWithName can now return
+ * subcomponents.
*
- * Revision 1.11 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.11 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.10 2003/01/13 22:24:18 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.10 2003/01/13 22:24:18 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.9 2003/01/10 20:17:41 mpowers
- * Component action urls are now working.
+ * Revision 1.9 2003/01/10 20:17:41 mpowers Component action urls are now
+ * working.
*
- * Revision 1.8 2003/01/10 19:16:40 mpowers
- * Implemented support for page caching.
+ * Revision 1.8 2003/01/10 19:16:40 mpowers Implemented support for page
+ * caching.
*
- * Revision 1.4 2002/12/19 17:58:52 mpowers
- * Rewrote the template parsing - no longer confused about "root element".
+ * Revision 1.4 2002/12/19 17:58:52 mpowers Rewrote the template parsing - no
+ * longer confused about "root element".
*
- * Revision 1.3 2002/12/18 14:12:38 mpowers
- * Support for differentiated request handlers.
- * Support url generation for WOContext and WORequest.
+ * Revision 1.3 2002/12/18 14:12:38 mpowers Support for differentiated request
+ * handlers. Support url generation for WOContext and WORequest.
*
- * Revision 1.2 2002/12/17 14:57:41 mpowers
- * Minor corrections to WORequests's parsing, and updated javadocs.
+ * Revision 1.2 2002/12/17 14:57:41 mpowers Minor corrections to WORequests's
+ * parsing, and updated javadocs.
*
- * Revision 1.1.1.1 2000/12/21 15:52:50 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:50 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOAssociation.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOAssociation.java
index 608f9fa..89623a6 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOAssociation.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOAssociation.java
@@ -19,150 +19,138 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web;
/**
-* A pure java implementation of WOAssociation. <br><br>
-*
-* A WOAssociation represents the mapping of a property on a
-* WOComponent to a property on a WOAssociation. For example: <br><br>
-*
-* MyAssociation: WOString { value = currentCustomer.location.city }; <br><br>
-*
-* This example represents a WOAssociation between the value field
-* on a WOString element and the city property of the location property
-* of the currentCustomer property of a WOComponent. <br><br>
-*
-* To resolve values, a property accessor method will be used in
-* preference to a public field, if both exist. Any null value
-* in the path will produce null. <br><br>
-*
-* A mapping represented in quotation marks: { value = "This is a test." }
-* is considered a constant value.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class WOAssociation implements java.io.Serializable
-{
+ * A pure java implementation of WOAssociation. <br>
+ * <br>
+ *
+ * A WOAssociation represents the mapping of a property on a WOComponent to a
+ * property on a WOAssociation. For example: <br>
+ * <br>
+ *
+ * MyAssociation: WOString { value = currentCustomer.location.city }; <br>
+ * <br>
+ *
+ * This example represents a WOAssociation between the value field on a WOString
+ * element and the city property of the location property of the currentCustomer
+ * property of a WOComponent. <br>
+ * <br>
+ *
+ * To resolve values, a property accessor method will be used in preference to a
+ * public field, if both exist. Any null value in the path will produce null.
+ * <br>
+ * <br>
+ *
+ * A mapping represented in quotation marks: { value = "This is a test." } is
+ * considered a constant value.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class WOAssociation implements java.io.Serializable {
protected Object value;
protected String path;
-
+
+ /**
+ * The default constructor. The static factory methods should be used to create
+ * instances of WOAssociation.
+ */
+ protected WOAssociation() {
+ value = null;
+ path = null;
+ }
+
/**
- * The default constructor. The static factory methods should
- * be used to create instances of WOAssociation.
- */
- protected WOAssociation ()
- {
- value = null;
- path = null;
- }
+ * Creates a WOAssociation that maps to a constant value.
+ */
+ public static WOAssociation associationWithValue(Object anObject) {
+ WOAssociation result = new WOAssociation();
+ result.value = anObject;
+ return result;
+ }
/**
- * Creates a WOAssociation that maps to a constant value.
- */
- public static WOAssociation associationWithValue (Object anObject)
- {
- WOAssociation result = new WOAssociation();
- result.value = anObject;
- return result;
- }
-
- /**
- * Creates a WOAssociation that maps to the specified key path.
- * If the path is null, the association will map to null.
- * Throws an exception if the property cannot be resolved.
- */
- public static WOAssociation associationWithKeyPath (String aString)
- {
- WOAssociation result = new WOAssociation();
- result.path = aString;
- return result;
- }
+ * Creates a WOAssociation that maps to the specified key path. If the path is
+ * null, the association will map to null. Throws an exception if the property
+ * cannot be resolved.
+ */
+ public static WOAssociation associationWithKeyPath(String aString) {
+ WOAssociation result = new WOAssociation();
+ result.path = aString;
+ return result;
+ }
/**
- * Returns the value for this association's key path in the
- * specified component, or null if any value in the path is
- * null or if the key path is null.
- */
- public Object valueInComponent (WOComponent aComponent)
- {
- if ( aComponent == null ) return null;
- if ( value != null ) return value;
- if ( path != null ) return aComponent.valueForKey( path );
- throw new RuntimeException(
- "WOAssociation: neither value nor path specified!" );
- }
-
- /**
- * Sets the property in the specified component to the specified value.
- * Throws an exception if the property cannot be resolved.
- */
- public void setValue (Object aValue, WOComponent aComponent)
- {
- if ( path != null )
- {
- aComponent.takeValueForKey( aValue, path );
+ * Returns the value for this association's key path in the specified component,
+ * or null if any value in the path is null or if the key path is null.
+ */
+ public Object valueInComponent(WOComponent aComponent) {
+ if (aComponent == null)
+ return null;
+ if (value != null)
+ return value;
+ if (path != null)
+ return aComponent.valueForKey(path);
+ throw new RuntimeException("WOAssociation: neither value nor path specified!");
+ }
+
+ /**
+ * Sets the property in the specified component to the specified value. Throws
+ * an exception if the property cannot be resolved.
+ */
+ public void setValue(Object aValue, WOComponent aComponent) {
+ if (path != null) {
+ aComponent.takeValueForKey(aValue, path);
return;
}
- throw new RuntimeException(
- "WOAssociation: tried to set value but no path was specified!" );
+ throw new RuntimeException("WOAssociation: tried to set value but no path was specified!");
+ }
+
+ /**
+ * Returns true if this association is writable; that is, returns true if this
+ * association is not constant.
+ */
+ public boolean isValueSettable() {
+ return (path != null);
}
/**
- * Returns true if this association is writable; that is,
- * returns true if this association is not constant.
- */
- public boolean isValueSettable ()
- {
- return ( path != null );
- }
-
- /**
- * Returns true if this association is constant
- * and therefore read-only.
- */
- public boolean isValueConstant ()
- {
- return ( path == null );
- }
-
- /**
- * For debugging purposes.
- */
- public String toString()
- {
- if ( path != null )
- {
- return "[WOAssociation:" + path + "]";
- }
- return "[WOAssociation:\"" + value + "\"]";
- }
-}
+ * Returns true if this association is constant and therefore read-only.
+ */
+ public boolean isValueConstant() {
+ return (path == null);
+ }
+
+ /**
+ * For debugging purposes.
+ */
+ public String toString() {
+ if (path != null) {
+ return "[WOAssociation:" + path + "]";
+ }
+ return "[WOAssociation:\"" + value + "\"]";
+ }
+}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.6 2003/01/24 20:13:22 mpowers
- * Now accepting immutable NSDictionary in constructor, not Map.
+ * Revision 1.6 2003/01/24 20:13:22 mpowers Now accepting immutable NSDictionary
+ * in constructor, not Map.
*
- * Revision 1.5 2003/01/17 22:55:08 mpowers
- * Straighted out the parent binding issue (I think).
- * Fixes for woextensions compatibility.
+ * Revision 1.5 2003/01/17 22:55:08 mpowers Straighted out the parent binding
+ * issue (I think). Fixes for woextensions compatibility.
*
- * Revision 1.3 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.3 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.2 2003/01/14 15:51:48 mpowers
- * Removed value() method from WOAssociaton.
+ * Revision 1.2 2003/01/14 15:51:48 mpowers Removed value() method from
+ * WOAssociaton.
*
- * Revision 1.1.1.1 2000/12/21 15:52:50 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:50 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOBody.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOBody.java
index 9f0707d..131d223 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOBody.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOBody.java
@@ -23,99 +23,91 @@ import net.wotonomy.foundation.NSData;
import net.wotonomy.foundation.NSDictionary;
/**
-* WOBody represents a page's "body" tag and is used to dynamically
-* set the background image for a page, and therefore works much like WOImage.
-*
-* Bindings are:
-* <UL>
-* <li>src: A static URL for the image source.</li>
-* <li>data: A NSData object with the image content. Must be used with mimeType.</li>
-* <li>mimeType: The MIME type for the image data. Can be used with filename or data bindings.</li>
-* <li>filename: The path to a file containing an image.</li>
-* <li>framework: The optional framework from whence the image should be retrieved (used in conjunction with filename).</li>
-* <li>key: A key under which this resource will be cached for repeated access.</li>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+ * WOBody represents a page's "body" tag and is used to dynamically set the
+ * background image for a page, and therefore works much like WOImage.
+ *
+ * Bindings are:
+ * <UL>
+ * <li>src: A static URL for the image source.</li>
+ * <li>data: A NSData object with the image content. Must be used with
+ * mimeType.</li>
+ * <li>mimeType: The MIME type for the image data. Can be used with filename or
+ * data bindings.</li>
+ * <li>filename: The path to a file containing an image.</li>
+ * <li>framework: The optional framework from whence the image should be
+ * retrieved (used in conjunction with filename).</li>
+ * <li>key: A key under which this resource will be cached for repeated
+ * access.</li>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOBody extends WOImage {
- protected String src;
- protected String filename;
- protected String framework;
- protected NSData data;
- protected String mimeType;
+ protected String src;
+ protected String filename;
+ protected String framework;
+ protected NSData data;
+ protected String mimeType;
- protected WOBody() {
- super();
- }
+ protected WOBody() {
+ super();
+ }
- public WOBody(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
+ public WOBody(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
- void ensureAwakeInContext (WOContext aContext)
- {
- if ( rootElement != null )
- {
- rootElement.ensureAwakeInContext( aContext );
- }
- }
+ void ensureAwakeInContext(WOContext aContext) {
+ if (rootElement != null) {
+ rootElement.ensureAwakeInContext(aContext);
+ }
+ }
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
- if ( rootElement != null )
- {
- rootElement.takeValuesFromRequest( aRequest, aContext );
- }
- }
-
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- if ( rootElement != null )
- {
- return rootElement.invokeAction( aRequest, aContext );
- }
- return null;
- }
-
- public void appendToResponse(WOResponse r, WOContext c)
- {
- r.appendContentString("<body background=\"");
- r.appendContentString(sourceURL(c));
- r.appendContentString("\"");
- r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "src", "filename", "framework", "data", "mimeType" })));
- r.appendContentString(">");
- if ( rootElement != null )
- {
- rootElement.appendToResponse( r, c );
- }
- r.appendContentString("</body>");
- }
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ if (rootElement != null) {
+ rootElement.takeValuesFromRequest(aRequest, aContext);
+ }
+ }
+
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ if (rootElement != null) {
+ return rootElement.invokeAction(aRequest, aContext);
+ }
+ return null;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<body background=\"");
+ r.appendContentString(sourceURL(c));
+ r.appendContentString("\"");
+ r.appendContentString(additionalHTMLProperties(c.component(),
+ new NSArray(new Object[] { "src", "filename", "framework", "data", "mimeType" })));
+ r.appendContentString(">");
+ if (rootElement != null) {
+ rootElement.appendToResponse(r, c);
+ }
+ r.appendContentString("</body>");
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2003/08/07 00:15:14 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.4 2003/08/07 00:15:14 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.3 2003/01/27 15:57:28 mpowers
- * Now participates in all parts of request/response cycle.
+ * Revision 1.3 2003/01/27 15:57:28 mpowers Now participates in all parts of
+ * request/response cycle.
*
- * Revision 1.2 2003/01/27 15:08:23 mpowers
- * Now appending to response.
+ * Revision 1.2 2003/01/27 15:08:23 mpowers Now appending to response.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCheckBox.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCheckBox.java
index 5d22d36..8e706c1 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCheckBox.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCheckBox.java
@@ -7,75 +7,75 @@ import net.wotonomy.foundation.NSMutableArray;
public class WOCheckBox extends WOInput {
- protected boolean checked = false;
+ protected boolean checked = false;
- public WOCheckBox() {
- super();
- }
+ public WOCheckBox() {
+ super();
+ }
- public WOCheckBox(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
+ public WOCheckBox(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
- protected String inputType() {
- return "CHECKBOX";
- }
+ protected String inputType() {
+ return "CHECKBOX";
+ }
- protected Object value(WOContext c) {
- Object val = null;
- boolean checked = false;
- if (associations.objectForKey("value") != null) {
- val = valueForProperty("value", c.component());
- Object sel = valueForProperty("selection", c.component());
- if (sel != null && val != null && sel.equals(val))
- checked = true;
- }
- if (val == null) {
- val = c.elementID();
- }
- return val;
- }
+ protected Object value(WOContext c) {
+ Object val = null;
+ boolean checked = false;
+ if (associations.objectForKey("value") != null) {
+ val = valueForProperty("value", c.component());
+ Object sel = valueForProperty("selection", c.component());
+ if (sel != null && val != null && sel.equals(val))
+ checked = true;
+ }
+ if (val == null) {
+ val = c.elementID();
+ }
+ return val;
+ }
- protected void appendExtras(WOResponse r, WOContext c) {
- checked |= booleanForProperty("checked", c.component());
- if (checked)
- r.appendContentString(" CHECKED");
- }
+ protected void appendExtras(WOResponse r, WOContext c) {
+ checked |= booleanForProperty("checked", c.component());
+ if (checked)
+ r.appendContentString(" CHECKED");
+ }
- protected NSMutableArray additionalAttributes() {
- NSMutableArray a = super.additionalAttributes();
- a.addObject("checked");
- a.addObject("selection");
- return a;
- }
+ protected NSMutableArray additionalAttributes() {
+ NSMutableArray a = super.additionalAttributes();
+ a.addObject("checked");
+ a.addObject("selection");
+ return a;
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- checked = false;
- super.appendToResponse(r, c);
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ checked = false;
+ super.appendToResponse(r, c);
+ }
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- if (disabled(c))
- return;
- NSArray values = r.formValuesForKey(inputName(c));
- Object val = valueForProperty("value", c.component());
- if (val == null)
- val = c.elementID();
- java.util.Enumeration enumerator = values.objectEnumerator();
- checked = false;
- while (enumerator.hasMoreElements()) {
- Object nextval = enumerator.nextElement();
- if (nextval.equals(val))
- checked = true;
- }
- if (associations.objectForKey("value") != null && associations.objectForKey("selection") != null) {
- if (checked)
- setValueForProperty("selection", val, c.component());
- else if (valueForProperty("selection", c.component()) != null)
- setValueForProperty("selection", null, c.component());
- }
- if (associations.objectForKey("checked") != null)
- setValueForProperty("checked", checked ? Boolean.TRUE : Boolean.FALSE, c.component());
- }
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ if (disabled(c))
+ return;
+ NSArray values = r.formValuesForKey(inputName(c));
+ Object val = valueForProperty("value", c.component());
+ if (val == null)
+ val = c.elementID();
+ java.util.Enumeration enumerator = values.objectEnumerator();
+ checked = false;
+ while (enumerator.hasMoreElements()) {
+ Object nextval = enumerator.nextElement();
+ if (nextval.equals(val))
+ checked = true;
+ }
+ if (associations.objectForKey("value") != null && associations.objectForKey("selection") != null) {
+ if (checked)
+ setValueForProperty("selection", val, c.component());
+ else if (valueForProperty("selection", c.component()) != null)
+ setValueForProperty("selection", null, c.component());
+ }
+ if (associations.objectForKey("checked") != null)
+ setValueForProperty("checked", checked ? Boolean.TRUE : Boolean.FALSE, c.component());
+ }
} \ No newline at end of file
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponent.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponent.java
index 20d8b0a..c99768c 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponent.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponent.java
@@ -42,1271 +42,1037 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.NSSelector;
/**
-* Pure java implementation of WOComponent.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOComponent
- extends WOElement
- implements WOActionResults,
- net.wotonomy.control.EOKeyValueCodingAdditions,
- net.wotonomy.control.EOKeyValueCoding
-{
+ * Pure java implementation of WOComponent.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOComponent extends WOElement implements WOActionResults, net.wotonomy.control.EOKeyValueCodingAdditions,
+ net.wotonomy.control.EOKeyValueCoding {
WOElement rootElement;
-
- private static final String DIRECTORY_SUFFIX = ".wo";
- private static final String TEMPLATE_SUFFIX = ".html";
- private static final String DECLARATION_SUFFIX = ".wod";
-
- private static final String OPEN_TAG = "webobject";
- private static final String CLOSE_TAG = "/webobject";
- private static final String NAME_KEY = "name";
-
- protected transient WOContext context; // don't persist
- protected boolean cachingEnabled;
- protected WOElement template;
- protected WOComponent parent;
+
+ private static final String DIRECTORY_SUFFIX = ".wo";
+ private static final String TEMPLATE_SUFFIX = ".html";
+ private static final String DECLARATION_SUFFIX = ".wod";
+
+ private static final String OPEN_TAG = "webobject";
+ private static final String CLOSE_TAG = "/webobject";
+ private static final String NAME_KEY = "name";
+
+ protected transient WOContext context; // don't persist
+ protected boolean cachingEnabled;
+ protected WOElement template;
+ protected WOComponent parent;
+
+ /**
+ * Default constructor. Deprecated in latest spec.
+ */
+ public WOComponent() {
+ parent = null;
+ cachingEnabled = true;
+ template = null;
+ }
+
+ /**
+ * Constructor specifying a context.
+ */
+ public WOComponent(WOContext aContext) {
+ this();
+ context = aContext;
+ }
+
+ /**
+ * Returns the name of the component, which is usually just the class name.
+ */
+ public String name() {
+ return justTheClassName();
+ }
/**
- * Default constructor. Deprecated in latest spec.
- */
- public WOComponent ()
- {
- parent = null;
- cachingEnabled = true;
- template = null;
- }
-
- /**
- * Constructor specifying a context.
- */
- public WOComponent( WOContext aContext )
- {
- this();
- context = aContext;
- }
-
+ * Returns the system-dependent file path to the current component directory,
+ * including the ".wo" extension.
+ */
+ public String path() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
/**
- * Returns the name of the component, which is usually just the class name.
- */
- public String name ()
- {
- return justTheClassName();
- }
-
- /**
- * Returns the system-dependent file path to the current component
- * directory, including the ".wo" extension.
- */
- public String path ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
+ * Returns the URL for this component, relative to the server's document root on
+ * the server's file system. This is not an http url.
+ */
+ public String baseURL() {
+ throw new RuntimeException("Not implemented yet.");
+ }
/**
- * Returns the URL for this component, relative to the server's
- * document root on the server's file system.
- * This is not an http url.
- */
- public String baseURL ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
+ * Returns the name of the framework that contains this component, or null if
+ * the component does not belong to a framework. This currently returns the
+ * package path of the class, or null if it does not belong to a package.
+ */
+ public String frameworkName() {
+ return justTheResourcePath();
+ }
/**
- * Returns the name of the framework that contains this component,
- * or null if the component does not belong to a framework.
- * This currently returns the package path of the class, or
- * null if it does not belong to a package.
- */
- public String frameworkName ()
- {
- return justTheResourcePath();
- }
-
- /**
- * Sets whether templates are cached. If true, templates will
- * only be read once per application lifetime. Otherwise, templates
- * will be read each time this class is instantiated. Defaults to false.
- */
- public void setCachingEnabled (boolean enabled)
- {
+ * Sets whether templates are cached. If true, templates will only be read once
+ * per application lifetime. Otherwise, templates will be read each time this
+ * class is instantiated. Defaults to false.
+ */
+ public void setCachingEnabled(boolean enabled) {
cachingEnabled = enabled;
}
- /**
- * Returns whether templates are cached. If true, templates are
- * read once per application lifetime. Otherwise, templates are
- * read each time this class is instantiated.
- */
- public boolean isCachingEnabled ()
- {
- return cachingEnabled && WOApplication.application().isCachingEnabled();
- }
-
- /**
- * Returns the root of the tree of elements produced by parsing
- * the templates in the component directory for this component.
- */
- public WOElement template()
- {
- return template;
- }
-
- /**
- * Returns the root of the tree of elements produced by parsing
- * the templates in the component directory for the named component.
- * @deprecated Use template() instead.
- */
- public WOElement templateWithName(String aComponentName)
- {
- return templateWithName( aComponentName, null );
- }
-
- /**
- * Returns the root of the tree of elements produced by parsing
- * the templates in the component directory for the named component.
- */
- WOElement templateWithName(String aComponentName, String aFramework)
- {
- NSArray languages = null;
- WOContext context = context();
- if ( context != null )
- {
- languages = context.request().browserLanguages();
- }
- WOElement result = templateWithHTMLString(
- readTemplateResource( aComponentName, aFramework, TEMPLATE_SUFFIX, languages ),
- readTemplateResource( aComponentName, aFramework, DECLARATION_SUFFIX, languages ),
- languages );
- if ( result == null )
- {
- System.out.println( "WOComponent.templateWithName: failed for " + aComponentName );
- }
- return result;
- }
-
- /**
- * Returns the root of the tree of elements produced by parsing
- * the specfified HTML string and bindings declaration string.
- * Note: language list is currently ignored.
- */
- public static WOElement templateWithHTMLString (
- String anHTMLString, String aDeclaration, List aLanguageList)
- {
- if ( anHTMLString == null ) return null;
- WOElement result = null;
- try
- {
- NSDictionary bindings = processDeclaration( aDeclaration );
- List elements = new LinkedList();
- int index = processTemplate( elements, anHTMLString, 0, bindings, aLanguageList );
- if ( index == -1 )
- {
- if ( elements.size() == 1 )
- {
- result = (WOElement) elements.get(0);
- }
- else
- {
- result = new WOParentElement( elements );
- }
- }
- else // entire template did not process
- {
- throw new RuntimeException( "No closing tag: " + anHTMLString.substring( index ) );
- }
- }
- catch ( Exception exc )
- {
- exc.printStackTrace();
- }
+ /**
+ * Returns whether templates are cached. If true, templates are read once per
+ * application lifetime. Otherwise, templates are read each time this class is
+ * instantiated.
+ */
+ public boolean isCachingEnabled() {
+ return cachingEnabled && WOApplication.application().isCachingEnabled();
+ }
+
+ /**
+ * Returns the root of the tree of elements produced by parsing the templates in
+ * the component directory for this component.
+ */
+ public WOElement template() {
+ return template;
+ }
+
+ /**
+ * Returns the root of the tree of elements produced by parsing the templates in
+ * the component directory for the named component.
+ *
+ * @deprecated Use template() instead.
+ */
+ public WOElement templateWithName(String aComponentName) {
+ return templateWithName(aComponentName, null);
+ }
+
+ /**
+ * Returns the root of the tree of elements produced by parsing the templates in
+ * the component directory for the named component.
+ */
+ WOElement templateWithName(String aComponentName, String aFramework) {
+ NSArray languages = null;
+ WOContext context = context();
+ if (context != null) {
+ languages = context.request().browserLanguages();
+ }
+ WOElement result = templateWithHTMLString(
+ readTemplateResource(aComponentName, aFramework, TEMPLATE_SUFFIX, languages),
+ readTemplateResource(aComponentName, aFramework, DECLARATION_SUFFIX, languages), languages);
+ if (result == null) {
+ System.out.println("WOComponent.templateWithName: failed for " + aComponentName);
+ }
return result;
- }
-
- /**
- * Called at the beginning of a request-response cycle.
- * Override to perform any necessary initialization.
- * This implementation does nothing.
- */
- public void awake ()
- {
- }
-
- /**
- * Package access only. Called to initialize the component with
- * the proper context before the start of the request-response cycle.
- * If the context has a current component, that component becomes
- * this component's parent.
- */
- void ensureAwakeInContext (WOContext aContext)
- {
+ }
+
+ /**
+ * Returns the root of the tree of elements produced by parsing the specfified
+ * HTML string and bindings declaration string. Note: language list is currently
+ * ignored.
+ */
+ public static WOElement templateWithHTMLString(String anHTMLString, String aDeclaration, List aLanguageList) {
+ if (anHTMLString == null)
+ return null;
+ WOElement result = null;
+ try {
+ NSDictionary bindings = processDeclaration(aDeclaration);
+ List elements = new LinkedList();
+ int index = processTemplate(elements, anHTMLString, 0, bindings, aLanguageList);
+ if (index == -1) {
+ if (elements.size() == 1) {
+ result = (WOElement) elements.get(0);
+ } else {
+ result = new WOParentElement(elements);
+ }
+ } else // entire template did not process
+ {
+ throw new RuntimeException("No closing tag: " + anHTMLString.substring(index));
+ }
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ }
+ return result;
+ }
+
+ /**
+ * Called at the beginning of a request-response cycle. Override to perform any
+ * necessary initialization. This implementation does nothing.
+ */
+ public void awake() {
+ }
+
+ /**
+ * Package access only. Called to initialize the component with the proper
+ * context before the start of the request-response cycle. If the context has a
+ * current component, that component becomes this component's parent.
+ */
+ void ensureAwakeInContext(WOContext aContext) {
context = aContext;
parent = aContext.parent();
- if ( template == null )
- {
- template = templateWithName( name(), frameworkName() );
- }
- if ( template != null )
- {
- template.ensureAwakeInContext( aContext );
- }
- awake();
- }
-
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
- if ( synchronizesVariablesWithBindings() )
- {
- pullValuesFromParent();
- if ( template != null )
- {
- template.takeValuesFromRequest( aRequest, aContext );
- }
- pushValuesToParent();
- }
- else
- if ( template != null )
- {
- template.takeValuesFromRequest( aRequest, aContext );
- }
- }
-
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- WOActionResults result = null;
- if ( synchronizesVariablesWithBindings() )
- {
- pullValuesFromParent();
- if ( template != null )
- {
- result = template.invokeAction( aRequest, aContext );
- }
- pushValuesToParent();
- }
- else
- if ( template != null )
- {
- result = template.invokeAction( aRequest, aContext );
- }
+ if (template == null) {
+ template = templateWithName(name(), frameworkName());
+ }
+ if (template != null) {
+ template.ensureAwakeInContext(aContext);
+ }
+ awake();
+ }
+
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ if (synchronizesVariablesWithBindings()) {
+ pullValuesFromParent();
+ if (template != null) {
+ template.takeValuesFromRequest(aRequest, aContext);
+ }
+ pushValuesToParent();
+ } else if (template != null) {
+ template.takeValuesFromRequest(aRequest, aContext);
+ }
+ }
+
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ WOActionResults result = null;
+ if (synchronizesVariablesWithBindings()) {
+ pullValuesFromParent();
+ if (template != null) {
+ result = template.invokeAction(aRequest, aContext);
+ }
+ pushValuesToParent();
+ } else if (template != null) {
+ result = template.invokeAction(aRequest, aContext);
+ }
return result;
- }
-
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- if ( synchronizesVariablesWithBindings() )
- {
- pullValuesFromParent();
- if ( template != null )
- {
- template.appendToResponse( aResponse, aContext );
- }
- pushValuesToParent();
- }
- else
- if ( template != null )
- {
- template.appendToResponse( aResponse, aContext );
- }
- context = null;
- }
-
- /**
- * Called at the end of a request-response cycle.
- * Override to perform any necessary clean-up.
- * This implementation does nothing.
- */
- public void sleep ()
- {
- }
-
- /**
- * Generates a WOResponse and calls appendToResponse() on it.
- */
- public WOResponse generateResponse ()
- {
- WOResponse response = new WOResponse();
- WOContext context = context();
- appendToResponse( response, context ); // nulls out context
- context.session().savePage( this ); //?is this the right place for this?
- return response;
- }
+ }
+
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ if (synchronizesVariablesWithBindings()) {
+ pullValuesFromParent();
+ if (template != null) {
+ template.appendToResponse(aResponse, aContext);
+ }
+ pushValuesToParent();
+ } else if (template != null) {
+ template.appendToResponse(aResponse, aContext);
+ }
+ context = null;
+ }
+
+ /**
+ * Called at the end of a request-response cycle. Override to perform any
+ * necessary clean-up. This implementation does nothing.
+ */
+ public void sleep() {
+ }
/**
- * Returns this component's parent component, or null if none.
- */
- public WOComponent parent()
- {
- return parent;
- }
-
- /**
- * Invokes the specified action on this component's parent.
- * Variables will be synchronized when this method returns.
- */
- public WOActionResults performParentAction(String anAction)
- {
- WOActionResults result = parent().performAction( anAction );
- if ( synchronizesVariablesWithBindings() )
- {
- pullValuesFromParent();
- }
- return result;
- }
-
- /**
- * Invokes the specified action on this component.
- */
- WOActionResults performAction( String anAction )
- {
- try
- {
- return (WOActionResults) NSSelector.invoke( anAction, this );
+ * Generates a WOResponse and calls appendToResponse() on it.
+ */
+ public WOResponse generateResponse() {
+ WOResponse response = new WOResponse();
+ WOContext context = context();
+ appendToResponse(response, context); // nulls out context
+ context.session().savePage(this); // ?is this the right place for this?
+ return response;
+ }
+
+ /**
+ * Returns this component's parent component, or null if none.
+ */
+ public WOComponent parent() {
+ return parent;
+ }
+
+ /**
+ * Invokes the specified action on this component's parent. Variables will be
+ * synchronized when this method returns.
+ */
+ public WOActionResults performParentAction(String anAction) {
+ WOActionResults result = parent().performAction(anAction);
+ if (synchronizesVariablesWithBindings()) {
+ pullValuesFromParent();
}
- catch ( NoSuchMethodException exc )
- {
+ return result;
+ }
+
+ /**
+ * Invokes the specified action on this component.
+ */
+ WOActionResults performAction(String anAction) {
+ try {
+ return (WOActionResults) NSSelector.invoke(anAction, this);
+ } catch (NoSuchMethodException exc) {
// returns below
- }
- catch ( InvocationTargetException exc )
- {
+ } catch (InvocationTargetException exc) {
Throwable t = exc.getTargetException();
- exc.printStackTrace();
- throw new RuntimeException( t.toString() );
+ exc.printStackTrace();
+ throw new RuntimeException(t.toString());
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ throw new RuntimeException(exc.toString());
}
- catch ( Exception exc )
- {
- exc.printStackTrace();
- throw new RuntimeException( exc.toString() );
+ return null;
+ }
+
+ /**
+ * Called before each phase of the request-response cycle, if
+ * synchronizesVariablesWithBindings is true and the component is not stateless.
+ */
+ public void pullValuesFromParent() {
+ if (associations == null)
+ return;
+ String key;
+ Enumeration e = associations.keyEnumerator();
+ while (e.hasMoreElements()) {
+ key = e.nextElement().toString();
+ takeValueForKey(valueForBinding(key), key);
+ }
+ }
+
+ /**
+ * Called after each phase of the request-response cycle, if
+ * synchronizesVariablesWithBindings is true and the component is not stateless.
+ */
+ public void pushValuesToParent() {
+ if (associations == null)
+ return;
+ String key;
+ Enumeration e = associations.keyEnumerator();
+ while (e.hasMoreElements()) {
+ key = e.nextElement().toString();
+ setValueForBinding(valueForKey(key), key);
}
- return null;
- }
-
- /**
- * Called before each phase of the request-response cycle,
- * if synchronizesVariablesWithBindings is true and the
- * component is not stateless.
- */
- public void pullValuesFromParent()
- {
- if ( associations == null ) return;
- String key;
- Enumeration e = associations.keyEnumerator();
- while ( e.hasMoreElements() )
- {
- key = e.nextElement().toString();
- takeValueForKey( valueForBinding( key ), key );
- }
- }
-
- /**
- * Called after each phase of the request-response cycle,
- * if synchronizesVariablesWithBindings is true and the
- * component is not stateless.
- */
- public void pushValuesToParent()
- {
- if ( associations == null ) return;
- String key;
- Enumeration e = associations.keyEnumerator();
- while ( e.hasMoreElements() )
- {
- key = e.nextElement().toString();
- setValueForBinding( valueForKey( key ), key );
- }
- }
-
- /**
- * Returns whether this component should be considered stateless.
- * Stateless components are shared between sessions to conserve memory.
- * This implementation returns false; override to return true.
- */
- public boolean isStateless()
- {
- return false;
- }
-
- /**
- * Called only on stateless components to tell themselves to reset
- * themselves for another invocation using a different context.
- * This implementation does nothing.
- */
- public void reset()
- {
- // does nothing
- }
-
- /**
- * Returns the application containing this instance of the class.
- */
- public WOApplication application ()
- {
- return context.application();
- }
-
- /**
- * Returns whether a session has been created for this user.
- */
- public boolean hasSession ()
- {
- return context.hasSession();
- }
-
- /**
- * Returns the current session object, creating it if it doesn't exist.
- */
- public WOSession session ()
- {
- return context.session();
- }
+ }
+
+ /**
+ * Returns whether this component should be considered stateless. Stateless
+ * components are shared between sessions to conserve memory. This
+ * implementation returns false; override to return true.
+ */
+ public boolean isStateless() {
+ return false;
+ }
+
+ /**
+ * Called only on stateless components to tell themselves to reset themselves
+ * for another invocation using a different context. This implementation does
+ * nothing.
+ */
+ public void reset() {
+ // does nothing
+ }
/**
- * Returns the current context for this component.
- */
- public WOContext context ()
- {
- return context;
- }
+ * Returns the application containing this instance of the class.
+ */
+ public WOApplication application() {
+ return context.application();
+ }
/**
- * Returns a new WOComponent with the specified name.
- * If null, returns the component named "Main".
- * If the named component doesn't exist, returns null.
- */
- public WOComponent pageWithName (String aName)
- {
- return application().pageWithName( aName, context() );
- }
+ * Returns whether a session has been created for this user.
+ */
+ public boolean hasSession() {
+ return context.hasSession();
+ }
/**
- * Called when exceptions are raised by assigning values
- * to this object. This implementation does nothing, but
- * subclasses may override to do something useful.
- */
- public void validationFailedWithException (
- Throwable anException, Object aValue, String aPath)
- {
- // does nothing
- }
+ * Returns the current session object, creating it if it doesn't exist.
+ */
+ public WOSession session() {
+ return context.session();
+ }
/**
- * Called on the component that represents the requested page.
- * Override to return logging information specific to your
- * component. This implementation returns the component's name.
- */
- public String descriptionForResponse (
- WOResponse aResponse, WOContext aContext)
- {
- return name();
- }
+ * Returns the current context for this component.
+ */
+ public WOContext context() {
+ return context;
+ }
/**
- * Returns true if this component should get and set values
- * in its parent. This implementation returns true.
- * Override to create a component that does not automatically
- * synchronize bindings with its parent, useful if you wish
- * to handle synchronization manually.
- */
- public boolean synchronizesVariablesWithBindings ()
- {
- return true;
- }
-
- /**
- * Returns whether this component has a readable value that maps
- * to the specified binding. This implementation calls
- * hasBinding(aBinding).
- */
- public boolean canGetValueForBinding(String aBinding)
- {
- return hasBinding( aBinding );
- }
-
- /**
- * Returns whether this component has a writable value that maps
- * to the specified binding.
- */
- public boolean canSetValueForBinding(String aBinding)
- {
- WOAssociation assoc =
- (WOAssociation)associations.objectForKey(aBinding);
- if (assoc != null)
- {
- if ( assoc.isValueSettable() ) return true;
- }
- return false;
- }
-
- /**
- * Returns whether this component has the specified binding.
- */
- public boolean hasBinding (String aBinding)
- {
- if ( associations == null ) return false;
- return associations.containsKey( aBinding );
- }
+ * Returns a new WOComponent with the specified name. If null, returns the
+ * component named "Main". If the named component doesn't exist, returns null.
+ */
+ public WOComponent pageWithName(String aName) {
+ return application().pageWithName(aName, context());
+ }
+
+ /**
+ * Called when exceptions are raised by assigning values to this object. This
+ * implementation does nothing, but subclasses may override to do something
+ * useful.
+ */
+ public void validationFailedWithException(Throwable anException, Object aValue, String aPath) {
+ // does nothing
+ }
+
+ /**
+ * Called on the component that represents the requested page. Override to
+ * return logging information specific to your component. This implementation
+ * returns the component's name.
+ */
+ public String descriptionForResponse(WOResponse aResponse, WOContext aContext) {
+ return name();
+ }
/**
- * Returns the value for the specified binding for this component.
- * The parent component is expected to have set the binding for
- * this component. If no such binding exists, the binding is
- * treated as a property is and obtained using valueForKey.
- * If the property is not found, this method returns null.
- */
- public Object valueForBinding (String aBinding)
- {
- WOComponent parent = parent();
- if ( associations != null )
- {
- WOAssociation assoc =
- (WOAssociation)associations.objectForKey(aBinding);
- if (assoc != null && parent != null)
- {
- return assoc.valueInComponent( parent );
- }
- }
- if ( parent != null )
- {
- return parent.valueForKey( aBinding );
- }
- return null;
- }
+ * Returns true if this component should get and set values in its parent. This
+ * implementation returns true. Override to create a component that does not
+ * automatically synchronize bindings with its parent, useful if you wish to
+ * handle synchronization manually.
+ */
+ public boolean synchronizesVariablesWithBindings() {
+ return true;
+ }
+
+ /**
+ * Returns whether this component has a readable value that maps to the
+ * specified binding. This implementation calls hasBinding(aBinding).
+ */
+ public boolean canGetValueForBinding(String aBinding) {
+ return hasBinding(aBinding);
+ }
+
+ /**
+ * Returns whether this component has a writable value that maps to the
+ * specified binding.
+ */
+ public boolean canSetValueForBinding(String aBinding) {
+ WOAssociation assoc = (WOAssociation) associations.objectForKey(aBinding);
+ if (assoc != null) {
+ if (assoc.isValueSettable())
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether this component has the specified binding.
+ */
+ public boolean hasBinding(String aBinding) {
+ if (associations == null)
+ return false;
+ return associations.containsKey(aBinding);
+ }
+
+ /**
+ * Returns the value for the specified binding for this component. The parent
+ * component is expected to have set the binding for this component. If no such
+ * binding exists, the binding is treated as a property is and obtained using
+ * valueForKey. If the property is not found, this method returns null.
+ */
+ public Object valueForBinding(String aBinding) {
+ WOComponent parent = parent();
+ if (associations != null) {
+ WOAssociation assoc = (WOAssociation) associations.objectForKey(aBinding);
+ if (assoc != null && parent != null) {
+ return assoc.valueInComponent(parent);
+ }
+ }
+ if (parent != null) {
+ return parent.valueForKey(aBinding);
+ }
+ return null;
+ }
/**
- * Sets the value for the specified binding for this component.
- * The parent component is expected to have set the binding
- * for this component. If no such binding exists, the binding
- * is treated as a property and is set using takeValueForKey.
- * If the property is not found, this method fails silently.
- */
- public void setValueForBinding (Object aValue, String aBinding)
- {
- if ( associations == null ) return;
-
- WOComponent parent = parent();
-
- if ( associations != null )
- {
- WOAssociation assoc =
- (WOAssociation)associations.objectForKey(aBinding);
- if (assoc != null && parent != null)
- {
- if ( assoc.isValueSettable() )
- {
- assoc.setValue( aValue, parent );
- return;
- }
- }
- }
- if ( parent != null )
- {
- parent.takeValueForKey( aValue, aBinding );
- }
- }
-
- public static void logString (String aString)
- {
- System.out.println( aString );
- }
-
- public static void debugString (String aString)
- {
- System.err.println( aString );
- }
-
- public Object valueForKeyPath (String aPath)
- {
- // currently key value coding support also handles keypaths
- return valueForKey( aPath );
- }
-
- public void takeValueForKeyPath (Object aValue, String aPath)
- {
- // currently key value coding support also handles keypaths
- takeValueForKey( aValue, aPath );
- }
-
- public NSDictionary valuesForKeys (List aKeyList)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public void takeValuesFromDictionary (Map aValueMap)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public Object valueForKey (String aKey)
- { // System.out.println( "valueForKey: " + aKey + "->" + this );
- // handle "^" property keys
- if ( aKey.startsWith( "^" ) )
- {
- return valueForBinding( aKey.substring(1) );
- }
- return EOKeyValueCodingSupport.valueForKey( this, aKey );
- }
-
- public void takeValueForKey (Object aValue, String aKey)
- { // System.out.println( "takeValueForKey: " + aKey + " : " + aValue + "->" + this );
- // handle "^" property keys
- if ( aKey.startsWith( "^" ) )
- {
- setValueForBinding( aValue, aKey.substring(1) );
- return;
- }
- EOKeyValueCodingSupport.takeValueForKey( this, aValue, aKey );
- }
-
- public Object storedValueForKey (String aKey)
- {
- return EOKeyValueCodingSupport.storedValueForKey( this, aKey );
- }
-
- public void takeStoredValueForKey (Object aValue, String aKey)
- {
- EOKeyValueCodingSupport.takeStoredValueForKey( this, aValue, aKey );
- }
-
- public Object handleQueryWithUnboundKey (String aKey)
- {
- return EOKeyValueCodingSupport.handleQueryWithUnboundKey( this, aKey );
- }
-
- public void handleTakeValueForUnboundKey (Object aValue, String aKey)
- {
- EOKeyValueCodingSupport.handleTakeValueForUnboundKey( this, aValue, aKey );
- }
-
- public void unableToSetNullForKey (String aKey)
- {
- EOKeyValueCodingSupport.unableToSetNullForKey( this, aKey );
- }
-
- public Object validateTakeValueForKeyPath (Object aValue, String aKey)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
+ * Sets the value for the specified binding for this component. The parent
+ * component is expected to have set the binding for this component. If no such
+ * binding exists, the binding is treated as a property and is set using
+ * takeValueForKey. If the property is not found, this method fails silently.
+ */
+ public void setValueForBinding(Object aValue, String aBinding) {
+ if (associations == null)
+ return;
+
+ WOComponent parent = parent();
+
+ if (associations != null) {
+ WOAssociation assoc = (WOAssociation) associations.objectForKey(aBinding);
+ if (assoc != null && parent != null) {
+ if (assoc.isValueSettable()) {
+ assoc.setValue(aValue, parent);
+ return;
+ }
+ }
+ }
+ if (parent != null) {
+ parent.takeValueForKey(aValue, aBinding);
+ }
+ }
+
+ public static void logString(String aString) {
+ System.out.println(aString);
+ }
+
+ public static void debugString(String aString) {
+ System.err.println(aString);
+ }
+
+ public Object valueForKeyPath(String aPath) {
+ // currently key value coding support also handles keypaths
+ return valueForKey(aPath);
+ }
+
+ public void takeValueForKeyPath(Object aValue, String aPath) {
+ // currently key value coding support also handles keypaths
+ takeValueForKey(aValue, aPath);
+ }
+
+ public NSDictionary valuesForKeys(List aKeyList) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public void takeValuesFromDictionary(Map aValueMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+ public Object valueForKey(String aKey) { // System.out.println( "valueForKey: " + aKey + "->" + this );
+ // handle "^" property keys
+ if (aKey.startsWith("^")) {
+ return valueForBinding(aKey.substring(1));
+ }
+ return EOKeyValueCodingSupport.valueForKey(this, aKey);
+ }
+
+ public void takeValueForKey(Object aValue, String aKey) { // System.out.println( "takeValueForKey: " + aKey + " : "
+ // + aValue + "->" + this );
+ // handle "^" property keys
+ if (aKey.startsWith("^")) {
+ setValueForBinding(aValue, aKey.substring(1));
+ return;
+ }
+ EOKeyValueCodingSupport.takeValueForKey(this, aValue, aKey);
+ }
+
+ public Object storedValueForKey(String aKey) {
+ return EOKeyValueCodingSupport.storedValueForKey(this, aKey);
+ }
+
+ public void takeStoredValueForKey(Object aValue, String aKey) {
+ EOKeyValueCodingSupport.takeStoredValueForKey(this, aValue, aKey);
+ }
+
+ public Object handleQueryWithUnboundKey(String aKey) {
+ return EOKeyValueCodingSupport.handleQueryWithUnboundKey(this, aKey);
+ }
+
+ public void handleTakeValueForUnboundKey(Object aValue, String aKey) {
+ EOKeyValueCodingSupport.handleTakeValueForUnboundKey(this, aValue, aKey);
+ }
+
+ public void unableToSetNullForKey(String aKey) {
+ EOKeyValueCodingSupport.unableToSetNullForKey(this, aKey);
+ }
+
+ public Object validateTakeValueForKeyPath(Object aValue, String aKey) {
+ throw new RuntimeException("Not implemented yet.");
+ }
// Template Processing
- /**
- * Takes a template string and a location to begin parsing,
- * looking only for interesting tags, and calling itself recursively
- * as necessary. Returns the index to resume parsing, or -1 if done.
- */
- static private int processTemplate(
- List elements, String template, int index,
- Map bindings, List aLanguageList )
- throws java.io.IOException
- { //System.out.println( "processTemplate: " + index );
- if ( template == null ) return -1;
-
- int start = index;
-
- while ( true )
- {
- // search for start of next tag
- start = template.indexOf( '<', start );
-
- if ( start == -1 )
- {
- // if no tags, send output and return
- elements.add( new WOStaticElement( template.substring( index ) ) );
- return -1;
- }
-
- // search for end of opening tag
- int end = template.indexOf( ">", start + 1 );
- if ( end == -1 )
- {
- // if no end to tag
- throw new RuntimeException( "No end to tag: "
- + template.substring( start ) );
- }
-
- boolean hasBody = true;
- if ( template.charAt( end - 1 ) == '/' )
- {
- // tag is standalone - no body
- end = end - 1;
- hasBody = false;
- }
-
- // search for name of tag
- int endName = start + 1;
- while ( endName < end )
- {
- if ( Character.isWhitespace(
- template.charAt(endName) ) ) break;
- endName++;
- }
-
- String name = template.substring( start + 1, endName );
-
- if ( name.toLowerCase().startsWith( OPEN_TAG ) )
- {
- // add the contents before the tag
- //System.out.println( index + " : " + start + " : " + hasBody );
- elements.add( new WOStaticElement( template.substring( index, start ) ) );
-
- // interesting tag; parse parameters
- Map params = new HashMap( 5 ); // arbitrary init length
- if ( endName < end )
- {
- // delimit by whitespace
- StringTokenizer tokens = new StringTokenizer(
- template.substring( endName+1, end ) );
- int equals;
- String token;
- String value;
- while ( tokens.hasMoreTokens() )
- {
- token = tokens.nextToken();
- equals = token.indexOf( '=' );
- if ( equals != -1 )
- {
- value = token.substring( equals+1 );
-
- if ( value.startsWith( "\"" ) )
- {
- // handle spaces within parameter names
- while ( ! value.endsWith( "\"" ) )
- {
- value = value + " " + tokens.nextToken();
- }
-
- // strip quotation marks
- if ( value.endsWith( "\"" ) )
- {
- value = value.substring( 1, value.length()-1 );
- }
- }
-
- // register key with specified value
- params.put(
- token.substring( 0, equals ).toLowerCase(), value );
-
- }
- else
- {
- // no value found, register the key name
- params.put( token.toLowerCase(), "" );
- }
- }
- }
-
- index = end + (hasBody?1:2);
-
- WOElement body = null;
- if ( hasBody )
- {
- List childElements = new LinkedList();
-
- index = processTemplate(
- childElements, template, index,
- bindings, aLanguageList );
- start = index;
-
- if ( index == -1 )
- {
- throw new RuntimeException(
- "No closing tag found: " + template.substring( end ) );
- }
-
- if ( childElements.size() == 1 )
- {
- body = (WOElement) childElements.get(0);
- }
- else
- {
- body = new WOParentElement( childElements );
- }
- }
-
- WOElement element = null;
- String nameProperty = (String) params.get( NAME_KEY );
- NSDictionary original = (NSDictionary) bindings.get( nameProperty );
- //System.out.println( nameProperty + " : " + associations );
- if ( original == null )
- {
- original = NSDictionary.EmptyDictionary;
- System.err.println( "No associations for: " + nameProperty );
- System.err.println( bindings );
- }
-
- NSDictionary associations = new NSMutableDictionary( original );
- String elementClass = (String) associations.remove( WOApplication.ELEMENT_CLASS );
-
- WOApplication application = WOApplication.application();
- element = application.dynamicElementWithName(
- elementClass, associations, body, aLanguageList );
- if ( element == null )
- {
- // unable to create element: show assocs in static element
- element = new WOStaticElement( associations.toString() );
- }
-
- //System.out.println( element );
- elements.add( element );
-
- if ( !hasBody )
- {
- start = end + 2;
- }
- }
- else
- if ( name.toLowerCase().startsWith( CLOSE_TAG ) )
- {
- // add any contents before the tag
- elements.add( new WOStaticElement( template.substring( index, start ) ) );
-
+ /**
+ * Takes a template string and a location to begin parsing, looking only for
+ * interesting tags, and calling itself recursively as necessary. Returns the
+ * index to resume parsing, or -1 if done.
+ */
+ static private int processTemplate(List elements, String template, int index, Map bindings, List aLanguageList)
+ throws java.io.IOException { // System.out.println( "processTemplate: " + index );
+ if (template == null)
+ return -1;
+
+ int start = index;
+
+ while (true) {
+ // search for start of next tag
+ start = template.indexOf('<', start);
+
+ if (start == -1) {
+ // if no tags, send output and return
+ elements.add(new WOStaticElement(template.substring(index)));
+ return -1;
+ }
+
+ // search for end of opening tag
+ int end = template.indexOf(">", start + 1);
+ if (end == -1) {
+ // if no end to tag
+ throw new RuntimeException("No end to tag: " + template.substring(start));
+ }
+
+ boolean hasBody = true;
+ if (template.charAt(end - 1) == '/') {
+ // tag is standalone - no body
+ end = end - 1;
+ hasBody = false;
+ }
+
+ // search for name of tag
+ int endName = start + 1;
+ while (endName < end) {
+ if (Character.isWhitespace(template.charAt(endName)))
+ break;
+ endName++;
+ }
+
+ String name = template.substring(start + 1, endName);
+
+ if (name.toLowerCase().startsWith(OPEN_TAG)) {
+ // add the contents before the tag
+ // System.out.println( index + " : " + start + " : " + hasBody );
+ elements.add(new WOStaticElement(template.substring(index, start)));
+
+ // interesting tag; parse parameters
+ Map params = new HashMap(5); // arbitrary init length
+ if (endName < end) {
+ // delimit by whitespace
+ StringTokenizer tokens = new StringTokenizer(template.substring(endName + 1, end));
+ int equals;
+ String token;
+ String value;
+ while (tokens.hasMoreTokens()) {
+ token = tokens.nextToken();
+ equals = token.indexOf('=');
+ if (equals != -1) {
+ value = token.substring(equals + 1);
+
+ if (value.startsWith("\"")) {
+ // handle spaces within parameter names
+ while (!value.endsWith("\"")) {
+ value = value + " " + tokens.nextToken();
+ }
+
+ // strip quotation marks
+ if (value.endsWith("\"")) {
+ value = value.substring(1, value.length() - 1);
+ }
+ }
+
+ // register key with specified value
+ params.put(token.substring(0, equals).toLowerCase(), value);
+
+ } else {
+ // no value found, register the key name
+ params.put(token.toLowerCase(), "");
+ }
+ }
+ }
+
+ index = end + (hasBody ? 1 : 2);
+
+ WOElement body = null;
+ if (hasBody) {
+ List childElements = new LinkedList();
+
+ index = processTemplate(childElements, template, index, bindings, aLanguageList);
+ start = index;
+
+ if (index == -1) {
+ throw new RuntimeException("No closing tag found: " + template.substring(end));
+ }
+
+ if (childElements.size() == 1) {
+ body = (WOElement) childElements.get(0);
+ } else {
+ body = new WOParentElement(childElements);
+ }
+ }
+
+ WOElement element = null;
+ String nameProperty = (String) params.get(NAME_KEY);
+ NSDictionary original = (NSDictionary) bindings.get(nameProperty);
+ // System.out.println( nameProperty + " : " + associations );
+ if (original == null) {
+ original = NSDictionary.EmptyDictionary;
+ System.err.println("No associations for: " + nameProperty);
+ System.err.println(bindings);
+ }
+
+ NSDictionary associations = new NSMutableDictionary(original);
+ String elementClass = (String) associations.remove(WOApplication.ELEMENT_CLASS);
+
+ WOApplication application = WOApplication.application();
+ element = application.dynamicElementWithName(elementClass, associations, body, aLanguageList);
+ if (element == null) {
+ // unable to create element: show assocs in static element
+ element = new WOStaticElement(associations.toString());
+ }
+
+ // System.out.println( element );
+ elements.add(element);
+
+ if (!hasBody) {
+ start = end + 2;
+ }
+ } else if (name.toLowerCase().startsWith(CLOSE_TAG)) {
+ // add any contents before the tag
+ elements.add(new WOStaticElement(template.substring(index, start)));
+
// return end + name.length() + 1; // "<" + ">" - 1 = 1
- return end + (hasBody?1:2); // "<" + ">" - 1 = 1
- }
- else
- {
- // tag not interesting: continue
- start = end + (hasBody?1:2);
- }
- }
- }
-
-
- // Utility Methods
-
- static private void rewriteTag( String tagName,
- Map properties, String body, StringBuffer context )
- throws java.io.IOException
- {
- context.append( "<"+tagName );
+ return end + (hasBody ? 1 : 2); // "<" + ">" - 1 = 1
+ } else {
+ // tag not interesting: continue
+ start = end + (hasBody ? 1 : 2);
+ }
+ }
+ }
+
+ // Utility Methods
+
+ static private void rewriteTag(String tagName, Map properties, String body, StringBuffer context)
+ throws java.io.IOException {
+ context.append("<" + tagName);
Iterator it = properties.keySet().iterator();
String key;
- while ( it.hasNext() )
- {
+ while (it.hasNext()) {
key = (String) it.next();
- context.append( " " + key + "=\"" + properties.get( key ) + "\"" );
+ context.append(" " + key + "=\"" + properties.get(key) + "\"");
}
-
- if ( body == null )
- {
- context.append( "/>" );
+
+ if (body == null) {
+ context.append("/>");
return;
}
-
- context.append( ">" + body + "</" + tagName + ">" );
+
+ context.append(">" + body + "</" + tagName + ">");
+ }
+
+ private String justTheClassName() {
+ String className = getClass().getName();
+ int index = className.lastIndexOf(".");
+ if (index == -1)
+ return className;
+ return className.substring(index + 1);
+ }
+
+ private String justTheResourcePath() {
+ int last = -1;
+ char[] src = getClass().getName().toCharArray();
+ char[] dst = new char[src.length];
+ for (int i = 0; i < src.length; i++) {
+ if (src[i] == '.') {
+ dst[i] = '/';
+ last = i;
+ } else {
+ dst[i] = src[i];
+ }
+ }
+ if (last == -1)
+ return null;
+ return new String(dst, 0, last);
}
-
- private String justTheClassName()
- {
- String className = getClass().getName();
- int index = className.lastIndexOf( "." );
- if ( index == -1 ) return className;
- return className.substring( index+1 );
- }
-
- private String justTheResourcePath()
- {
- int last = -1;
- char[] src = getClass().getName().toCharArray();
- char[] dst = new char[ src.length ];
- for ( int i = 0; i < src.length; i++ )
- {
- if ( src[i] == '.' )
- {
- dst[i] = '/';
- last = i;
- }
- else
- {
- dst[i] = src[i];
- }
- }
- if ( last == -1 ) return null;
- return new String( dst, 0, last );
- }
-
- private String readTemplateResource( String name, String framework, String suffix, NSArray languages )
- {
- if ( name == null ) return null;
- name = name + DIRECTORY_SUFFIX + '/' + name + suffix;
- InputStream is = null;
- if ( isCachingEnabled() )
- {
- byte[] data = WOApplication.application().resourceManager().bytesForResourceNamed(
- name, framework, languages );
- if ( data != null )
- {
- is = new ByteArrayInputStream( data );
- }
- }
- else
- {
- is = WOApplication.application().resourceManager().inputStreamForResourceNamed(
- name, framework, languages );
- }
- if ( is == null )
- {
- System.err.println( "No resources found for: " + name );
- return null;
- }
-
- // try to autodetect encoding
- String encoding = "ISO8859_1";
- try
- {
- byte[] header = new byte[4];
- is = new PushbackInputStream( is, 4 );
- is.read( header );
- if ( header[0] < 33 || header[0] > 126 )
- {
- // if any funny characters, presume UTF-16
- encoding = "UTF-16";
- if (!( header[1] < 33 || header[1] > 126 ))
- {
- // if second character is valid, presume UTF-8
- encoding = "UTF-8";
- }
- }
- // check byte-order-mark
- if (header[0] == 0xef && header[1] == 0xbb && header[2] == 0xbf) // utf-8
- {
- encoding = "UTF-8";
- }
- else
- if (header[0] == 0xfe && header[1] == 0xff) // utf-16
- {
- encoding = "UTF-16";
- }
- else
- if (header[0] == 0 && header[1] == 0 && header[2] == 0xfe && header[3] == 0xff) // ucs-4
- {
- encoding = "UCS-4"; //??
- }
- else
- if (header[0] == 0xff && header[1] == 0xfe) // ucs-2le, ucs-4le, and
- {
- encoding = "UCS-16le"; //??
- }
- // put back the header
- ((PushbackInputStream)is).unread( header );
- }
- catch ( Throwable t )
- {
- t.printStackTrace();
- System.err.println(
- "Error while autodetecting encoding: should never happen" );
- }
-
- try
- {
- String line;
- StringBuffer buf = new StringBuffer();
- BufferedReader r = new BufferedReader( new InputStreamReader( is, encoding ) );
- while ( ( line = r.readLine() ) != null )
- {
- buf.append( line );
- buf.append( '\n' );
- }
- is.close(); // release the resource
- return buf.toString();
- }
- catch ( IOException exc )
- {
- System.err.println( "Error while reading: " + name );
- exc.printStackTrace();
- return null;
- }
- }
-
- // Declaration Parsing
-
- /**
- * Parses the declarations in the specified content and returns a map of element names
- * to maps of attribute names to WOAssociations.
- */
- private static NSDictionary processDeclaration( String content )
- {
- int index;
- NSMutableDictionary result = new NSMutableDictionary();
-
- // strip out comments
- StringBuffer stripped = new StringBuffer();
- try
- {
- LineNumberReader reader =
- new LineNumberReader( new StringReader( content ) );
- String line;
- while ( ( line = reader.readLine() ) != null )
- {
- index = line.indexOf("//");
- while (index > -1) {
- //(chochos) This used to truncate lines with quoted URLs
- //in them. We have to check that the "//" is not inside quotes.
- boolean quoted = false;
- if (index > 0) {
- for (int _position = 0; _position < index; _position++)
- if (line.charAt(_position) == '"')
- quoted = !quoted;
- }
- if (!quoted) {
- line = line.substring( 0, index );
- index = -1;
- } else {
- //if we didn't truncate the line it's because the //
- //were quoted. let's look for more, and check if they're not quoted...
- index = line.indexOf("\"", index);
- if (index > 0) {
- index = line.indexOf("//", index);
- }
- }
- }
- stripped.append( line );
- }
+
+ private String readTemplateResource(String name, String framework, String suffix, NSArray languages) {
+ if (name == null)
+ return null;
+ name = name + DIRECTORY_SUFFIX + '/' + name + suffix;
+ InputStream is = null;
+ if (isCachingEnabled()) {
+ byte[] data = WOApplication.application().resourceManager().bytesForResourceNamed(name, framework,
+ languages);
+ if (data != null) {
+ is = new ByteArrayInputStream(data);
+ }
+ } else {
+ is = WOApplication.application().resourceManager().inputStreamForResourceNamed(name, framework, languages);
}
- catch ( IOException exc )
- {
- throw new RuntimeException(
- "Error while stripping comments from declaration: " + stripped );
+ if (is == null) {
+ System.err.println("No resources found for: " + name);
+ return null;
}
- while ( (index = stripped.toString().indexOf( "/*" )) != -1 )
- {
- int j = stripped.toString().indexOf( "*/", index+1 );
- if ( j == -1 ) break;
- stripped.delete( index, j+2 );
- }
-
- String token;
- StringTokenizer tokens = new StringTokenizer( stripped.toString(), "{}", true );
- while ( tokens.hasMoreTokens() )
- {
- token = tokens.nextToken();
-
- // next token is the name and class
- String name, cl;
- index = token.indexOf( ":" );
- if ( index > -1 )
- {
- name = token.substring( 0, index ).trim();
- cl = token.substring( index+1 ).trim();
+
+ // try to autodetect encoding
+ String encoding = "ISO8859_1";
+ try {
+ byte[] header = new byte[4];
+ is = new PushbackInputStream(is, 4);
+ is.read(header);
+ if (header[0] < 33 || header[0] > 126) {
+ // if any funny characters, presume UTF-16
+ encoding = "UTF-16";
+ if (!(header[1] < 33 || header[1] > 126)) {
+ // if second character is valid, presume UTF-8
+ encoding = "UTF-8";
+ }
}
- else
+ // check byte-order-mark
+ if (header[0] == 0xef && header[1] == 0xbb && header[2] == 0xbf) // utf-8
+ {
+ encoding = "UTF-8";
+ } else if (header[0] == 0xfe && header[1] == 0xff) // utf-16
+ {
+ encoding = "UTF-16";
+ } else if (header[0] == 0 && header[1] == 0 && header[2] == 0xfe && header[3] == 0xff) // ucs-4
{
- System.err.println( "Could not parse declaration:" );
- System.err.println( content );
- throw new RuntimeException(
- "Could not parse declaration: " + token );
- }
+ encoding = "UCS-4"; // ??
+ } else if (header[0] == 0xff && header[1] == 0xfe) // ucs-2le, ucs-4le, and
+ {
+ encoding = "UCS-16le"; // ??
+ }
+ // put back the header
+ ((PushbackInputStream) is).unread(header);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ System.err.println("Error while autodetecting encoding: should never happen");
+ }
+
+ try {
+ String line;
+ StringBuffer buf = new StringBuffer();
+ BufferedReader r = new BufferedReader(new InputStreamReader(is, encoding));
+ while ((line = r.readLine()) != null) {
+ buf.append(line);
+ buf.append('\n');
+ }
+ is.close(); // release the resource
+ return buf.toString();
+ } catch (IOException exc) {
+ System.err.println("Error while reading: " + name);
+ exc.printStackTrace();
+ return null;
+ }
+ }
+
+ // Declaration Parsing
+
+ /**
+ * Parses the declarations in the specified content and returns a map of element
+ * names to maps of attribute names to WOAssociations.
+ */
+ private static NSDictionary processDeclaration(String content) {
+ int index;
+ NSMutableDictionary result = new NSMutableDictionary();
+
+ // strip out comments
+ StringBuffer stripped = new StringBuffer();
+ try {
+ LineNumberReader reader = new LineNumberReader(new StringReader(content));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ index = line.indexOf("//");
+ while (index > -1) {
+ // (chochos) This used to truncate lines with quoted URLs
+ // in them. We have to check that the "//" is not inside quotes.
+ boolean quoted = false;
+ if (index > 0) {
+ for (int _position = 0; _position < index; _position++)
+ if (line.charAt(_position) == '"')
+ quoted = !quoted;
+ }
+ if (!quoted) {
+ line = line.substring(0, index);
+ index = -1;
+ } else {
+ // if we didn't truncate the line it's because the //
+ // were quoted. let's look for more, and check if they're not quoted...
+ index = line.indexOf("\"", index);
+ if (index > 0) {
+ index = line.indexOf("//", index);
+ }
+ }
+ }
+ stripped.append(line);
+ }
+ } catch (IOException exc) {
+ throw new RuntimeException("Error while stripping comments from declaration: " + stripped);
+ }
+ while ((index = stripped.toString().indexOf("/*")) != -1) {
+ int j = stripped.toString().indexOf("*/", index + 1);
+ if (j == -1)
+ break;
+ stripped.delete(index, j + 2);
+ }
+
+ String token;
+ StringTokenizer tokens = new StringTokenizer(stripped.toString(), "{}", true);
+ while (tokens.hasMoreTokens()) {
+ token = tokens.nextToken();
+
+ // next token is the name and class
+ String name, cl;
+ index = token.indexOf(":");
+ if (index > -1) {
+ name = token.substring(0, index).trim();
+ cl = token.substring(index + 1).trim();
+ } else {
+ System.err.println("Could not parse declaration:");
+ System.err.println(content);
+ throw new RuntimeException("Could not parse declaration: " + token);
+ }
// next token is the declaration for the name and class
- if ( ! tokens.hasMoreTokens() )
- {
- System.err.println( "Could not find associations for declaration:" );
- System.err.println( content );
- throw new RuntimeException(
- "Could not find associations for declaration: " + name );
+ if (!tokens.hasMoreTokens()) {
+ System.err.println("Could not find associations for declaration:");
+ System.err.println(content);
+ throw new RuntimeException("Could not find associations for declaration: " + name);
+ }
+
+ token = tokens.nextToken();
+ if (token.equals("{")) {
+ if (!tokens.hasMoreTokens())
+ throw new RuntimeException("Error parsing declaration: expected { but found: '" + token + "'");
+ token = tokens.nextToken();
+ }
+
+ NSMutableDictionary associations = new NSMutableDictionary();
+
+ if (!token.equals("}")) {
+ String line, key, value;
+ StringTokenizer lines = new StringTokenizer(token, ";");
+ while (lines.hasMoreElements()) {
+ line = lines.nextToken();
+ index = line.indexOf("=");
+ if (index > -1) {
+ if (line.length() == index + 1)
+ line += " ";
+ key = line.substring(0, index).trim();
+ value = line.substring(index + 1).trim();
+ } else {
+ // not a valid key: skip
+ key = null;
+ value = null;
+ }
+
+ if (key != null) {
+ // if in quotation marks
+ if ((value.startsWith("\"")) && (value.endsWith("\""))) {
+ // it's a constant value association
+ value = value.substring(1, value.length() - 1);
+ associations.put(key, WOAssociation.associationWithValue(value));
+ } else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
+ // HACK: needed to be compatible with woextensions
+ // apparently true and false are allowed without quotes
+ associations.put(key, WOAssociation.associationWithValue(value));
+ } else {
+ // HACK: needed to be compatible with woextensions:
+ // apparently a standalone integer is allowed without quotes.
+ try {
+ Integer.parseInt(value); // does it parse?
+ associations.put(key, WOAssociation.associationWithValue(value));
+ } catch (NumberFormatException nfe) {
+ // did not parse:
+ // it's a key path association
+ associations.put(key, WOAssociation.associationWithKeyPath(value));
+ }
+ }
+ }
+ }
+ if (tokens.hasMoreTokens()) {
+ token = tokens.nextToken();
+ if (!token.equals("}"))
+ throw new RuntimeException("Error parsing declaration: expected } but found: '" + token + "'");
+ }
}
-
- token = tokens.nextToken();
- if ( token.equals( "{" ) )
- {
- if ( !tokens.hasMoreTokens() ) throw new RuntimeException(
- "Error parsing declaration: expected { but found: '" + token + "'" );
- token = tokens.nextToken();
- }
-
- NSMutableDictionary associations = new NSMutableDictionary();
-
- if ( !token.equals( "}" ) )
- {
- String line, key, value;
- StringTokenizer lines =
- new StringTokenizer( token, ";" );
- while ( lines.hasMoreElements() )
- {
- line = lines.nextToken();
- index = line.indexOf( "=" );
- if ( index > -1 )
- {
- if ( line.length() == index+ 1 ) line += " ";
- key = line.substring( 0, index ).trim();
- value = line.substring( index+1 ).trim();
- }
- else
- {
- // not a valid key: skip
- key = null;
- value = null;
- }
-
- if ( key != null )
- {
- // if in quotation marks
- if ( ( value.startsWith( "\"" ) ) && ( value.endsWith( "\"" ) ) )
- {
- // it's a constant value association
- value = value.substring( 1, value.length()-1 );
- associations.put( key,
- WOAssociation.associationWithValue( value ) );
- }
- else
- if ( value.equalsIgnoreCase( "true" ) || value.equalsIgnoreCase( "false" ) )
- {
- //HACK: needed to be compatible with woextensions
- // apparently true and false are allowed without quotes
- associations.put( key,
- WOAssociation.associationWithValue( value ) );
- }
- else
- {
- //HACK: needed to be compatible with woextensions:
- // apparently a standalone integer is allowed without quotes.
- try
- {
- Integer.parseInt( value ); // does it parse?
- associations.put( key,
- WOAssociation.associationWithValue( value ) );
- }
- catch ( NumberFormatException nfe )
- {
- // did not parse:
- // it's a key path association
- associations.put( key,
- WOAssociation.associationWithKeyPath( value ) );
- }
- }
- }
- }
- if ( tokens.hasMoreTokens() )
- {
- token = tokens.nextToken();
- if ( !token.equals( "}" ) ) throw new RuntimeException(
- "Error parsing declaration: expected } but found: '" + token + "'" );
- }
- }
- associations.put( WOApplication.ELEMENT_CLASS, cl ); // store classname
- result.put( name, associations );
-
- }
- //System.out.println( "processDeclaration: " + result );
- return result;
- }
+ associations.put(WOApplication.ELEMENT_CLASS, cl); // store classname
+ result.put(name, associations);
+
+ }
+ // System.out.println( "processDeclaration: " + result );
+ return result;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.32 2003/08/07 00:15:14 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.32 2003/08/07 00:15:14 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.31 2003/07/24 00:23:21 chochos
- * fixed problem with parsing wod files that have //-type comments. Quotes URL's would be truncated.
+ * Revision 1.31 2003/07/24 00:23:21 chochos fixed problem with parsing wod
+ * files that have //-type comments. Quotes URL's would be truncated.
*
- * Revision 1.30 2003/03/28 15:33:11 mpowers
- * Now using a PushBackInputStream for auto detection of content encoding.
- * No longer relying on markSupported() since jar input streams don't have it.
+ * Revision 1.30 2003/03/28 15:33:11 mpowers Now using a PushBackInputStream for
+ * auto detection of content encoding. No longer relying on markSupported()
+ * since jar input streams don't have it.
*
- * Revision 1.29 2003/03/03 16:41:52 mpowers
- * Bad characters in cvs log.
+ * Revision 1.29 2003/03/03 16:41:52 mpowers Bad characters in cvs log.
*
- * Revision 1.28 2003/03/03 16:37:35 mpowers
- * Better handling for string encodings.
- * Now trying to autodetect unicode-formatted templates and declarations.
- * Now handlings block-style comments in declarations.
+ * Revision 1.28 2003/03/03 16:37:35 mpowers Better handling for string
+ * encodings. Now trying to autodetect unicode-formatted templates and
+ * declarations. Now handlings block-style comments in declarations.
*
- * Revision 1.27 2003/01/28 19:33:51 mpowers
- * Implemented the rest of WOResourceManager.
- * Implemented support for java-style i18n.
- * Components now use the resource manager to load templates.
+ * Revision 1.27 2003/01/28 19:33:51 mpowers Implemented the rest of
+ * WOResourceManager. Implemented support for java-style i18n. Components now
+ * use the resource manager to load templates.
*
- * Revision 1.26 2003/01/24 20:13:22 mpowers
- * Now accepting immutable NSDictionary in constructor, not Map.
+ * Revision 1.26 2003/01/24 20:13:22 mpowers Now accepting immutable
+ * NSDictionary in constructor, not Map.
*
- * Revision 1.25 2003/01/21 17:53:45 mpowers
- * Now correctly reporting error for missing bindings.
+ * Revision 1.25 2003/01/21 17:53:45 mpowers Now correctly reporting error for
+ * missing bindings.
*
- * Revision 1.24 2003/01/20 17:50:11 mpowers
- * Caught a loop condition when same declaration was used twice.
+ * Revision 1.24 2003/01/20 17:50:11 mpowers Caught a loop condition when same
+ * declaration was used twice.
*
- * Revision 1.23 2003/01/19 22:33:25 mpowers
- * Fixed problems with classpath and dynamic class loading.
- * Dynamic elements now pass on ensureAwakeInContext.
+ * Revision 1.23 2003/01/19 22:33:25 mpowers Fixed problems with classpath and
+ * dynamic class loading. Dynamic elements now pass on ensureAwakeInContext.
* Parser how handles <standalone/> tags.
*
- * Revision 1.22 2003/01/17 22:55:09 mpowers
- * Straighted out the parent binding issue (I think).
- * Fixes for woextensions compatibility.
+ * Revision 1.22 2003/01/17 22:55:09 mpowers Straighted out the parent binding
+ * issue (I think). Fixes for woextensions compatibility.
*
- * Revision 1.21 2003/01/17 20:34:57 mpowers
- * Better handling for components and parents in the context's element stack.
+ * Revision 1.21 2003/01/17 20:34:57 mpowers Better handling for components and
+ * parents in the context's element stack.
*
- * Revision 1.19 2003/01/17 15:32:22 mpowers
- * Changes to better support generic elements and containers.
- * Now preserving newlines in templates.
+ * Revision 1.19 2003/01/17 15:32:22 mpowers Changes to better support generic
+ * elements and containers. Now preserving newlines in templates.
*
- * Revision 1.17 2003/01/16 22:47:30 mpowers
- * Compatibility changes to support compiling woextensions source.
- * (34 out of 56 classes compile!)
+ * Revision 1.17 2003/01/16 22:47:30 mpowers Compatibility changes to support
+ * compiling woextensions source. (34 out of 56 classes compile!)
*
- * Revision 1.15 2003/01/16 15:50:43 mpowers
- * More robust declaration parsing.
- * Subcomponents are now supported.
- * dynamicElementWithName can now return subcomponents.
+ * Revision 1.15 2003/01/16 15:50:43 mpowers More robust declaration parsing.
+ * Subcomponents are now supported. dynamicElementWithName can now return
+ * subcomponents.
*
- * Revision 1.14 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.14 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.13 2003/01/15 14:33:48 mpowers
- * Refactoring: element id handling is now confined to WOParentElement.
- * Other elements/components should not have to do element id incrementing.
+ * Revision 1.13 2003/01/15 14:33:48 mpowers Refactoring: element id handling is
+ * now confined to WOParentElement. Other elements/components should not have to
+ * do element id incrementing.
*
- * Revision 1.12 2003/01/14 16:05:12 mpowers
- * Removed extraneous printlns.
+ * Revision 1.12 2003/01/14 16:05:12 mpowers Removed extraneous printlns.
*
- * Revision 1.11 2003/01/13 22:24:25 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.11 2003/01/13 22:24:25 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.10 2003/01/10 19:33:28 mpowers
- * Added contextID for the component url generation.
+ * Revision 1.10 2003/01/10 19:33:28 mpowers Added contextID for the component
+ * url generation.
*
- * Revision 1.9 2003/01/10 19:16:40 mpowers
- * Implemented support for page caching.
+ * Revision 1.9 2003/01/10 19:16:40 mpowers Implemented support for page
+ * caching.
*
- * Revision 1.8 2003/01/09 21:16:48 mpowers
- * Bringing request-response cycle more into conformance.
+ * Revision 1.8 2003/01/09 21:16:48 mpowers Bringing request-response cycle more
+ * into conformance.
*
- * Revision 1.7 2003/01/09 16:13:55 mpowers
- * Implemented WOComponentRequestHandler:
- * Bringing the request-response cycle more into conformance.
+ * Revision 1.7 2003/01/09 16:13:55 mpowers Implemented
+ * WOComponentRequestHandler: Bringing the request-response cycle more into
+ * conformance.
*
- * Revision 1.6 2002/12/20 22:56:33 mpowers
- * Reimplemented the template parsing again.
- * Nested components are now correctly parsed.
- * ElementID numbering is now working.
+ * Revision 1.6 2002/12/20 22:56:33 mpowers Reimplemented the template parsing
+ * again. Nested components are now correctly parsed. ElementID numbering is now
+ * working.
*
- * Revision 1.3 2002/12/18 14:12:38 mpowers
- * Support for differentiated request handlers.
- * Support url generation for WOContext and WORequest.
+ * Revision 1.3 2002/12/18 14:12:38 mpowers Support for differentiated request
+ * handlers. Support url generation for WOContext and WORequest.
*
- * Revision 1.2 2002/11/07 18:52:33 mpowers
- * New components courtesy of ezamudio@nasoft.com. Many thanks!
+ * Revision 1.2 2002/11/07 18:52:33 mpowers New components courtesy of
+ * ezamudio@nasoft.com. Many thanks!
*
- * Revision 1.1.1.1 2000/12/21 15:53:01 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:01 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentContent.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentContent.java
index 1544934..909212c 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentContent.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentContent.java
@@ -21,25 +21,28 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
- * Used to include a component's content inside another component. This way, you can create reusable components
- * with content that surrounds the component it's in. In reality all it does is forward the appendToResponse
- * method to the WOElement containing the HTML between the WEBOBJECT tags that define this element.
+ * Used to include a component's content inside another component. This way, you
+ * can create reusable components with content that surrounds the component it's
+ * in. In reality all it does is forward the appendToResponse method to the
+ * WOElement containing the HTML between the WEBOBJECT tags that define this
+ * element.
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOComponentContent extends WODynamicElement {
- public WOComponentContent() {
- super();
- }
+ public WOComponentContent() {
+ super();
+ }
- public WOComponentContent(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOComponentContent(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- c.component().rootElement.appendToResponse(r, c);
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ c.component().rootElement.appendToResponse(r, c);
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentRequestHandler.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentRequestHandler.java
index 9f79987..9d35ab4 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentRequestHandler.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentRequestHandler.java
@@ -18,212 +18,168 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web;
-
/**
-* An implementation of WORequestHandler that dispatches Component actions.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOComponentRequestHandler
- extends WORequestHandler
-{
- public WOResponse handleRequest( WORequest aRequest )
- {
- WOApplication application = aRequest.application();
- WOContext context = WOContext.contextWithRequest( aRequest );
- WOResponse response = null;
-
- // no concurrent access is allowed to a user's session:
- // a user/browser/machine with multiple requests will have to wait
- synchronized ( aRequest.request.getSession() )
- {
- try
- {
- application.awake();
-
- WOSession session = null;
- /*
- // the NeXT way
- String sessionID = aRequest.sessionID();
- if ( sessionID != null )
- {
- session = application.restoreSessionWithID( sessionID, context );
- if ( session == null )
- {
- response = application.handleSessionRestorationErrorInContext( context );
- }
- }
- else
- {
- session = application.createSessionForRequest( aRequest );
- if ( session == null )
- {
- response = application.handleSessionCreationErrorInContext( context );
- }
- else
- {
- session.setContext( context );
- }
- }
- */
- // the servlet way
- String sessionID = aRequest.sessionID();
- if ( sessionID != null )
- {
- session = application.restoreSessionWithID( sessionID, context );
- }
-
- if ( session == null )
- {
- session = application.createSessionForRequest( aRequest );
- if ( session == null )
- {
- response = application.handleSessionCreationErrorInContext( context );
- }
- else
- {
- session.setContext( context );
- }
- }
-
- context.setSession( session );
-
- session.awake();
-
- if ( response == null )
- {
-
- WOComponent page;
- String contextID = aRequest.contextID();
-
- if ( contextID != null )
- {
- page = session.restorePageForContextID( contextID );
- }
- else
- {
- page = application.pageWithName( aRequest.pageName(), context );
- }
-
- if ( page == null )
- {
- //FIXME: should we call this a restoration error, or do we
- // allow a bookmark with an expired context id to resume gracefully?
- page = application.pageWithName( aRequest.pageName(), context );
- //!response = application.handlePageRestorationErrorInContext( context );
- }
- //!else
- {
- context.pushElement( page ); //? needed?
- page.ensureAwakeInContext( context ); //? shouldn't this be in WOApplication?
-
- // only take values from request if there are values in the request
- System.out.println("should I takeValuesFromRequest ? " + ( aRequest.formValueKeys().count() > 0 ));
- if ( aRequest.formValueKeys().count() > 0 )
- {
- application.takeValuesFromRequest( aRequest, context );
- }
-
- // only invoke action if there is a sender id to invoke
- WOActionResults result;
- System.out.println("senderID: " + aRequest.senderID());
- if ( aRequest.senderID() != null )
- {
- result = application.invokeAction( aRequest, context );
- }
- else
- {
- result = null;
- }
-
- if ( result == null || result == page ) // same page is returned
- {
- result = page;
-
- // generate response
- response = new WOResponse();
- application.appendToResponse( response, context );
- page.sleep();
- }
- else // different page is returned
- if ( result instanceof WOComponent )
- {
- page.sleep();
- page = (WOComponent) result;
- page.ensureAwakeInContext( context );
- context.popElement(); // removes page
- context.pushElement( page );
-
- // generate response
- response = new WOResponse();
- application.appendToResponse( response, context );
- page.sleep();
- }
- else // WOResponse was returnd
- {
- response = (WOResponse) result;
- }
-
- context.popElement();
- session.sleep();
- session.savePage( page );
- session.setContext( null );
- application.saveSessionForContext( context );
- }
- }
- }
- catch ( Throwable t )
- {
- response = application.handleException( t, context );
- }
-
- application.sleep();
- }
- return response;
- }
+ * An implementation of WORequestHandler that dispatches Component actions.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOComponentRequestHandler extends WORequestHandler {
+ public WOResponse handleRequest(WORequest aRequest) {
+ WOApplication application = aRequest.application();
+ WOContext context = WOContext.contextWithRequest(aRequest);
+ WOResponse response = null;
+
+ // no concurrent access is allowed to a user's session:
+ // a user/browser/machine with multiple requests will have to wait
+ synchronized (aRequest.request.getSession()) {
+ try {
+ application.awake();
+
+ WOSession session = null;
+ /*
+ * // the NeXT way String sessionID = aRequest.sessionID(); if ( sessionID !=
+ * null ) { session = application.restoreSessionWithID( sessionID, context ); if
+ * ( session == null ) { response =
+ * application.handleSessionRestorationErrorInContext( context ); } } else {
+ * session = application.createSessionForRequest( aRequest ); if ( session ==
+ * null ) { response = application.handleSessionCreationErrorInContext( context
+ * ); } else { session.setContext( context ); } }
+ */
+ // the servlet way
+ String sessionID = aRequest.sessionID();
+ if (sessionID != null) {
+ session = application.restoreSessionWithID(sessionID, context);
+ }
+
+ if (session == null) {
+ session = application.createSessionForRequest(aRequest);
+ if (session == null) {
+ response = application.handleSessionCreationErrorInContext(context);
+ } else {
+ session.setContext(context);
+ }
+ }
+
+ context.setSession(session);
+
+ session.awake();
+
+ if (response == null) {
+
+ WOComponent page;
+ String contextID = aRequest.contextID();
+
+ if (contextID != null) {
+ page = session.restorePageForContextID(contextID);
+ } else {
+ page = application.pageWithName(aRequest.pageName(), context);
+ }
+
+ if (page == null) {
+ // FIXME: should we call this a restoration error, or do we
+ // allow a bookmark with an expired context id to resume gracefully?
+ page = application.pageWithName(aRequest.pageName(), context);
+ // !response = application.handlePageRestorationErrorInContext( context );
+ }
+ // !else
+ {
+ context.pushElement(page); // ? needed?
+ page.ensureAwakeInContext(context); // ? shouldn't this be in WOApplication?
+
+ // only take values from request if there are values in the request
+ System.out
+ .println("should I takeValuesFromRequest ? " + (aRequest.formValueKeys().count() > 0));
+ if (aRequest.formValueKeys().count() > 0) {
+ application.takeValuesFromRequest(aRequest, context);
+ }
+
+ // only invoke action if there is a sender id to invoke
+ WOActionResults result;
+ System.out.println("senderID: " + aRequest.senderID());
+ if (aRequest.senderID() != null) {
+ result = application.invokeAction(aRequest, context);
+ } else {
+ result = null;
+ }
+
+ if (result == null || result == page) // same page is returned
+ {
+ result = page;
+
+ // generate response
+ response = new WOResponse();
+ application.appendToResponse(response, context);
+ page.sleep();
+ } else // different page is returned
+ if (result instanceof WOComponent) {
+ page.sleep();
+ page = (WOComponent) result;
+ page.ensureAwakeInContext(context);
+ context.popElement(); // removes page
+ context.pushElement(page);
+
+ // generate response
+ response = new WOResponse();
+ application.appendToResponse(response, context);
+ page.sleep();
+ } else // WOResponse was returnd
+ {
+ response = (WOResponse) result;
+ }
+
+ context.popElement();
+ session.sleep();
+ session.savePage(page);
+ session.setContext(null);
+ application.saveSessionForContext(context);
+ }
+ }
+ } catch (Throwable t) {
+ response = application.handleException(t, context);
+ }
+
+ application.sleep();
+ }
+ return response;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.8 2003/08/07 00:15:15 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.8 2003/08/07 00:15:15 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.7 2003/01/17 20:34:57 mpowers
- * Better handling for components and parents in the context's element stack.
+ * Revision 1.7 2003/01/17 20:34:57 mpowers Better handling for components and
+ * parents in the context's element stack.
*
- * Revision 1.6 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.6 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.4 2003/01/14 15:51:09 mpowers
- * No longer calling takeValues or invokeAction if there are no request params
+ * Revision 1.4 2003/01/14 15:51:09 mpowers No longer calling takeValues or
+ * invokeAction if there are no request params
*
- * Revision 1.3 2003/01/13 22:24:34 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.3 2003/01/13 22:24:34 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.1 2003/01/09 16:13:59 mpowers
- * Implemented WOComponentRequestHandler:
- * Bringing the request-response cycle more into conformance.
+ * Revision 1.1 2003/01/09 16:13:59 mpowers Implemented
+ * WOComponentRequestHandler: Bringing the request-response cycle more into
+ * conformance.
*
- * Revision 1.2 2002/12/17 14:57:44 mpowers
- * Minor corrections to WORequests's parsing, and updated javadocs.
+ * Revision 1.2 2002/12/17 14:57:44 mpowers Minor corrections to WORequests's
+ * parsing, and updated javadocs.
*
- * Revision 1.1.1.1 2000/12/21 15:53:19 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:19 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:50 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:50 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOConditional.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOConditional.java
index 124ca11..d0ab35e 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOConditional.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOConditional.java
@@ -21,14 +21,13 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
-* WOConditional renders whatever is inside its opening and closing tags
- * only if a condition is met.
- * Bindings are:
+ * WOConditional renders whatever is inside its opening and closing tags only if
+ * a condition is met. Bindings are:
* <ul>
- * <li>condition: a boolean property that indicates whether the contents of the element
- * should be displayed, invoked, or passed the request form values.</li>
- * <li>negate: if this is true, then the behavior of the element is reversed, showing its
- * contents only if the condition is NOT met.</li>
+ * <li>condition: a boolean property that indicates whether the contents of the
+ * element should be displayed, invoked, or passed the request form values.</li>
+ * <li>negate: if this is true, then the behavior of the element is reversed,
+ * showing its contents only if the condition is NOT met.</li>
* </ul>
*
* @author ezamudio@nasoft.com
@@ -37,63 +36,65 @@ import net.wotonomy.foundation.NSDictionary;
*/
public class WOConditional extends WODynamicElement {
- public boolean condition;
- public boolean negate;
-
- protected WOConditional() {
- super();
- }
-
- public WOConditional(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
-
- public void setCondition(boolean value) {
- condition = value;
- }
- public boolean condition() {
- return condition;
- }
-
- public void setNegate(boolean value) {
- negate = value;
- }
- public boolean negate() {
- return negate;
- }
-
- protected void pullValuesFromParent(WOComponent c) {
- condition = booleanForProperty("condition", c);
- negate = booleanForProperty("negate", c);
- }
-
- public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
- if (rootElement == null)
- return;
- pullValuesFromParent(aContext.component());
- if ((condition && !negate) || (!condition && negate)) {
- rootElement.takeValuesFromRequest(aRequest, aContext);
- }
- }
-
- public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
- if (rootElement == null)
- return null;
- pullValuesFromParent(aContext.component());
- WOActionResults el = null;
- if ((condition && !negate) || (!condition && negate)) {
- el = rootElement.invokeAction(aRequest, aContext);
- }
- return el;
- }
-
- public void appendToResponse(WOResponse aResponse, WOContext aContext) {
- if (rootElement == null)
- return;
- pullValuesFromParent(aContext.component());
- if ((condition && !negate) || (!condition && negate)) {
- rootElement.appendToResponse(aResponse, aContext);
- }
- }
+ public boolean condition;
+ public boolean negate;
+
+ protected WOConditional() {
+ super();
+ }
+
+ public WOConditional(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
+
+ public void setCondition(boolean value) {
+ condition = value;
+ }
+
+ public boolean condition() {
+ return condition;
+ }
+
+ public void setNegate(boolean value) {
+ negate = value;
+ }
+
+ public boolean negate() {
+ return negate;
+ }
+
+ protected void pullValuesFromParent(WOComponent c) {
+ condition = booleanForProperty("condition", c);
+ negate = booleanForProperty("negate", c);
+ }
+
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ if (rootElement == null)
+ return;
+ pullValuesFromParent(aContext.component());
+ if ((condition && !negate) || (!condition && negate)) {
+ rootElement.takeValuesFromRequest(aRequest, aContext);
+ }
+ }
+
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ if (rootElement == null)
+ return null;
+ pullValuesFromParent(aContext.component());
+ WOActionResults el = null;
+ if ((condition && !negate) || (!condition && negate)) {
+ el = rootElement.invokeAction(aRequest, aContext);
+ }
+ return el;
+ }
+
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ if (rootElement == null)
+ return;
+ pullValuesFromParent(aContext.component());
+ if ((condition && !negate) || (!condition && negate)) {
+ rootElement.appendToResponse(aResponse, aContext);
+ }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOContext.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOContext.java
index 4f774e6..40c5f5c 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOContext.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOContext.java
@@ -25,548 +25,455 @@ import java.util.List;
import java.util.Map;
/**
-* A pure java implementation of WOContext.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOContext
-{
+ * A pure java implementation of WOContext.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOContext {
private WOSession session;
private WORequest request;
private WOResponse response;
- private List elementStack;
+ private List elementStack;
private boolean isInForm;
private boolean isDistributionEnabled;
- private static final String EMPTY = "";
- private static final String SEP = ".";
- private static final String ZERO = "0";
- private static final String HTTP = "http://";
- private static final String HTTPS = "https://";
+ private static final String EMPTY = "";
+ private static final String SEP = ".";
+ private static final String ZERO = "0";
+ private static final String HTTP = "http://";
+ private static final String HTTPS = "https://";
// package access
WOComponent page;
WOComponent component;
StringBuffer elementID;
-
- private static volatile int contextCounter = 0;
- private String contextID;
-
- /**
- * Default constructor performs necessary initialization.
- * Subclassers should override the static factory method below.
- */
- public WOContext ()
- {
- contextID = null;
- elementID = new StringBuffer();
- elementStack = new LinkedList();
- }
-
- /**
- * Preferred constructor performs necessary initialization.
- * Subclassers should override this method.
- */
- public WOContext (WORequest aRequest)
- {
- this();
- request = aRequest;
- response = new WOResponse();
- }
-
- /**
- * Simply calls the preferred constructor.
- * Included for compatibility.
- */
- public static WOContext contextWithRequest (WORequest aRequest)
- {
- String id = Integer.toString( contextCounter++ );
- WOContext result = new WOContext( aRequest );
- result.contextID = id;
- return result;
- }
-
- /**
- * Returns the context id.
- */
- public String contextID ()
- {
- return contextID;
- }
-
- /**
- * Returns the sender id, or null if it doesn't exist.
- */
- public String senderID ()
- {
- return request.senderID();
- }
-
- /**
- * Returns the element id, or null if it doesn't exist.
- */
- public String elementID ()
- {
- return elementID.toString();
- }
-
- /**
- * Returns this context's application, or null if it doesn't exist.
- */
- public WOApplication application ()
- {
- return request.application();
- }
-
- /**
- * Returns whether a session has been created for the associated request.
- */
- public boolean hasSession ()
- {
- return ( session != null );
- }
-
- /**
- * Returns this context's session, creating one if it doesn't exist.
- */
- public WOSession session ()
- {
- if ( session == null )
- {
- // so far we can't figure out how the direct action handler can avoid creating a session
- throw new RuntimeException( "WOContext.session: Lazy instantiation not yet implemented." );
-/*
- session = application().restoreSessionWithID(
- request.sessionID(), this );
- if ( session == null )
- {
- session = application().createSessionForRequest( request );
- session.setContext( this );
- }
-*/
- }
- return session;
- }
-
- /**
- * Package access only.
- */
- void setSession( WOSession aSession )
- {
- session = aSession;
- }
-
- /**
- * Returns this context's request.
- */
- public WORequest request ()
- {
- return request;
- }
-
- /**
- * Returns this context's response.
- */
- public WOResponse response ()
- {
- return response;
- }
-
- /**
- * Returns the current page.
- */
- public WOComponent page ()
- {
- return (WOComponent) elementStack.get( elementStack.size()-1 );
- }
-
- /**
- * Returns the current component.
- */
- public WOComponent component ()
- {
- Object o;
- Iterator i = elementStack.iterator();
- while ( i.hasNext() )
- {
- o = i.next();
- if ( o instanceof WOComponent ) return (WOComponent) o;
- }
- return null;
- }
-
- /**
- * Returns the current component's parent.
- */
- WOComponent parent ()
- {
- Object o;
- Iterator i = elementStack.iterator();
- if ( i.hasNext() )
- {
- // skip current component
- o = i.next();
- }
- while ( i.hasNext() )
- {
- o = i.next();
- if ( o instanceof WOComponent )
- {
- return (WOComponent) o;
- }
- }
- return null;
- }
-
- /**
- * Pushes an element onto the stack.
- * Package access only.
- */
- void pushElement( WOElement aComponent )
- {
- elementStack.add( 0, aComponent );
- }
-
- /**
- * Pops an element off the stack.
- * Package access only.
- */
- WOElement popElement()
- {
- return (WOElement) elementStack.remove(0);
- }
-
- /**
- * Returns whether the current context is in a form.
- */
- public boolean isInForm ()
- {
- return isInForm;
- }
-
- /**
- * Sets whether the current context is in a WOForm.
- */
- public void setInForm (boolean inForm)
- {
- isInForm = inForm;
- }
-
- /**
- * Appends the specified string to the end of the element id.
- * For example, if the element id is "0.1", sending "Test"
- * changes the element id to "0.1.Test".
- */
- public void appendElementIDComponent (String aString)
- {
- if ( elementID.length() > 0 )
- {
- elementID.append( SEP );
- }
- elementID.append( aString );
- }
-
- /**
- * Appends a zero to the element id to represent the first
- * new child component. For example, if the element id is "0.1",
- * calling this changes the element id to "0.1.0".
- */
- public void appendZeroElementIDComponent ()
- {
- if ( elementID.length() > 0 )
- {
- elementID.append( SEP );
- }
- elementID.append( ZERO );
- }
-
- /**
- * Increments the last component of the element id.
- * For example, if the element id is "0.1", calling this
- * changes the element id to "0.2".
- */
- public void incrementLastElementIDComponent ()
- {
- String last;
- String id = elementID.toString();
- int index = id.lastIndexOf( SEP );
- if ( index == -1 )
- {
- last = id;
- }
- else
- {
- last = id.substring( index + 1 );
- }
-
- deleteLastElementIDComponent();
-
- try
- {
- appendElementIDComponent(
- Integer.toString( Integer.parseInt( last ) + 1 ) );
- }
- catch ( Exception exc )
- {
- System.err.println( "Error parsing id: " + last );
- appendZeroElementIDComponent();
- }
- //System.out.println( "WOContext: " + elementID );
- }
-
- /**
- * Deletes the last component of the element id.
- * For example, if the element id is "0.1", callling this
- * changes the element id to "0".
- */
- public void deleteLastElementIDComponent ()
- {
- int index = elementID.toString().lastIndexOf( SEP );
- if ( index == -1 )
- {
- elementID.setLength( 0 );
- }
- else
- {
- elementID.setLength( index );
- }
- }
-
- /**
- * Deletes all components of the element id.
- * This makes the element id an empty string.
- */
- public void deleteAllElementIDComponents ()
- {
- elementID.setLength( 0 );
- }
-
- /**
- * Returns a URL for the named action with query parameters
- * as specified by the dictionary.
- */
- public String directActionURLForActionNamed (
- String anActionName, Map aQueryDict)
- {
- StringBuffer query = new StringBuffer();
-
- try
- {
- String key;
- Iterator i = aQueryDict.keySet().iterator();
- while ( i.hasNext() )
- {
- key = i.next().toString();
- query.append( URI.encode( key,
- URI.allowed_within_query ) );
- query.append( '=' );
- query.append( URI.encode( aQueryDict.get( key ).toString(),
- URI.allowed_within_query ) );
- if ( i.hasNext() )
- {
- query.append( '&' );
- }
- }
- }
- catch ( IOException exc )
- {
- // report error
- System.err.println(
- "directActionURLForActionNamed: " + anActionName + " : " + aQueryDict );
- System.err.println( exc );
-
- // delete query string
- query = new StringBuffer();
- }
-
- return urlWithRequestHandlerKey(
- WOApplication.directActionRequestHandlerKey(),
- anActionName, query.toString() );
- }
-
- /**
- * Returns the complete URL for the current component action.
- */
- public String componentActionURL ()
- {
- StringBuffer buffer = new StringBuffer();
- buffer.append( request().applicationName() );
- buffer.append( '/' );
- buffer.append( WOApplication.application().componentRequestHandlerKey() );
- buffer.append( '/' );
- buffer.append( page().name() );
- buffer.append( '/' );
- buffer.append( contextID );
- buffer.append( '/' );
- buffer.append( elementID );
- return buffer.toString();
- }
-
- /**
- * Returns a URL relative to the servlet for the specified
- * request handler, action, and query string.
- */
- public String urlWithRequestHandlerKey (
- String aRequestHandlerKey, String aPath, String aQueryString)
- {
- StringBuffer buffer = new StringBuffer();
- buffer.append( request().applicationName() );
- buffer.append( '/' );
- buffer.append( aRequestHandlerKey );
- buffer.append( '/' );
- buffer.append( aPath );
- if ( aQueryString != null && aQueryString.trim().length() > 0 )
- {
- buffer.append( '?' );
- buffer.append( aQueryString );
- }
- return buffer.toString();
- }
-
- /**
- * Returns the complete URL for the specified request handler,
- * path, and query string. isSecure determines the protocol:
- * http or https. port is appended to the protocol, if zero,
- * the port is omitted from the URL.
- */
- public String completeURLWithRequestHandlerKey (
- String aRequestHandlerKey, String aPath, String aQueryString,
- boolean isSecure, int port)
- {
- StringBuffer buffer = new StringBuffer();
-
- if ( isSecure )
- {
- buffer.append( HTTPS );
- }
- else
- {
- buffer.append( HTTP );
- }
-
- buffer.append( request.applicationHost() );
-
- if ( port != 0 && port != 80 )
- {
- buffer.append( ':' );
- buffer.append( Integer.toString( port ) );
- }
-
- buffer.append( urlWithRequestHandlerKey(
- aRequestHandlerKey, aPath, aQueryString ) );
-
- return buffer.toString();
- }
-
- /**
- * Sets whether distribution is enabled.
- */
- public void setDistributionEnabled (boolean distributionEnabled)
- {
- isDistributionEnabled = distributionEnabled;
- }
-
- /**
- * Returns whether distribution is enabled.
- */
- public boolean isDistributionEnabled ()
- {
- return isDistributionEnabled;
- }
-
- /**
- * This method is not included in the WOContext specification.
- * This implementation returns "" since only cookie ids are
- * currently supported.
- */
- String urlSessionPrefix ()
- {
- return EMPTY; // "/" + sessionid;
- }
-
- /**
- * Returns the relative URL for the current page.
- */
- String url ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public String toString()
- {
- return "[WOContext@"+Integer.toHexString(System.identityHashCode(this))
- +":id=" + contextID +":page=" + page + ":component=" + component + ":element=" + elementID + "]";
- }
+
+ private static volatile int contextCounter = 0;
+ private String contextID;
+
+ /**
+ * Default constructor performs necessary initialization. Subclassers should
+ * override the static factory method below.
+ */
+ public WOContext() {
+ contextID = null;
+ elementID = new StringBuffer();
+ elementStack = new LinkedList();
+ }
+
+ /**
+ * Preferred constructor performs necessary initialization. Subclassers should
+ * override this method.
+ */
+ public WOContext(WORequest aRequest) {
+ this();
+ request = aRequest;
+ response = new WOResponse();
+ }
+
+ /**
+ * Simply calls the preferred constructor. Included for compatibility.
+ */
+ public static WOContext contextWithRequest(WORequest aRequest) {
+ String id = Integer.toString(contextCounter++);
+ WOContext result = new WOContext(aRequest);
+ result.contextID = id;
+ return result;
+ }
+
+ /**
+ * Returns the context id.
+ */
+ public String contextID() {
+ return contextID;
+ }
+
+ /**
+ * Returns the sender id, or null if it doesn't exist.
+ */
+ public String senderID() {
+ return request.senderID();
+ }
+
+ /**
+ * Returns the element id, or null if it doesn't exist.
+ */
+ public String elementID() {
+ return elementID.toString();
+ }
+
+ /**
+ * Returns this context's application, or null if it doesn't exist.
+ */
+ public WOApplication application() {
+ return request.application();
+ }
+
+ /**
+ * Returns whether a session has been created for the associated request.
+ */
+ public boolean hasSession() {
+ return (session != null);
+ }
+
+ /**
+ * Returns this context's session, creating one if it doesn't exist.
+ */
+ public WOSession session() {
+ if (session == null) {
+ // so far we can't figure out how the direct action handler can avoid creating a
+ // session
+ throw new RuntimeException("WOContext.session: Lazy instantiation not yet implemented.");
+ /*
+ * session = application().restoreSessionWithID( request.sessionID(), this ); if
+ * ( session == null ) { session = application().createSessionForRequest(
+ * request ); session.setContext( this ); }
+ */
+ }
+ return session;
+ }
+
+ /**
+ * Package access only.
+ */
+ void setSession(WOSession aSession) {
+ session = aSession;
+ }
+
+ /**
+ * Returns this context's request.
+ */
+ public WORequest request() {
+ return request;
+ }
+
+ /**
+ * Returns this context's response.
+ */
+ public WOResponse response() {
+ return response;
+ }
+
+ /**
+ * Returns the current page.
+ */
+ public WOComponent page() {
+ return (WOComponent) elementStack.get(elementStack.size() - 1);
+ }
+
+ /**
+ * Returns the current component.
+ */
+ public WOComponent component() {
+ Object o;
+ Iterator i = elementStack.iterator();
+ while (i.hasNext()) {
+ o = i.next();
+ if (o instanceof WOComponent)
+ return (WOComponent) o;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the current component's parent.
+ */
+ WOComponent parent() {
+ Object o;
+ Iterator i = elementStack.iterator();
+ if (i.hasNext()) {
+ // skip current component
+ o = i.next();
+ }
+ while (i.hasNext()) {
+ o = i.next();
+ if (o instanceof WOComponent) {
+ return (WOComponent) o;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Pushes an element onto the stack. Package access only.
+ */
+ void pushElement(WOElement aComponent) {
+ elementStack.add(0, aComponent);
+ }
+
+ /**
+ * Pops an element off the stack. Package access only.
+ */
+ WOElement popElement() {
+ return (WOElement) elementStack.remove(0);
+ }
+
+ /**
+ * Returns whether the current context is in a form.
+ */
+ public boolean isInForm() {
+ return isInForm;
+ }
+
+ /**
+ * Sets whether the current context is in a WOForm.
+ */
+ public void setInForm(boolean inForm) {
+ isInForm = inForm;
+ }
+
+ /**
+ * Appends the specified string to the end of the element id. For example, if
+ * the element id is "0.1", sending "Test" changes the element id to "0.1.Test".
+ */
+ public void appendElementIDComponent(String aString) {
+ if (elementID.length() > 0) {
+ elementID.append(SEP);
+ }
+ elementID.append(aString);
+ }
+
+ /**
+ * Appends a zero to the element id to represent the first new child component.
+ * For example, if the element id is "0.1", calling this changes the element id
+ * to "0.1.0".
+ */
+ public void appendZeroElementIDComponent() {
+ if (elementID.length() > 0) {
+ elementID.append(SEP);
+ }
+ elementID.append(ZERO);
+ }
+
+ /**
+ * Increments the last component of the element id. For example, if the element
+ * id is "0.1", calling this changes the element id to "0.2".
+ */
+ public void incrementLastElementIDComponent() {
+ String last;
+ String id = elementID.toString();
+ int index = id.lastIndexOf(SEP);
+ if (index == -1) {
+ last = id;
+ } else {
+ last = id.substring(index + 1);
+ }
+
+ deleteLastElementIDComponent();
+
+ try {
+ appendElementIDComponent(Integer.toString(Integer.parseInt(last) + 1));
+ } catch (Exception exc) {
+ System.err.println("Error parsing id: " + last);
+ appendZeroElementIDComponent();
+ }
+ // System.out.println( "WOContext: " + elementID );
+ }
+
+ /**
+ * Deletes the last component of the element id. For example, if the element id
+ * is "0.1", callling this changes the element id to "0".
+ */
+ public void deleteLastElementIDComponent() {
+ int index = elementID.toString().lastIndexOf(SEP);
+ if (index == -1) {
+ elementID.setLength(0);
+ } else {
+ elementID.setLength(index);
+ }
+ }
+
+ /**
+ * Deletes all components of the element id. This makes the element id an empty
+ * string.
+ */
+ public void deleteAllElementIDComponents() {
+ elementID.setLength(0);
+ }
+
+ /**
+ * Returns a URL for the named action with query parameters as specified by the
+ * dictionary.
+ */
+ public String directActionURLForActionNamed(String anActionName, Map aQueryDict) {
+ StringBuffer query = new StringBuffer();
+
+ try {
+ String key;
+ Iterator i = aQueryDict.keySet().iterator();
+ while (i.hasNext()) {
+ key = i.next().toString();
+ query.append(URI.encode(key, URI.allowed_within_query));
+ query.append('=');
+ query.append(URI.encode(aQueryDict.get(key).toString(), URI.allowed_within_query));
+ if (i.hasNext()) {
+ query.append('&');
+ }
+ }
+ } catch (IOException exc) {
+ // report error
+ System.err.println("directActionURLForActionNamed: " + anActionName + " : " + aQueryDict);
+ System.err.println(exc);
+
+ // delete query string
+ query = new StringBuffer();
+ }
+
+ return urlWithRequestHandlerKey(WOApplication.directActionRequestHandlerKey(), anActionName, query.toString());
+ }
+
+ /**
+ * Returns the complete URL for the current component action.
+ */
+ public String componentActionURL() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(request().applicationName());
+ buffer.append('/');
+ buffer.append(WOApplication.application().componentRequestHandlerKey());
+ buffer.append('/');
+ buffer.append(page().name());
+ buffer.append('/');
+ buffer.append(contextID);
+ buffer.append('/');
+ buffer.append(elementID);
+ return buffer.toString();
+ }
+
+ /**
+ * Returns a URL relative to the servlet for the specified request handler,
+ * action, and query string.
+ */
+ public String urlWithRequestHandlerKey(String aRequestHandlerKey, String aPath, String aQueryString) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(request().applicationName());
+ buffer.append('/');
+ buffer.append(aRequestHandlerKey);
+ buffer.append('/');
+ buffer.append(aPath);
+ if (aQueryString != null && aQueryString.trim().length() > 0) {
+ buffer.append('?');
+ buffer.append(aQueryString);
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Returns the complete URL for the specified request handler, path, and query
+ * string. isSecure determines the protocol: http or https. port is appended to
+ * the protocol, if zero, the port is omitted from the URL.
+ */
+ public String completeURLWithRequestHandlerKey(String aRequestHandlerKey, String aPath, String aQueryString,
+ boolean isSecure, int port) {
+ StringBuffer buffer = new StringBuffer();
+
+ if (isSecure) {
+ buffer.append(HTTPS);
+ } else {
+ buffer.append(HTTP);
+ }
+
+ buffer.append(request.applicationHost());
+
+ if (port != 0 && port != 80) {
+ buffer.append(':');
+ buffer.append(Integer.toString(port));
+ }
+
+ buffer.append(urlWithRequestHandlerKey(aRequestHandlerKey, aPath, aQueryString));
+
+ return buffer.toString();
+ }
+
+ /**
+ * Sets whether distribution is enabled.
+ */
+ public void setDistributionEnabled(boolean distributionEnabled) {
+ isDistributionEnabled = distributionEnabled;
+ }
+
+ /**
+ * Returns whether distribution is enabled.
+ */
+ public boolean isDistributionEnabled() {
+ return isDistributionEnabled;
+ }
+
+ /**
+ * This method is not included in the WOContext specification. This
+ * implementation returns "" since only cookie ids are currently supported.
+ */
+ String urlSessionPrefix() {
+ return EMPTY; // "/" + sessionid;
+ }
+
+ /**
+ * Returns the relative URL for the current page.
+ */
+ String url() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public String toString() {
+ return "[WOContext@" + Integer.toHexString(System.identityHashCode(this)) + ":id=" + contextID + ":page=" + page
+ + ":component=" + component + ":element=" + elementID + "]";
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.19 2003/08/07 00:15:15 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.19 2003/08/07 00:15:15 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.18 2003/02/21 16:40:23 mpowers
- * Now reading port and smtp host from system properties.
- * Implemented WOApplication.main.
+ * Revision 1.18 2003/02/21 16:40:23 mpowers Now reading port and smtp host from
+ * system properties. Implemented WOApplication.main.
*
- * Revision 1.17 2003/01/24 20:12:54 mpowers
- * Better parent determination.
+ * Revision 1.17 2003/01/24 20:12:54 mpowers Better parent determination.
*
- * Revision 1.16 2003/01/21 22:27:02 mpowers
- * Corrected context id usage.
+ * Revision 1.16 2003/01/21 22:27:02 mpowers Corrected context id usage.
* Implemented backtracking.
*
- * Revision 1.15 2003/01/17 20:58:19 mpowers
- * Fixed up WOHyperlink.
+ * Revision 1.15 2003/01/17 20:58:19 mpowers Fixed up WOHyperlink.
*
- * Revision 1.14 2003/01/17 20:34:57 mpowers
- * Better handling for components and parents in the context's element stack.
+ * Revision 1.14 2003/01/17 20:34:57 mpowers Better handling for components and
+ * parents in the context's element stack.
*
- * Revision 1.13 2003/01/14 19:48:36 mpowers
- * - fixes to property synchronization
- * - forms now pass takeValuesFromRequest to children
- * - fixes to action invocation
- * - now supporting multipleSubmit in forms
+ * Revision 1.13 2003/01/14 19:48:36 mpowers - fixes to property synchronization
+ * - forms now pass takeValuesFromRequest to children - fixes to action
+ * invocation - now supporting multipleSubmit in forms
*
- * Revision 1.12 2003/01/13 22:24:44 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.12 2003/01/13 22:24:44 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.11 2003/01/10 20:17:41 mpowers
- * Component action urls are now working.
+ * Revision 1.11 2003/01/10 20:17:41 mpowers Component action urls are now
+ * working.
*
- * Revision 1.8 2003/01/09 21:16:48 mpowers
- * Bringing request-response cycle more into conformance.
+ * Revision 1.8 2003/01/09 21:16:48 mpowers Bringing request-response cycle more
+ * into conformance.
*
- * Revision 1.7 2003/01/09 16:13:59 mpowers
- * Implemented WOComponentRequestHandler:
- * Bringing the request-response cycle more into conformance.
+ * Revision 1.7 2003/01/09 16:13:59 mpowers Implemented
+ * WOComponentRequestHandler: Bringing the request-response cycle more into
+ * conformance.
*
- * Revision 1.4 2002/12/20 22:56:33 mpowers
- * Reimplemented the template parsing again.
- * Nested components are now correctly parsed.
- * ElementID numbering is now working.
+ * Revision 1.4 2002/12/20 22:56:33 mpowers Reimplemented the template parsing
+ * again. Nested components are now correctly parsed. ElementID numbering is now
+ * working.
*
- * Revision 1.3 2002/12/18 14:12:38 mpowers
- * Support for differentiated request handlers.
- * Support url generation for WOContext and WORequest.
+ * Revision 1.3 2002/12/18 14:12:38 mpowers Support for differentiated request
+ * handlers. Support url generation for WOContext and WORequest.
*
- * Revision 1.2 2002/12/17 14:57:42 mpowers
- * Minor corrections to WORequests's parsing, and updated javadocs.
+ * Revision 1.2 2002/12/17 14:57:42 mpowers Minor corrections to WORequests's
+ * parsing, and updated javadocs.
*
- * Revision 1.1.1.1 2000/12/21 15:53:04 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:04 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCookie.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCookie.java
index 78427f0..4c5f498 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCookie.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCookie.java
@@ -21,183 +21,159 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDate;
/**
-* A pure java implementation of WOCookie that extends
-* javax.servlet.httpd.Cookie for greater compatibility.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOCookie
- extends javax.servlet.http.Cookie
-{
- /**
- * Default constructor.
- */
- public WOCookie ()
- {
- super( "", "" );
- }
-
- /**
- * Constructs a cookie with the specified name and value.
- */
- public WOCookie( String aName, String aValue )
- {
- super( aName, aValue );
- }
-
- /**
- * Constructs a cookie with the specified name and value.
- * Also sets the path to the current application's path.
- */
- public static WOCookie cookieWithName (String aName, String aValue)
- {
- WOCookie result = new WOCookie( aName, aValue );
- //TODO: Set the path to the current application's path.
- return result;
- }
-
- /**
- * Constructs a cookie with the specified attributes.
- */
- public static WOCookie cookieWithName (String aName, String aValue,
- String aPath, String aDomain, NSDate expirationDate, boolean secure)
- {
- WOCookie result = new WOCookie( aName, aValue );
- result.setPath( aPath );
- result.setDomain( aDomain );
- result.setExpires( expirationDate );
- result.setSecure( secure );
+ * A pure java implementation of WOCookie that extends
+ * javax.servlet.httpd.Cookie for greater compatibility.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOCookie extends javax.servlet.http.Cookie {
+ /**
+ * Default constructor.
+ */
+ public WOCookie() {
+ super("", "");
+ }
+
+ /**
+ * Constructs a cookie with the specified name and value.
+ */
+ public WOCookie(String aName, String aValue) {
+ super(aName, aValue);
+ }
+
+ /**
+ * Constructs a cookie with the specified name and value. Also sets the path to
+ * the current application's path.
+ */
+ public static WOCookie cookieWithName(String aName, String aValue) {
+ WOCookie result = new WOCookie(aName, aValue);
+ // TODO: Set the path to the current application's path.
+ return result;
+ }
+
+ /**
+ * Constructs a cookie with the specified attributes.
+ */
+ public static WOCookie cookieWithName(String aName, String aValue, String aPath, String aDomain,
+ NSDate expirationDate, boolean secure) {
+ WOCookie result = new WOCookie(aName, aValue);
+ result.setPath(aPath);
+ result.setDomain(aDomain);
+ result.setExpires(expirationDate);
+ result.setSecure(secure);
return result;
}
-
- /**
- * Returns the name of the cookie.
- */
- public String name ()
- {
- return this.getName();
- }
-
- /**
- * Sets the name of the cookie.
- */
- public void setName (String aString)
- {
- // super.setName( aString );
- throw new RuntimeException( "Not yet implemented." );
- }
-
- /**
- * Returns the value of the cookie.
- */
- public String value ()
- {
- return this.getValue();
- }
-
- /**
- * Sets the value of the cookie.
- */
- public void setValue (String aString)
- {
- super.setValue( aString );
- }
-
- /**
- * Gets the domain of the cookie.
- */
- public String domain ()
- {
- return this.getDomain();
- }
-
- /**
- * Sets the domain of the cookie.
- */
- public void setDomain (String aString)
- {
- super.setDomain( aString );
- }
-
- /**
- * Gets the path of the cookie.
- */
- public String path ()
- {
- return this.getPath();
- }
-
- /**
- * Sets the path of the cookie.
- */
- public void setPath (String aString)
- {
- super.setPath( aString );
- }
-
- /**
- * Gets the expiration date of the cookie.
- * If in the past, the cookie will persist until browser shutdown.
- */
- public NSDate expires ()
- {
- return new NSDate( this.getMaxAge() );
- }
-
- /**
- * Sets the expiration date of the cookie.
- */
- public void setExpires (NSDate aDate)
- {
- this.setMaxAge( (int) aDate.timeIntervalSinceNow() );
- }
-
- /**
- * Returns whether the cookie will only be sent over a secure protocol.
- */
- public boolean isSecure ()
- {
- return this.getSecure();
- }
-
- /**
- * Sets whether the cookie will only be sent over a secure protocol.
- */
- public void setIsSecure (boolean isSecure)
- {
- this.setSecure( isSecure );
- }
-
- /**
- * Returns the string as it appears in the HTTP header of the response.
- * This would normally be called by WOResponse, but is handled automatically
- * by the servlet implementation.
- */
- public String headerString ()
- {
- new RuntimeException( "Not implemented yet." );
- return null;
- }
+
+ /**
+ * Returns the name of the cookie.
+ */
+ public String name() {
+ return this.getName();
+ }
+
+ /**
+ * Sets the name of the cookie.
+ */
+ public void setName(String aString) {
+ // super.setName( aString );
+ throw new RuntimeException("Not yet implemented.");
+ }
+
+ /**
+ * Returns the value of the cookie.
+ */
+ public String value() {
+ return this.getValue();
+ }
+
+ /**
+ * Sets the value of the cookie.
+ */
+ public void setValue(String aString) {
+ super.setValue(aString);
+ }
+
+ /**
+ * Gets the domain of the cookie.
+ */
+ public String domain() {
+ return this.getDomain();
+ }
+
+ /**
+ * Sets the domain of the cookie.
+ */
+ public void setDomain(String aString) {
+ super.setDomain(aString);
+ }
+
+ /**
+ * Gets the path of the cookie.
+ */
+ public String path() {
+ return this.getPath();
+ }
+
+ /**
+ * Sets the path of the cookie.
+ */
+ public void setPath(String aString) {
+ super.setPath(aString);
+ }
+
+ /**
+ * Gets the expiration date of the cookie. If in the past, the cookie will
+ * persist until browser shutdown.
+ */
+ public NSDate expires() {
+ return new NSDate(this.getMaxAge());
+ }
+
+ /**
+ * Sets the expiration date of the cookie.
+ */
+ public void setExpires(NSDate aDate) {
+ this.setMaxAge((int) aDate.timeIntervalSinceNow());
+ }
+
+ /**
+ * Returns whether the cookie will only be sent over a secure protocol.
+ */
+ public boolean isSecure() {
+ return this.getSecure();
+ }
+
+ /**
+ * Sets whether the cookie will only be sent over a secure protocol.
+ */
+ public void setIsSecure(boolean isSecure) {
+ this.setSecure(isSecure);
+ }
+
+ /**
+ * Returns the string as it appears in the HTTP header of the response. This
+ * would normally be called by WOResponse, but is handled automatically by the
+ * servlet implementation.
+ */
+ public String headerString() {
+ new RuntimeException("Not implemented yet.");
+ return null;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:53:04 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:04 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:50 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:50 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectAction.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectAction.java
index 09d0131..08b591f 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectAction.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectAction.java
@@ -29,289 +29,241 @@ import net.wotonomy.foundation.internal.Introspector;
import net.wotonomy.foundation.internal.ValueConverter;
/**
-* A pure java implementation of WODirectAction.
-* This class provides a number of services to subclasses,
-* including access to the query parameters, the request,
-* the session, and logging and debugging facilities.
-* A new instance of the class is created and then destroyed
-* for every request-response cycle.<br><br>
-*
-* Subclass this to implement direct actions for your
-* application. Subclasses would typically override the
-* constructor to initialize state based on the request,
-* and then provide additional methods that would be invoked
-* based on the value at the end of the URI. <br><br>
-*
-* Example: "http://www/MyApp.woa/MyActions/search" would call
-* the method named "searchAction" on the DirectAction subclass
-* named "MyActions". If the subclass name is omitted, a subclass
-* named "DirectAction" is assumed to exist within the application.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WODirectAction
-{
+ * A pure java implementation of WODirectAction. This class provides a number of
+ * services to subclasses, including access to the query parameters, the
+ * request, the session, and logging and debugging facilities. A new instance of
+ * the class is created and then destroyed for every request-response cycle.<br>
+ * <br>
+ *
+ * Subclass this to implement direct actions for your application. Subclasses
+ * would typically override the constructor to initialize state based on the
+ * request, and then provide additional methods that would be invoked based on
+ * the value at the end of the URI. <br>
+ * <br>
+ *
+ * Example: "http://www/MyApp.woa/MyActions/search" would call the method named
+ * "searchAction" on the DirectAction subclass named "MyActions". If the
+ * subclass name is omitted, a subclass named "DirectAction" is assumed to exist
+ * within the application.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WODirectAction {
private WORequest request;
- WOContext context;
+ WOContext context;
/**
- * Default constructor. This is called implicitly by
- * subclasses in all cases. Package access only.
- */
- WODirectAction ()
- {
-
- }
+ * Default constructor. This is called implicitly by subclasses in all cases.
+ * Package access only.
+ */
+ WODirectAction() {
+
+ }
/**
- * Request constructor. This is the constructor used
- * to create an action in response to a user request.
- * Override to perform any necessary initialization in
- * your subclass.
- */
- public WODirectAction (WORequest aRequest)
- {
- this();
- request = aRequest;
- }
+ * Request constructor. This is the constructor used to create an action in
+ * response to a user request. Override to perform any necessary initialization
+ * in your subclass.
+ */
+ public WODirectAction(WORequest aRequest) {
+ this();
+ request = aRequest;
+ }
- /**
- * Returns the response from the component named "Main".
- */
- public WOActionResults defaultAction()
- {
- return pageWithName("Main").generateResponse();
- }
-
/**
- * Returns the WORequest object for the current request.
- */
- public WORequest request ()
- {
- return request;
- }
+ * Returns the response from the component named "Main".
+ */
+ public WOActionResults defaultAction() {
+ return pageWithName("Main").generateResponse();
+ }
/**
- * Returns the existing session, or null if no session exists.
- */
- public WOSession existingSession ()
- {
- //FIXME: this is incorrect
- HttpSession session = request.servletRequest().getSession();
- if ( session == null ) return null;
- WOSession wosession = new WOSession();
- wosession.setServletSession( session );
- return wosession;
- }
+ * Returns the WORequest object for the current request.
+ */
+ public WORequest request() {
+ return request;
+ }
/**
- * Returns the existing session if it exists. If no session
- * exists, returns a newly created session. Note that if the
- * user client does not support session ids/cookies, this will
- * create a new session with each request.
- */
- public WOSession session ()
- {
- //FIXME: this is incorrect
- WOSession wosession = new WOSession();
- wosession.setServletSession(
- request.servletRequest().getSession( true ) );
- return wosession;
- }
+ * Returns the existing session, or null if no session exists.
+ */
+ public WOSession existingSession() {
+ // FIXME: this is incorrect
+ HttpSession session = request.servletRequest().getSession();
+ if (session == null)
+ return null;
+ WOSession wosession = new WOSession();
+ wosession.setServletSession(session);
+ return wosession;
+ }
/**
- * Returns the named WOComponent.
- */
- public WOComponent pageWithName (String aString)
- {
- return request.application().pageWithName( aString, context );
- }
+ * Returns the existing session if it exists. If no session exists, returns a
+ * newly created session. Note that if the user client does not support session
+ * ids/cookies, this will create a new session with each request.
+ */
+ public WOSession session() {
+ // FIXME: this is incorrect
+ WOSession wosession = new WOSession();
+ wosession.setServletSession(request.servletRequest().getSession(true));
+ return wosession;
+ }
/**
- * Appends "Action" to the specified string and tries to invoke
- * method with that name and no arguments. Returns null if
- * the method does not exist. If anAction is null, "defaultAction"
- * will be assumed.
- */
- public WOActionResults performActionNamed (String anAction)
- {
- if ( anAction == null ) anAction = "default";
- try
- {
- NSSelector sel = new NSSelector( anAction+"Action" );
- return (WOActionResults) sel.invoke( this );
- }
- catch ( NoSuchMethodException exc )
- {
+ * Returns the named WOComponent.
+ */
+ public WOComponent pageWithName(String aString) {
+ return request.application().pageWithName(aString, context);
+ }
+
+ /**
+ * Appends "Action" to the specified string and tries to invoke method with that
+ * name and no arguments. Returns null if the method does not exist. If anAction
+ * is null, "defaultAction" will be assumed.
+ */
+ public WOActionResults performActionNamed(String anAction) {
+ if (anAction == null)
+ anAction = "default";
+ try {
+ NSSelector sel = new NSSelector(anAction + "Action");
+ return (WOActionResults) sel.invoke(this);
+ } catch (NoSuchMethodException exc) {
// returns below
- }
- catch ( InvocationTargetException exc )
- {
+ } catch (InvocationTargetException exc) {
Throwable e = exc.getTargetException();
- exc.printStackTrace();
- throw new RuntimeException( e.toString() );
- }
- catch ( Exception exc )
- {
- exc.printStackTrace();
- throw new RuntimeException( exc.toString() );
+ exc.printStackTrace();
+ throw new RuntimeException(e.toString());
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ throw new RuntimeException(exc.toString());
}
- WOResponse error = new WOResponse();
- error.setStatus( 404 ); // not found
- error.appendContentString(
- "Could not find method named \"" + anAction + "Action\"." );
- return error;
- }
+ WOResponse error = new WOResponse();
+ error.setStatus(404); // not found
+ error.appendContentString("Could not find method named \"" + anAction + "Action\".");
+ return error;
+ }
/**
- * Assigns the arrays of form values for the specified keys
- * to properties on this object with matching names whose type
- * is NSArray or is convertable from a Collection.
- */
- public void takeFormValueArraysForKeyArray (NSArray anArray)
- {
- if ( anArray == null ) return;
-
- Method m;
- Object key;
- Object value;
- java.util.Enumeration e = anArray.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- key = e.nextElement();
- value = request.formValuesForKey( key.toString() );
- try
- {
- // obtain setter method for this class
- m = Introspector.getPropertyWriteMethod(
- this.getClass(), key.toString(),
- new Class[] { Introspector.WILD } );
- if ( m != null )
- {
- // if value isn't null, try to convert it to type
- if ( value != null )
- {
- Class[] paramTypes = m.getParameterTypes();
- if ( ! paramTypes[0].isAssignableFrom(
- value.getClass() ) )
- {
- //TODO: find a constructor whose parameter
- // is assignable from value.getClass()
- // and instantiate it in the place of value.
+ * Assigns the arrays of form values for the specified keys to properties on
+ * this object with matching names whose type is NSArray or is convertable from
+ * a Collection.
+ */
+ public void takeFormValueArraysForKeyArray(NSArray anArray) {
+ if (anArray == null)
+ return;
+
+ Method m;
+ Object key;
+ Object value;
+ java.util.Enumeration e = anArray.objectEnumerator();
+ while (e.hasMoreElements()) {
+ key = e.nextElement();
+ value = request.formValuesForKey(key.toString());
+ try {
+ // obtain setter method for this class
+ m = Introspector.getPropertyWriteMethod(this.getClass(), key.toString(),
+ new Class[] { Introspector.WILD });
+ if (m != null) {
+ // if value isn't null, try to convert it to type
+ if (value != null) {
+ Class[] paramTypes = m.getParameterTypes();
+ if (!paramTypes[0].isAssignableFrom(value.getClass())) {
+ // TODO: find a constructor whose parameter
+ // is assignable from value.getClass()
+ // and instantiate it in the place of value.
}
- }
- // set property to value
- m.invoke( this, new Object[] { value } );
- }
- }
- catch ( Exception exc )
- {
- // show error and continue
- debugString( "WODirectAction.takeFormValuesForKeyArray: " + exc );
- }
+ }
+ // set property to value
+ m.invoke(this, new Object[] { value });
+ }
+ } catch (Exception exc) {
+ // show error and continue
+ debugString("WODirectAction.takeFormValuesForKeyArray: " + exc);
+ }
}
-
- }
+
+ }
/**
- * Assigns the form values for the specified keys to properties
- * on this object with matching names.
- */
- public void takeFormValuesForKeyArray (NSArray anArray)
- {
- if ( anArray == null ) return;
-
- Method m;
- Object key;
- Object value;
- java.util.Enumeration e = anArray.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- key = e.nextElement();
- value = request.formValueForKey( key.toString() );
- try
- {
- // obtain setter method for this class
- m = Introspector.getPropertyWriteMethod(
- this.getClass(), key.toString(),
- new Class[] { Introspector.WILD } );
- if ( m != null )
- {
- // if value isn't null, try to convert it to type
- if ( value != null )
- {
- Class[] paramTypes = m.getParameterTypes();
- Object convertedValue =
- ValueConverter.convertObjectToClass(
- value, paramTypes[0] );
- if ( convertedValue != null )
- {
- value = convertedValue;
- }
- }
- // set property to value
- m.invoke( this, new Object[] { value } );
- }
- }
- catch ( Exception exc )
- {
- // show error and continue
- debugString( "WODirectAction.takeFormValuesForKeyArray: " + exc );
- }
+ * Assigns the form values for the specified keys to properties on this object
+ * with matching names.
+ */
+ public void takeFormValuesForKeyArray(NSArray anArray) {
+ if (anArray == null)
+ return;
+
+ Method m;
+ Object key;
+ Object value;
+ java.util.Enumeration e = anArray.objectEnumerator();
+ while (e.hasMoreElements()) {
+ key = e.nextElement();
+ value = request.formValueForKey(key.toString());
+ try {
+ // obtain setter method for this class
+ m = Introspector.getPropertyWriteMethod(this.getClass(), key.toString(),
+ new Class[] { Introspector.WILD });
+ if (m != null) {
+ // if value isn't null, try to convert it to type
+ if (value != null) {
+ Class[] paramTypes = m.getParameterTypes();
+ Object convertedValue = ValueConverter.convertObjectToClass(value, paramTypes[0]);
+ if (convertedValue != null) {
+ value = convertedValue;
+ }
+ }
+ // set property to value
+ m.invoke(this, new Object[] { value });
+ }
+ } catch (Exception exc) {
+ // show error and continue
+ debugString("WODirectAction.takeFormValuesForKeyArray: " + exc);
+ }
}
-
- }
+
+ }
/**
- * Writes a message to the standard error stream.
- */
- public static void logString (String aString)
- {
- System.err.println( aString );
- }
+ * Writes a message to the standard error stream.
+ */
+ public static void logString(String aString) {
+ System.err.println(aString);
+ }
/**
- * Writes a message to the standard error stream
- * if debugging is activated.
- */
- public static void debugString (String aString)
- {
- // TODO: Check to see if debugging is enabled.
- System.err.println( aString );
- }
+ * Writes a message to the standard error stream if debugging is activated.
+ */
+ public static void debugString(String aString) {
+ // TODO: Check to see if debugging is enabled.
+ System.err.println(aString);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2003/01/13 22:24:51 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.5 2003/01/13 22:24:51 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.4 2003/01/09 21:16:48 mpowers
- * Bringing request-response cycle more into conformance.
+ * Revision 1.4 2003/01/09 21:16:48 mpowers Bringing request-response cycle more
+ * into conformance.
*
- * Revision 1.3 2003/01/07 15:58:11 mpowers
- * Implementing the request-response cycle.
- * WOSession refactored to support distribution.
+ * Revision 1.3 2003/01/07 15:58:11 mpowers Implementing the request-response
+ * cycle. WOSession refactored to support distribution.
*
- * Revision 1.2 2002/12/17 14:57:43 mpowers
- * Minor corrections to WORequests's parsing, and updated javadocs.
+ * Revision 1.2 2002/12/17 14:57:43 mpowers Minor corrections to WORequests's
+ * parsing, and updated javadocs.
*
- * Revision 1.1.1.1 2000/12/21 15:53:18 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:18 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:50 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:50 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectActionRequestHandler.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectActionRequestHandler.java
index eac826b..228f387 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectActionRequestHandler.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectActionRequestHandler.java
@@ -21,201 +21,161 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSArray;
/**
-* An implementation of WORequestHandler that dispatches
-* DirectActions. <br><br>
-*
-* See WODirectAction for the rules for parsing a request.
-* In short, className defaults to "DirectAction", and the
-* action defaults to "default". The action class is expected
-* to have a constructor that takes a WORequest parameter.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WODirectActionRequestHandler
- extends WORequestHandler
-{
- public WOResponse handleRequest (WORequest aRequest)
- {
- WOResponse response = null;
-
- // no concurrent access is allowed to a user's session:
- // a user/browser/machine with multiple requests will have to wait.
- // NOTE: this forces a session creation for any direct action (!)
- synchronized ( aRequest.request.getSession() )
- {
- WOApplication application = aRequest.application();
- WOContext context = WOContext.contextWithRequest( aRequest );
-
- String className = "DirectAction";
- String actionName = "default";
- NSArray path = aRequest.requestHandlerPathArray();
- if ( path.count() > 0 )
- {
- className = path.objectAtIndex( 0 ).toString();
- if ( path.count() > 1 )
- {
- actionName = path.objectAtIndex( path.count() - 1 ).toString();
- }
- if ( path.count() > 2 )
- {
- for ( int i = 1; i < path.count()-1; i++ )
- {
- className = className + "." +
- path.objectAtIndex( i ).toString();
- }
- }
- }
-
- //FIXME: sessions are supposed to be lazily created for direct actions
-
- WOSession session = null;
-
- String sessionID = aRequest.sessionID();
- if ( sessionID != null )
- {
- session = application.restoreSessionWithID( sessionID, context );
- }
-
- if ( session == null )
- {
- session = application.createSessionForRequest( aRequest );
- if ( session == null )
- {
- response = application.handleSessionCreationErrorInContext( context );
- }
- else
- {
- session.setContext( context );
- }
- }
-
- context.setSession( session );
-
- application.awake();
- session.awake();
-
- try
- {
-
- if ( response == null )
- {
- Class c = null;
- c = application.getLocalClass( className );
- if ( ( c == null ) && ( path.count() == 1 ) )
- {
- actionName = className;
- className = "DirectAction";
- c = application.getLocalClass( className );
- }
- if ( c == null )
- {
- throw new RuntimeException(
- "Could not find class named \"" + className
- + "\": " );
- }
- java.lang.reflect.Constructor ctor =
- c.getConstructor( new Class[] { WORequest.class } );
-
- WODirectAction action = (WODirectAction)
- ctor.newInstance( new Object[] { aRequest } );
- action.context = context; //HACK: how else can action call pageWithName?
-
- WOActionResults result = action.performActionNamed( actionName );
- if ( result instanceof WOComponent )
- {
- //HACK: I'm not sure where this should have gone: seems hackish here.
- context.pushElement( (WOComponent) result );
- ((WOComponent)result).ensureAwakeInContext( context );
- //context.popElement();
- }
- response = result.generateResponse(); // calls session.savePage (?)
- if ( result instanceof WOComponent )
- {
- //HACK: I'm not sure where this should have gone: seems hackish here.
- ((WOComponent)result).sleep();
- }
- }
- }
- catch ( NoSuchMethodException exc )
- {
- WOResponse error = new WOResponse();
- exc.printStackTrace();
- error.setStatus( 404 ); // not found
- error.appendContentString(
- "Could not find request constructor for class named \""
- + className + "\": " );
- response = error;
- }
- catch ( Exception exc )
- {
- WOResponse error = new WOResponse();
- error.setStatus( 500 ); // error
- if ( exc.getMessage() != null )
- {
- error.appendContentString( exc.getMessage() );
- exc.printStackTrace();
- }
- else
- {
- error.appendContentString( exc.toString() );
- exc.printStackTrace();
- }
- response = error;
- }
-
- session.sleep();
- session.setContext( null );
- application.saveSessionForContext( context );
- application.sleep();
- }
- return response;
- }
-
+ * An implementation of WORequestHandler that dispatches DirectActions. <br>
+ * <br>
+ *
+ * See WODirectAction for the rules for parsing a request. In short, className
+ * defaults to "DirectAction", and the action defaults to "default". The action
+ * class is expected to have a constructor that takes a WORequest parameter.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WODirectActionRequestHandler extends WORequestHandler {
+ public WOResponse handleRequest(WORequest aRequest) {
+ WOResponse response = null;
+
+ // no concurrent access is allowed to a user's session:
+ // a user/browser/machine with multiple requests will have to wait.
+ // NOTE: this forces a session creation for any direct action (!)
+ synchronized (aRequest.request.getSession()) {
+ WOApplication application = aRequest.application();
+ WOContext context = WOContext.contextWithRequest(aRequest);
+
+ String className = "DirectAction";
+ String actionName = "default";
+ NSArray path = aRequest.requestHandlerPathArray();
+ if (path.count() > 0) {
+ className = path.objectAtIndex(0).toString();
+ if (path.count() > 1) {
+ actionName = path.objectAtIndex(path.count() - 1).toString();
+ }
+ if (path.count() > 2) {
+ for (int i = 1; i < path.count() - 1; i++) {
+ className = className + "." + path.objectAtIndex(i).toString();
+ }
+ }
+ }
+
+ // FIXME: sessions are supposed to be lazily created for direct actions
+
+ WOSession session = null;
+
+ String sessionID = aRequest.sessionID();
+ if (sessionID != null) {
+ session = application.restoreSessionWithID(sessionID, context);
+ }
+
+ if (session == null) {
+ session = application.createSessionForRequest(aRequest);
+ if (session == null) {
+ response = application.handleSessionCreationErrorInContext(context);
+ } else {
+ session.setContext(context);
+ }
+ }
+
+ context.setSession(session);
+
+ application.awake();
+ session.awake();
+
+ try {
+
+ if (response == null) {
+ Class c = null;
+ c = application.getLocalClass(className);
+ if ((c == null) && (path.count() == 1)) {
+ actionName = className;
+ className = "DirectAction";
+ c = application.getLocalClass(className);
+ }
+ if (c == null) {
+ throw new RuntimeException("Could not find class named \"" + className + "\": ");
+ }
+ java.lang.reflect.Constructor ctor = c.getConstructor(new Class[] { WORequest.class });
+
+ WODirectAction action = (WODirectAction) ctor.newInstance(new Object[] { aRequest });
+ action.context = context; // HACK: how else can action call pageWithName?
+
+ WOActionResults result = action.performActionNamed(actionName);
+ if (result instanceof WOComponent) {
+ // HACK: I'm not sure where this should have gone: seems hackish here.
+ context.pushElement((WOComponent) result);
+ ((WOComponent) result).ensureAwakeInContext(context);
+ // context.popElement();
+ }
+ response = result.generateResponse(); // calls session.savePage (?)
+ if (result instanceof WOComponent) {
+ // HACK: I'm not sure where this should have gone: seems hackish here.
+ ((WOComponent) result).sleep();
+ }
+ }
+ } catch (NoSuchMethodException exc) {
+ WOResponse error = new WOResponse();
+ exc.printStackTrace();
+ error.setStatus(404); // not found
+ error.appendContentString("Could not find request constructor for class named \"" + className + "\": ");
+ response = error;
+ } catch (Exception exc) {
+ WOResponse error = new WOResponse();
+ error.setStatus(500); // error
+ if (exc.getMessage() != null) {
+ error.appendContentString(exc.getMessage());
+ exc.printStackTrace();
+ } else {
+ error.appendContentString(exc.toString());
+ exc.printStackTrace();
+ }
+ response = error;
+ }
+
+ session.sleep();
+ session.setContext(null);
+ application.saveSessionForContext(context);
+ application.sleep();
+ }
+ return response;
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.10 2003/03/28 17:26:18 mpowers
- * Implemented package support: Applications can now live in packages.
- * Better support for locating package local classes.
+ * Revision 1.10 2003/03/28 17:26:18 mpowers Implemented package support:
+ * Applications can now live in packages. Better support for locating package
+ * local classes.
*
- * Revision 1.9 2003/01/19 22:33:26 mpowers
- * Fixed problems with classpath and dynamic class loading.
- * Dynamic elements now pass on ensureAwakeInContext.
+ * Revision 1.9 2003/01/19 22:33:26 mpowers Fixed problems with classpath and
+ * dynamic class loading. Dynamic elements now pass on ensureAwakeInContext.
* Parser how handles <standalone/> tags.
*
- * Revision 1.8 2003/01/17 20:34:57 mpowers
- * Better handling for components and parents in the context's element stack.
+ * Revision 1.8 2003/01/17 20:34:57 mpowers Better handling for components and
+ * parents in the context's element stack.
*
- * Revision 1.7 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.7 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.5 2003/01/13 22:25:00 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.5 2003/01/13 22:25:00 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.4 2003/01/09 21:16:49 mpowers
- * Bringing request-response cycle more into conformance.
+ * Revision 1.4 2003/01/09 21:16:49 mpowers Bringing request-response cycle more
+ * into conformance.
*
- * Revision 1.2 2002/12/17 14:57:44 mpowers
- * Minor corrections to WORequests's parsing, and updated javadocs.
+ * Revision 1.2 2002/12/17 14:57:44 mpowers Minor corrections to WORequests's
+ * parsing, and updated javadocs.
*
- * Revision 1.1.1.1 2000/12/21 15:53:19 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:19 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:50 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:50 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java
index bda1dd5..0bdefdf 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java
@@ -49,2407 +49,1950 @@ import net.wotonomy.foundation.internal.Duplicator;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* WODisplayGroup manages a set of objects,
-* allowing them to be sorted, batched, and filtered.
-* WODisplay also acts as a bridge to the wotonomy's
-* control package, including WODisplayGroup and
-* EOEditingContext.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WODisplayGroup extends Observable
- implements EOObserving, EOEditingContext.Editor,
- java.io.Serializable
-{
- /**
- * Notification sent when the display group is about to fetch.
- */
- public static final String DisplayGroupWillFetchNotification
- = "DisplayGroupWillFetchNotification";
-
- private static boolean
- globalDefaultForValidatesChangesImmediately = true;
- private static String
- globalDefaultStringMatchFormat = "caseInsensitiveLike";
- private static String
- globalDefaultStringMatchOperator = "%@*";
-
- protected NSMutableArray allObjects;
- protected NSArray allObjectsProxy;
- protected NSMutableArray displayedObjects;
- protected NSArray displayedObjectsProxy;
- protected NSMutableArray selectedObjects;
- protected NSArray selectedObjectsProxy;
- protected NSMutableArray selectedIndexes;
-
- private String defaultStringMatchOperator;
- private String defaultStringMatchFormat;
-
- private boolean validatesChangesImmediately;
- private Object delegate;
- private EODataSource dataSource;
- private EOQualifier qualifier;
- private NSMutableArray sortOrderings;
- private NSArray sortOrderingsProxy;
-
- private NSArray localKeys;
- private NSDictionary insertedObjectDefaultValues;
- private boolean fetchesOnLoad;
- private boolean selectsFirstObjectAfterFetch;
- private boolean usesOptimisticRefresh;
- private boolean inQueryMode;
-
- // change detection: package access for helper classes
- boolean selectionChanged;
- int updatedObjectIndex;
-
- // batching
- private int batchIndex;
- private int batchSize;
-
- // this property is not in the spec
- private boolean compareByReference = false;
-
- private EOObserving lastGroupObserver;
-
- /**
- * Creates a new display group.
- */
- public WODisplayGroup()
- {
- validatesChangesImmediately =
- globalDefaultForValidatesChangesImmediately();
- defaultStringMatchOperator =
- globalDefaultStringMatchFormat();
- defaultStringMatchFormat =
- globalDefaultStringMatchOperator();
-
- allObjects = new ObservableArray( this );
- allObjectsProxy = NSArray.arrayBackedByList( allObjects );
- displayedObjects = new NSMutableArray();
- displayedObjectsProxy = NSArray.arrayBackedByList( displayedObjects );
- selectedObjects = new NSMutableArray();
- selectedObjectsProxy = NSArray.arrayBackedByList( selectedObjects );
- sortOrderings = new NSMutableArray();
- sortOrderingsProxy = NSArray.arrayBackedByList( sortOrderings );
- selectedIndexes = new NSMutableArray();
-
- delegate = null;
- dataSource = null;
- qualifier = null;
-
- localKeys = new NSArray(); // not implemented
- insertedObjectDefaultValues = new NSDictionary();
- fetchesOnLoad = false; // not implemented
- selectsFirstObjectAfterFetch = false;
- usesOptimisticRefresh = false;
- inQueryMode = false; // not implemented
-
- selectionChanged = false;
- updatedObjectIndex = -1;
-
- batchIndex = 0;
- batchSize = 0;
- }
-
-
-
- // specify optional data source
-
- /**
- * Sets the data source that will be used by
- * this display group.
- */
- public void setDataSource ( EODataSource aDataSource )
- {
- if ( ( dataSource != null )
- && ( dataSource.editingContext() != null ) )
- {
- // un-register for notifications from existing parent store
- NSNotificationCenter.defaultCenter().removeObserver(
- this, null, dataSource.editingContext() );
- dataSource.editingContext().removeEditor( this );
- if ( dataSource.editingContext().messageHandler() == this )
- {
- dataSource.editingContext().setMessageHandler( null );
- }
-
- }
-
- dataSource = aDataSource;
-
- if ( ( dataSource != null )
- && ( dataSource.editingContext() != null ) )
- {
- // register for notifications from parent store
- NSNotificationCenter.defaultCenter().addObserver(
- this, new NSSelector( "objectsInvalidatedInEditingContext",
- new Class[] { NSNotification.class } ),
- null, dataSource.editingContext() );
-
- // add ourselves as editor
- dataSource.editingContext().addEditor( this );
-
- // add ourselves as message handler if no such handler exists
- if ( dataSource.editingContext().messageHandler() == null )
- {
- dataSource.editingContext().setMessageHandler( this );
- }
- }
- }
-
- /**
- * Returns the current data source backing this display group,
- * or null if no dataSource is currently used.
- */
- public EODataSource dataSource()
- {
- return dataSource;
- }
-
- /**
- * Returns the key by which this display group is bound a master
- * display group, or null if this is not a detail display group.
- */
- public String detailKey()
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- return ((PropertyDataSource)dataSource).key();
- }
- return null;
- }
-
- /**
- * Sets the key by which this display group is bound a master
- * display group. Does nothing if this is not a detail display group.
- */
- public void setDetailKey( String aKey )
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- ((PropertyDataSource)dataSource).setKey( aKey );
- }
- }
-
- /**
- * Returns whether the data source is a detail data source,
- * suggesting that this is a detail display group.
- */
- public boolean hasDetailDataSource()
- {
- return ( dataSource instanceof PropertyDataSource );
- }
-
- /**
- * Returns the selected object in the master display group,
- * or null if this is not a detail display group.
- */
- public Object masterObject()
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- return ((PropertyDataSource)dataSource).source();
- }
- return null;
- }
-
- /**
- * Sets the master object in the detail data source.
- * Does nothing if there is no detail data source.
- */
- public void setMasterObject( Object anObject )
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- ((PropertyDataSource)dataSource).setSource( anObject );
- }
- }
-
- // specify optional delegate
-
- /**
- * Sets the display group delegate that
- * will be used by this display group.
- */
- public void setDelegate ( Object aDelegate )
- {
- delegate = aDelegate;
- }
-
- /**
- * Returns the current delegate for this display group,
- * or null if no delegate is currently set.
- */
- public Object delegate()
- {
- return delegate;
- }
-
-
-
- // display group configuration
-
- /**
- * Returns the current string matching format.
- * If not set, defaults to "%@*".
- */
- public String defaultStringMatchFormat()
- {
- return defaultStringMatchFormat;
- }
-
- /**
- * Returns the current string matching operator.
- * If not set, defaults to "caseInsensitiveLike".
- */
- public String defaultStringMatchOperator()
- {
- return defaultStringMatchOperator;
- }
-
- /**
- * Sets the display group and associations to edit a
- * "query by example" query object. This method is
- * used for target/action connections.
- */
- public void enterQueryMode ( Object aSender )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether this display group should immediate
- * fetch when loaded.
- */
- public boolean fetchesOnLoad()
- {
- return fetchesOnLoad;
- }
-
- /**
- * Returns whether this display group is in "query by
- * example" mode.
- */
- public boolean inQueryMode()
- {
- return inQueryMode;
- }
-
- /**
- * Returns a Map of default values that are applied
- * to new objects that are inserted into the list.
- */
- public NSDictionary insertedObjectDefaultValues()
- {
- return insertedObjectDefaultValues;
- }
-
- /**
- * Returns the keys that were declared when read from
- * an external resource file.
- */
- public NSArray localKeys()
- {
- return localKeys;
- }
-
- /**
- * Sets whether this display group will select the
- * first object in the list after a fetch.
- */
- public boolean selectsFirstObjectAfterFetch()
- {
- return selectsFirstObjectAfterFetch;
- }
-
- /**
- * Sets the default string matching format that
- * will be used by this display group.
- */
- public void setDefaultStringMatchFormat ( String aFormat )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the default string matching operator that
- * will be used by this display group.
- */
- public void setDefaultStringMatchOperator ( String anOperator )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets whether this display group will fetch objects
- * from its data source on load.
- */
- public void setFetchesOnLoad ( boolean willFetch )
- {
- fetchesOnLoad = willFetch;
- }
-
- /**
- * Sets whether this display group is in "query by example"
- * mode. If true, all associations will bind to a special
- * "example" object.
- */
- public void setInQueryMode ( boolean isInQueryMode )
- {
- inQueryMode = isInQueryMode;
- }
-
- /**
- * Sets the mapping that contains the values that will
- * be applied to new objects inserted into the display group.
- */
- public void setInsertedObjectDefaultValues ( Map aMap )
- {
- insertedObjectDefaultValues = new NSDictionary( aMap );
- }
-
- /**
- * Sets the keys that are declared when instantiated from
- * an external resource file.
- */
- public void setLocalKeys ( List aKeyList )
- {
- localKeys = new NSArray( (Collection) aKeyList );
- }
-
- /**
- * Sets whether the first object in the list will be
- * selected after a fetch.
- */
- public void setSelectsFirstObjectAfterFetch (
- boolean selectsFirst )
- {
- selectsFirstObjectAfterFetch = selectsFirst;
- }
-
- /**
- * Sets the order of the keys by which this display group
- * will be ordered after a fetch or after a call to
- * updateDisplayedObjects(). The elements in the display
- * group will be sorted first by the first key, within
- * the first key, by the second key, and so on.
- */
- public void setSortOrderings ( List aList )
- {
- sortOrderings.removeAllObjects();
-
- Object o;
- Iterator it = aList.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- // handle the convenience of specifying just a key
- if ( ! ( o instanceof EOSortOrdering ) )
- {
- o = new EOSortOrdering(
- o.toString(), EOSortOrdering.CompareAscending );
- }
- sortOrderings.add( o );
- }
- }
-
- /**
- * Sets whether only changed objects are refreshed (optimistic),
- * or whether all objects are refreshed (pessimistic, default).
- * By default, when the display group receives notification that
- * one of its objects has changed, updateDisplayedObjects is called.
- */
- public void setUsesOptimisticRefresh ( boolean isOptimistic )
- {
- usesOptimisticRefresh = isOptimistic;
- }
-
- /**
- * Sets whether changes made by associations are validated
- * immediately, or when changes are saved.
- */
- public void setValidatesChangesImmediately (
- boolean validatesImmediately )
- {
- validatesChangesImmediately = validatesImmediately;
- }
-
- /**
- * Returns a read-only List of sort orderings for this display group.
- */
- public NSArray sortOrderings()
- {
- return sortOrderingsProxy;
- }
-
- /**
- * Returns whether this display group refreshes only
- * the changed objects or all objects on refresh.
- */
- public boolean usesOptimisticRefresh()
- {
- return usesOptimisticRefresh;
- }
-
- /**
- * Returns whether this display group validates changes
- * immediately. Otherwise, validation should occur when
- * changes are saved. Default is the global default,
- * which is initially true.
- */
- public boolean validatesChangesImmediately()
- {
- return validatesChangesImmediately;
- }
-
-
- // qualification
-
- /**
- * Returns a qualifier that will be applied all the objects
- * in this display group to determine which objects will
- * be displayed.
- */
- public EOQualifier qualifier()
- {
- return qualifier;
- }
-
- /**
- * Returns a new qualifier built from the three query
- * value maps: greater than, equal to, and less than.
- */
- public EOQualifier qualifierFromQueryValues()
- {
- //TODO: assemble qualifier from query values
-
- return new EOQualifier()
- {
- // use inner class until we actually implement one
- public EOQualifier qualifierWithBindings(
- Map aMap,
- boolean requireAll )
- {
- return null;
- }
- public Throwable
- validateKeysWithRootClassDescription( Class aClass )
- {
- return null;
- }
- public boolean evaluateWithObject(Object o)
- {
- return false;
- }
- };
- }
-
- /**
- * Calls qualifierFromQueryValues(), applies the result
- * to the data source, and calls fetch().
- */
- public void qualifyDataSource()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Calls qualifierFromQueryValues(), sets the qualifier
- * with setQualifier(), and calls updateDisplayedObjects().
- */
- public void qualifyDisplayGroup()
- {
- setQualifier( qualifierFromQueryValues() );
- updateDisplayedObjects();
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values.
- */
- public NSDictionary queryBindingValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values.
- */
- public NSMutableDictionary queryBindings()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values for a matching query.
- */
- public NSMutableDictionary queryMatch()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values for a minimum value query.
- */
- public NSMutableDictionary queryMin()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values for a maximum value query.
- */
- public NSMutableDictionary queryMax()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to operator values.
- */
- public NSMutableDictionary queryOperator()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a list containing all supported qualifier operators.
- */
- public NSArray allQualifierOperators()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to operator values.
- */
- public NSDictionary queryOperatorValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the qualifier that will be used by
- * updateDisplayedObjects() to filter displayed objects.
- */
- public void setQualifier ( EOQualifier aQualifier )
- {
- qualifier = aQualifier;
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to binding values.
- */
- public void setQueryBindingValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to operator values.
- */
- public void setQueryOperatorValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
-
-
- // qualifier query values
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for equality.
- */
- public NSDictionary equalToQueryValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for greater value.
- */
- public NSDictionary greaterThanQueryValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for lesser value.
- */
- public NSDictionary lessThanQueryValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the Map that contains the mappings of keys
- * to query values that will be used to test for equality.
- */
- public void setEqualToQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to query values that will be used to test for greater value.
- */
- public void setGreaterThanQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to query values that will be used to test for lesser value.
- */
- public void setLessThanQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Deprecated: returns true.
- */
- public boolean endEditing()
- {
- return true;
- }
-
-
- // object management
-
- /**
- * Returns a read-only List containing all objects managed by the display group.
- * This includes those objects not visible due to disqualification.
- */
- public NSArray allObjects()
- { //System.out.println( "avoided allocation: allObjects" );
- return allObjectsProxy;
- }
-
- /**
- * Returns the total number of batches held by this display group.
- */
- public int batchCount()
- {
- if ( batchSize < 1 ) return 1;
- int count = displayedObjects.count();
- if ( count == 0 ) return 1;
- return ((count-1) / batchSize) + 1;
- }
-
- /**
- * Returns the index of the currently displayed batch.
- */
- public int currentBatchIndex()
- {
- return batchIndex;
- }
-
- /**
- * Sets the index of the currently displayed batch.
- */
- public void setCurrentBatchIndex( int aBatchIndex )
- {
- batchIndex = aBatchIndex;
- updateDisplayedObjects();
- }
-
- /**
- * Sets the displayed objects to the batch containing
- * the first selected object, and updates the current
- * batch index, and returns null to force a page reload.
- * Displays the first batch is there is no selection.
- */
- public Object displayBatchContainingSelectedObject()
- {
- if ( batchSize < 1 ) return null;
- NSArray indexes = selectionIndexes();
- if ( indexes.count() > 0 )
- {
- batchIndex =
- ((Number)indexes.objectAtIndex( 0 )).intValue() / batchSize;
- }
- else
- {
- batchIndex = 0;
- }
- updateDisplayedObjects();
- return null;
- }
-
- /**
- * Sets the displayed objects to the next batch
- * and updates the current batch index, and returns null
- * to force a page reload. If there is no next batch
- * the first batch is displayed.
- */
- public Object displayNextBatch()
- {
- batchIndex = (batchIndex + 1) % batchCount();
- updateDisplayedObjects();
- return null;
- }
-
- /**
- * Sets the displayed objects to the next batch
- * and updates the current batch index, and returns null
- * to force a page reload. If there is no previous
- * batch, the last batch is displayed.
- */
- public Object displayPreviousBatch()
- {
- batchIndex--;
- if ( batchIndex < 0 ) batchIndex = batchCount() - 1;
- updateDisplayedObjects();
- return null;
- }
-
- /**
- * Returns whether the displayed objects have been batched.
- */
- public boolean hasMultipleBatches()
- {
- return batchCount() > 1;
- }
-
- /**
- * Returns the one-based index within the displayed objects list
- * of the first displayed object in the current batch.
- */
- public int indexOfFirstDisplayedObject()
- {
- if ( batchSize < 1 ) return 1;
- return batchIndex * batchSize + 1;
- }
-
- /**
- * Returns the one-based index within the displayed objects list
- * of the first last object in the current batch.
- */
- public int indexOfLastDisplayedObject()
- {
- if ( batchSize < 1 ) return displayedObjects.count();
- return Math.min(
- ((batchIndex+1) * batchSize),
- displayedObjects.count() );
- }
-
- /**
- * Returns the number of objects per batch.
- */
- public int numberOfObjectsPerBatch()
- {
- return batchSize;
- }
-
- /**
- * Returns the number of objects per batch.
- */
- public void setNumberOfObjectsPerBatch( int aSize )
- {
- batchSize = aSize;
- updateDisplayedObjects();
- }
-
- /**
- * Clears the current selection.
- * @return True is the selection was cleared,
- * False if the selection could not be cleared
- * @see #setSelectionIndexes
- */
- public boolean clearSelection()
- {
- Object result = notifyDelegate(
- "displayGroupShouldChangeSelection",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, new NSArray( selectedObjects ) } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return false;
- }
-
- selectionChanged = true;
- willChange();
-
- selectedObjects.removeAllObjects();
- selectedIndexes.removeAllObjects();
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
-
- return true;
- }
-
- /**
- * Convenience for binding to a component action:
- * calls deleteSelection() and then displayBatchContainingSelectedObject()
- * and returns null, which is a suitable result from a component action.
- */
- public Object delete()
- {
- deleteSelection();
- displayBatchContainingSelectedObject();
- return null;
- }
-
- /**
- * Deletes the object at the specified index,
- * notifying the delegate before and after the operation,
- * and then updating the selection if needed.
- * @return True if delete was successful, false if the
- * object was not deleted.
- */
- public boolean deleteObjectAtIndex ( int anIndex )
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
-
- Object result = notifyDelegate(
- "displayGroupShouldDeleteObject",
- new Class[] { WODisplayGroup.class, Object.class },
- new Object[] { this, target } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return false;
- }
-
- deleteObjectAtIndexNoNotify( anIndex );
-
- if ( dataSource != null )
- {
- dataSource.deleteObject( target );
- }
-
- notifyDelegate(
- "displayGroupDidDeleteObject",
- new Class[] { WODisplayGroup.class, Object.class },
- new Object[] { this, target } );
-
- return true;
- }
-
- private void deleteObjectAtIndexNoNotify ( int anIndex )
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
-
- int i;
-
- // remove from selected objects if necessary
- i = indexOf( selectedObjects, target );
- if ( i != NSArray.NotFound )
- {
- selectionChanged = true;
- willChange(); // notify before removing
- selectedObjects.removeObjectAtIndex( i );
- selectedIndexes.remove( new Integer( i ) ); // comps by value
- }
- else // notify - no selection change needed
- {
- willChange();
- }
-
- // remove from all objects
- i = indexOf( allObjects, target );
- if ( i != NSArray.NotFound )
- {
- allObjects.removeObjectAtIndex( i );
- }
- else // otherwise should never happen
- {
+ * WODisplayGroup manages a set of objects, allowing them to be sorted, batched,
+ * and filtered. WODisplay also acts as a bridge to the wotonomy's control
+ * package, including WODisplayGroup and EOEditingContext.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WODisplayGroup extends Observable implements EOObserving, EOEditingContext.Editor, java.io.Serializable {
+ /**
+ * Notification sent when the display group is about to fetch.
+ */
+ public static final String DisplayGroupWillFetchNotification = "DisplayGroupWillFetchNotification";
+
+ private static boolean globalDefaultForValidatesChangesImmediately = true;
+ private static String globalDefaultStringMatchFormat = "caseInsensitiveLike";
+ private static String globalDefaultStringMatchOperator = "%@*";
+
+ protected NSMutableArray allObjects;
+ protected NSArray allObjectsProxy;
+ protected NSMutableArray displayedObjects;
+ protected NSArray displayedObjectsProxy;
+ protected NSMutableArray selectedObjects;
+ protected NSArray selectedObjectsProxy;
+ protected NSMutableArray selectedIndexes;
+
+ private String defaultStringMatchOperator;
+ private String defaultStringMatchFormat;
+
+ private boolean validatesChangesImmediately;
+ private Object delegate;
+ private EODataSource dataSource;
+ private EOQualifier qualifier;
+ private NSMutableArray sortOrderings;
+ private NSArray sortOrderingsProxy;
+
+ private NSArray localKeys;
+ private NSDictionary insertedObjectDefaultValues;
+ private boolean fetchesOnLoad;
+ private boolean selectsFirstObjectAfterFetch;
+ private boolean usesOptimisticRefresh;
+ private boolean inQueryMode;
+
+ // change detection: package access for helper classes
+ boolean selectionChanged;
+ int updatedObjectIndex;
+
+ // batching
+ private int batchIndex;
+ private int batchSize;
+
+ // this property is not in the spec
+ private boolean compareByReference = false;
+
+ private EOObserving lastGroupObserver;
+
+ /**
+ * Creates a new display group.
+ */
+ public WODisplayGroup() {
+ validatesChangesImmediately = globalDefaultForValidatesChangesImmediately();
+ defaultStringMatchOperator = globalDefaultStringMatchFormat();
+ defaultStringMatchFormat = globalDefaultStringMatchOperator();
+
+ allObjects = new ObservableArray(this);
+ allObjectsProxy = NSArray.arrayBackedByList(allObjects);
+ displayedObjects = new NSMutableArray();
+ displayedObjectsProxy = NSArray.arrayBackedByList(displayedObjects);
+ selectedObjects = new NSMutableArray();
+ selectedObjectsProxy = NSArray.arrayBackedByList(selectedObjects);
+ sortOrderings = new NSMutableArray();
+ sortOrderingsProxy = NSArray.arrayBackedByList(sortOrderings);
+ selectedIndexes = new NSMutableArray();
+
+ delegate = null;
+ dataSource = null;
+ qualifier = null;
+
+ localKeys = new NSArray(); // not implemented
+ insertedObjectDefaultValues = new NSDictionary();
+ fetchesOnLoad = false; // not implemented
+ selectsFirstObjectAfterFetch = false;
+ usesOptimisticRefresh = false;
+ inQueryMode = false; // not implemented
+
+ selectionChanged = false;
+ updatedObjectIndex = -1;
+
+ batchIndex = 0;
+ batchSize = 0;
+ }
+
+ // specify optional data source
+
+ /**
+ * Sets the data source that will be used by this display group.
+ */
+ public void setDataSource(EODataSource aDataSource) {
+ if ((dataSource != null) && (dataSource.editingContext() != null)) {
+ // un-register for notifications from existing parent store
+ NSNotificationCenter.defaultCenter().removeObserver(this, null, dataSource.editingContext());
+ dataSource.editingContext().removeEditor(this);
+ if (dataSource.editingContext().messageHandler() == this) {
+ dataSource.editingContext().setMessageHandler(null);
+ }
+
+ }
+
+ dataSource = aDataSource;
+
+ if ((dataSource != null) && (dataSource.editingContext() != null)) {
+ // register for notifications from parent store
+ NSNotificationCenter.defaultCenter().addObserver(this,
+ new NSSelector("objectsInvalidatedInEditingContext", new Class[] { NSNotification.class }), null,
+ dataSource.editingContext());
+
+ // add ourselves as editor
+ dataSource.editingContext().addEditor(this);
+
+ // add ourselves as message handler if no such handler exists
+ if (dataSource.editingContext().messageHandler() == null) {
+ dataSource.editingContext().setMessageHandler(this);
+ }
+ }
+ }
+
+ /**
+ * Returns the current data source backing this display group, or null if no
+ * dataSource is currently used.
+ */
+ public EODataSource dataSource() {
+ return dataSource;
+ }
+
+ /**
+ * Returns the key by which this display group is bound a master display group,
+ * or null if this is not a detail display group.
+ */
+ public String detailKey() {
+ if (dataSource instanceof PropertyDataSource) {
+ return ((PropertyDataSource) dataSource).key();
+ }
+ return null;
+ }
+
+ /**
+ * Sets the key by which this display group is bound a master display group.
+ * Does nothing if this is not a detail display group.
+ */
+ public void setDetailKey(String aKey) {
+ if (dataSource instanceof PropertyDataSource) {
+ ((PropertyDataSource) dataSource).setKey(aKey);
+ }
+ }
+
+ /**
+ * Returns whether the data source is a detail data source, suggesting that this
+ * is a detail display group.
+ */
+ public boolean hasDetailDataSource() {
+ return (dataSource instanceof PropertyDataSource);
+ }
+
+ /**
+ * Returns the selected object in the master display group, or null if this is
+ * not a detail display group.
+ */
+ public Object masterObject() {
+ if (dataSource instanceof PropertyDataSource) {
+ return ((PropertyDataSource) dataSource).source();
+ }
+ return null;
+ }
+
+ /**
+ * Sets the master object in the detail data source. Does nothing if there is no
+ * detail data source.
+ */
+ public void setMasterObject(Object anObject) {
+ if (dataSource instanceof PropertyDataSource) {
+ ((PropertyDataSource) dataSource).setSource(anObject);
+ }
+ }
+
+ // specify optional delegate
+
+ /**
+ * Sets the display group delegate that will be used by this display group.
+ */
+ public void setDelegate(Object aDelegate) {
+ delegate = aDelegate;
+ }
+
+ /**
+ * Returns the current delegate for this display group, or null if no delegate
+ * is currently set.
+ */
+ public Object delegate() {
+ return delegate;
+ }
+
+ // display group configuration
+
+ /**
+ * Returns the current string matching format. If not set, defaults to "%@*".
+ */
+ public String defaultStringMatchFormat() {
+ return defaultStringMatchFormat;
+ }
+
+ /**
+ * Returns the current string matching operator. If not set, defaults to
+ * "caseInsensitiveLike".
+ */
+ public String defaultStringMatchOperator() {
+ return defaultStringMatchOperator;
+ }
+
+ /**
+ * Sets the display group and associations to edit a "query by example" query
+ * object. This method is used for target/action connections.
+ */
+ public void enterQueryMode(Object aSender) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether this display group should immediate fetch when loaded.
+ */
+ public boolean fetchesOnLoad() {
+ return fetchesOnLoad;
+ }
+
+ /**
+ * Returns whether this display group is in "query by example" mode.
+ */
+ public boolean inQueryMode() {
+ return inQueryMode;
+ }
+
+ /**
+ * Returns a Map of default values that are applied to new objects that are
+ * inserted into the list.
+ */
+ public NSDictionary insertedObjectDefaultValues() {
+ return insertedObjectDefaultValues;
+ }
+
+ /**
+ * Returns the keys that were declared when read from an external resource file.
+ */
+ public NSArray localKeys() {
+ return localKeys;
+ }
+
+ /**
+ * Sets whether this display group will select the first object in the list
+ * after a fetch.
+ */
+ public boolean selectsFirstObjectAfterFetch() {
+ return selectsFirstObjectAfterFetch;
+ }
+
+ /**
+ * Sets the default string matching format that will be used by this display
+ * group.
+ */
+ public void setDefaultStringMatchFormat(String aFormat) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the default string matching operator that will be used by this display
+ * group.
+ */
+ public void setDefaultStringMatchOperator(String anOperator) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets whether this display group will fetch objects from its data source on
+ * load.
+ */
+ public void setFetchesOnLoad(boolean willFetch) {
+ fetchesOnLoad = willFetch;
+ }
+
+ /**
+ * Sets whether this display group is in "query by example" mode. If true, all
+ * associations will bind to a special "example" object.
+ */
+ public void setInQueryMode(boolean isInQueryMode) {
+ inQueryMode = isInQueryMode;
+ }
+
+ /**
+ * Sets the mapping that contains the values that will be applied to new objects
+ * inserted into the display group.
+ */
+ public void setInsertedObjectDefaultValues(Map aMap) {
+ insertedObjectDefaultValues = new NSDictionary(aMap);
+ }
+
+ /**
+ * Sets the keys that are declared when instantiated from an external resource
+ * file.
+ */
+ public void setLocalKeys(List aKeyList) {
+ localKeys = new NSArray((Collection) aKeyList);
+ }
+
+ /**
+ * Sets whether the first object in the list will be selected after a fetch.
+ */
+ public void setSelectsFirstObjectAfterFetch(boolean selectsFirst) {
+ selectsFirstObjectAfterFetch = selectsFirst;
+ }
+
+ /**
+ * Sets the order of the keys by which this display group will be ordered after
+ * a fetch or after a call to updateDisplayedObjects(). The elements in the
+ * display group will be sorted first by the first key, within the first key, by
+ * the second key, and so on.
+ */
+ public void setSortOrderings(List aList) {
+ sortOrderings.removeAllObjects();
+
+ Object o;
+ Iterator it = aList.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ // handle the convenience of specifying just a key
+ if (!(o instanceof EOSortOrdering)) {
+ o = new EOSortOrdering(o.toString(), EOSortOrdering.CompareAscending);
+ }
+ sortOrderings.add(o);
+ }
+ }
+
+ /**
+ * Sets whether only changed objects are refreshed (optimistic), or whether all
+ * objects are refreshed (pessimistic, default). By default, when the display
+ * group receives notification that one of its objects has changed,
+ * updateDisplayedObjects is called.
+ */
+ public void setUsesOptimisticRefresh(boolean isOptimistic) {
+ usesOptimisticRefresh = isOptimistic;
+ }
+
+ /**
+ * Sets whether changes made by associations are validated immediately, or when
+ * changes are saved.
+ */
+ public void setValidatesChangesImmediately(boolean validatesImmediately) {
+ validatesChangesImmediately = validatesImmediately;
+ }
+
+ /**
+ * Returns a read-only List of sort orderings for this display group.
+ */
+ public NSArray sortOrderings() {
+ return sortOrderingsProxy;
+ }
+
+ /**
+ * Returns whether this display group refreshes only the changed objects or all
+ * objects on refresh.
+ */
+ public boolean usesOptimisticRefresh() {
+ return usesOptimisticRefresh;
+ }
+
+ /**
+ * Returns whether this display group validates changes immediately. Otherwise,
+ * validation should occur when changes are saved. Default is the global
+ * default, which is initially true.
+ */
+ public boolean validatesChangesImmediately() {
+ return validatesChangesImmediately;
+ }
+
+ // qualification
+
+ /**
+ * Returns a qualifier that will be applied all the objects in this display
+ * group to determine which objects will be displayed.
+ */
+ public EOQualifier qualifier() {
+ return qualifier;
+ }
+
+ /**
+ * Returns a new qualifier built from the three query value maps: greater than,
+ * equal to, and less than.
+ */
+ public EOQualifier qualifierFromQueryValues() {
+ // TODO: assemble qualifier from query values
+
+ return new EOQualifier() {
+ // use inner class until we actually implement one
+ public EOQualifier qualifierWithBindings(Map aMap, boolean requireAll) {
+ return null;
+ }
+
+ public Throwable validateKeysWithRootClassDescription(Class aClass) {
+ return null;
+ }
+
+ public boolean evaluateWithObject(Object o) {
+ return false;
+ }
+ };
+ }
+
+ /**
+ * Calls qualifierFromQueryValues(), applies the result to the data source, and
+ * calls fetch().
+ */
+ public void qualifyDataSource() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Calls qualifierFromQueryValues(), sets the qualifier with setQualifier(), and
+ * calls updateDisplayedObjects().
+ */
+ public void qualifyDisplayGroup() {
+ setQualifier(qualifierFromQueryValues());
+ updateDisplayedObjects();
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values.
+ */
+ public NSDictionary queryBindingValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values.
+ */
+ public NSMutableDictionary queryBindings() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values for a
+ * matching query.
+ */
+ public NSMutableDictionary queryMatch() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values for a
+ * minimum value query.
+ */
+ public NSMutableDictionary queryMin() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values for a
+ * maximum value query.
+ */
+ public NSMutableDictionary queryMax() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to operator values.
+ */
+ public NSMutableDictionary queryOperator() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a list containing all supported qualifier operators.
+ */
+ public NSArray allQualifierOperators() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to operator values.
+ */
+ public NSDictionary queryOperatorValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the qualifier that will be used by updateDisplayedObjects() to filter
+ * displayed objects.
+ */
+ public void setQualifier(EOQualifier aQualifier) {
+ qualifier = aQualifier;
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to binding values.
+ */
+ public void setQueryBindingValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to operator values.
+ */
+ public void setQueryOperatorValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ // qualifier query values
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for equality.
+ */
+ public NSDictionary equalToQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for greater value.
+ */
+ public NSDictionary greaterThanQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for lesser value.
+ */
+ public NSDictionary lessThanQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the Map that contains the mappings of keys to query values that will be
+ * used to test for equality.
+ */
+ public void setEqualToQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to query values that will
+ * be used to test for greater value.
+ */
+ public void setGreaterThanQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to query values that will
+ * be used to test for lesser value.
+ */
+ public void setLessThanQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Deprecated: returns true.
+ */
+ public boolean endEditing() {
+ return true;
+ }
+
+ // object management
+
+ /**
+ * Returns a read-only List containing all objects managed by the display group.
+ * This includes those objects not visible due to disqualification.
+ */
+ public NSArray allObjects() { // System.out.println( "avoided allocation: allObjects" );
+ return allObjectsProxy;
+ }
+
+ /**
+ * Returns the total number of batches held by this display group.
+ */
+ public int batchCount() {
+ if (batchSize < 1)
+ return 1;
+ int count = displayedObjects.count();
+ if (count == 0)
+ return 1;
+ return ((count - 1) / batchSize) + 1;
+ }
+
+ /**
+ * Returns the index of the currently displayed batch.
+ */
+ public int currentBatchIndex() {
+ return batchIndex;
+ }
+
+ /**
+ * Sets the index of the currently displayed batch.
+ */
+ public void setCurrentBatchIndex(int aBatchIndex) {
+ batchIndex = aBatchIndex;
+ updateDisplayedObjects();
+ }
+
+ /**
+ * Sets the displayed objects to the batch containing the first selected object,
+ * and updates the current batch index, and returns null to force a page reload.
+ * Displays the first batch is there is no selection.
+ */
+ public Object displayBatchContainingSelectedObject() {
+ if (batchSize < 1)
+ return null;
+ NSArray indexes = selectionIndexes();
+ if (indexes.count() > 0) {
+ batchIndex = ((Number) indexes.objectAtIndex(0)).intValue() / batchSize;
+ } else {
+ batchIndex = 0;
+ }
+ updateDisplayedObjects();
+ return null;
+ }
+
+ /**
+ * Sets the displayed objects to the next batch and updates the current batch
+ * index, and returns null to force a page reload. If there is no next batch the
+ * first batch is displayed.
+ */
+ public Object displayNextBatch() {
+ batchIndex = (batchIndex + 1) % batchCount();
+ updateDisplayedObjects();
+ return null;
+ }
+
+ /**
+ * Sets the displayed objects to the next batch and updates the current batch
+ * index, and returns null to force a page reload. If there is no previous
+ * batch, the last batch is displayed.
+ */
+ public Object displayPreviousBatch() {
+ batchIndex--;
+ if (batchIndex < 0)
+ batchIndex = batchCount() - 1;
+ updateDisplayedObjects();
+ return null;
+ }
+
+ /**
+ * Returns whether the displayed objects have been batched.
+ */
+ public boolean hasMultipleBatches() {
+ return batchCount() > 1;
+ }
+
+ /**
+ * Returns the one-based index within the displayed objects list of the first
+ * displayed object in the current batch.
+ */
+ public int indexOfFirstDisplayedObject() {
+ if (batchSize < 1)
+ return 1;
+ return batchIndex * batchSize + 1;
+ }
+
+ /**
+ * Returns the one-based index within the displayed objects list of the first
+ * last object in the current batch.
+ */
+ public int indexOfLastDisplayedObject() {
+ if (batchSize < 1)
+ return displayedObjects.count();
+ return Math.min(((batchIndex + 1) * batchSize), displayedObjects.count());
+ }
+
+ /**
+ * Returns the number of objects per batch.
+ */
+ public int numberOfObjectsPerBatch() {
+ return batchSize;
+ }
+
+ /**
+ * Returns the number of objects per batch.
+ */
+ public void setNumberOfObjectsPerBatch(int aSize) {
+ batchSize = aSize;
+ updateDisplayedObjects();
+ }
+
+ /**
+ * Clears the current selection.
+ *
+ * @return True is the selection was cleared, False if the selection could not
+ * be cleared
+ * @see #setSelectionIndexes
+ */
+ public boolean clearSelection() {
+ Object result = notifyDelegate("displayGroupShouldChangeSelection",
+ new Class[] { WODisplayGroup.class, List.class }, new Object[] { this, new NSArray(selectedObjects) });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return false;
+ }
+
+ selectionChanged = true;
+ willChange();
+
+ selectedObjects.removeAllObjects();
+ selectedIndexes.removeAllObjects();
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { WODisplayGroup.class }, new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+
+ return true;
+ }
+
+ /**
+ * Convenience for binding to a component action: calls deleteSelection() and
+ * then displayBatchContainingSelectedObject() and returns null, which is a
+ * suitable result from a component action.
+ */
+ public Object delete() {
+ deleteSelection();
+ displayBatchContainingSelectedObject();
+ return null;
+ }
+
+ /**
+ * Deletes the object at the specified index, notifying the delegate before and
+ * after the operation, and then updating the selection if needed.
+ *
+ * @return True if delete was successful, false if the object was not deleted.
+ */
+ public boolean deleteObjectAtIndex(int anIndex) {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+
+ Object result = notifyDelegate("displayGroupShouldDeleteObject",
+ new Class[] { WODisplayGroup.class, Object.class }, new Object[] { this, target });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return false;
+ }
+
+ deleteObjectAtIndexNoNotify(anIndex);
+
+ if (dataSource != null) {
+ dataSource.deleteObject(target);
+ }
+
+ notifyDelegate("displayGroupDidDeleteObject", new Class[] { WODisplayGroup.class, Object.class },
+ new Object[] { this, target });
+
+ return true;
+ }
+
+ private void deleteObjectAtIndexNoNotify(int anIndex) {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+
+ int i;
+
+ // remove from selected objects if necessary
+ i = indexOf(selectedObjects, target);
+ if (i != NSArray.NotFound) {
+ selectionChanged = true;
+ willChange(); // notify before removing
+ selectedObjects.removeObjectAtIndex(i);
+ selectedIndexes.remove(new Integer(i)); // comps by value
+ } else // notify - no selection change needed
+ {
+ willChange();
+ }
+
+ // remove from all objects
+ i = indexOf(allObjects, target);
+ if (i != NSArray.NotFound) {
+ allObjects.removeObjectAtIndex(i);
+ } else // otherwise should never happen
+ {
// throw new WotonomyException(
// "Displayed object not found in allObjects" );
- }
-
- // remove from displayed objects
- displayedObjects.removeObjectAtIndex( anIndex );
- }
-
- /**
- * Deletes the currently selected objects.
- * This implementation calls deleteObjectAtIndex() for
- * each index in the selection list, immediately returning
- * false if any delete operation fails.
- * @return True if all selected objects were deleted,
- * false if any deletion failed.
- */
- public boolean deleteSelection()
- {
- int i;
- boolean result = true;
-
- Enumeration e = new NSArray( selectedObjects ).objectEnumerator();
- while ( e.hasMoreElements() )
- {
- i = indexOf( displayedObjects, e.nextElement() );
- if ( i == NSArray.NotFound )
- {
- // should never happen
- throw new WotonomyException(
- "Selected object not found in displayedObjects" );
- }
- result = result && deleteObjectAtIndex( i );
- }
-
- return result;
- }
-
- /**
- * Returns a read-only List of all objects in the display group
- * that are currently displayed by the associations.
- */
- public NSArray displayedObjects()
- { // System.out.println( "avoided allocation: displayedObjects" );
- if ( batchSize < 1 ) return displayedObjectsProxy;
- return displayedObjectsProxy.subarrayWithRange(
- new NSRange( batchIndex * batchSize, batchSize ) );
- }
-
- /**
- * Requests a list of objects from the DataSource
- * and calls setObjectArray to populate the list.
- * More specifically, calls endEditing(), asks the
- * delegate, fetches the objects, notifies the delegate,
- * and populates the list. Returns null to force a
- * page reload.
- */
- public Object fetch()
- {
- endEditing();
-
- if ( dataSource == null )
- {
- return null;
- }
-
- Object result = notifyDelegate(
- "displayGroupShouldFetch",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return null;
- }
-
- NSNotificationCenter.defaultCenter().postNotification(
- DisplayGroupWillFetchNotification, this, new NSDictionary() );
-
- NSArray objectList = dataSource.fetchObjects();
-
- notifyDelegate(
- "displayGroupDidFetchObjects",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, objectList } );
-
- setObjectArray( objectList );
-
- if ( ( selectsFirstObjectAfterFetch ) && ( displayedObjects.size() > 0 ) )
- {
- setSelectionIndexes( new NSArray( new Integer( 0 ) ) );
- }
-
- return null;
- }
-
- /**
- * Convenience to call insertNewObjectAtIndex with the current selection plus one,
- * or at the end of the list if there is no selection.
- * Returns null to force a page reload.
- */
- public Object insert()
- {
- NSArray indexes = selectionIndexes();
- int size = indexes.count();
- if ( size == 0 )
- {
- insertNewObjectAtIndex( displayedObjects.count() );
- }
- else
- {
- insertNewObjectAtIndex(
- ((Number)selectedIndexes.objectAtIndex( size-1 )).intValue()+1 );
- }
- return null;
- }
-
- /**
- * Creates a new object at the specified index.
- * Calls insertObjectAtIndex() with the result
- * from sending createObject() to the data source.
- * @return the newly created object.
- */
- public Object insertNewObjectAtIndex ( int anIndex )
- {
- Object result = null;
- if ( dataSource != null )
- {
- result = dataSource.createObject();
- }
- if ( result != null )
- {
- if ( insertedObjectDefaultValues != null )
- {
- Duplicator.writePropertiesForObject(
- insertedObjectDefaultValues, result );
- }
- insertObjectAtIndex( result, anIndex );
- }
- else // create failed
- {
- if ( delegate() != null )
- {
- NSSelector selector = new NSSelector(
- "displayGroupCreateObjectFailed",
- new Class[] { WODisplayGroup.class, EODataSource.class } );
- if ( selector.implementedByObject( delegate() ) )
- {
- try
- {
- selector.invoke( delegate(), new Object[] { this, dataSource } );
- return result;
- }
- catch ( Exception exc )
- {
- System.err.println( "Error notifying delegate: displayGroupCreateObjectFailed" );
- exc.printStackTrace();
- }
- }
- }
- }
- return result;
- }
-
- /**
- * Inserts the specified object into the list at
- * the specified index.
- */
- public void insertObjectAtIndex ( Object anObject, int anIndex )
- {
- Object result = notifyDelegate(
- "displayGroupShouldInsertObject",
- new Class[] { WODisplayGroup.class, Object.class, int.class },
- new Object[] { this, anObject, new Integer(anIndex) } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return;
- }
-
- updatedObjectIndex = anIndex;
- willChange();
-
- int i;
-
- // add to all objects
- if ( anIndex == displayedObjects.size() )
- {
- allObjects.addObject( anObject );
- }
- else // insert before same object
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
- int targetIndex = indexOf( allObjects, target );
- if ( targetIndex != NSArray.NotFound )
- {
- allObjects.insertObjectAtIndex( anObject, targetIndex );
- }
- else // should never happen
- {
- throw new WotonomyException(
- "Could not find displayed object in all objects list: "
- + target );
- }
- }
-
- // add to displayed objects
- displayedObjects.insertObjectAtIndex( anObject, anIndex );
-
- if ( dataSource != null )
- {
- if ( dataSource instanceof OrderedDataSource )
- {
- ((OrderedDataSource)dataSource).insertObjectAtIndex(
- anObject, anIndex );
- }
- else
- {
- dataSource.insertObject( anObject );
- }
- }
-
- notifyDelegate(
- "displayGroupDidInsertObject",
- new Class[] { WODisplayGroup.class, Object.class },
- new Object[] { this, anObject } );
- }
-
- /**
- * Sets contentsChanged to true and notifies all observers.
- */
- public void redisplay()
- {
- willChange();
- }
-
- /**
- * Sets the selection to the next displayed object after the current
- * selection. If the last object is selected, or if no object
- * is selected, then the first object becomes selected.
- * If multiple items are selected, the first selected item is
- * considered the selected item for the purposes of this method.
- * Does not call redisplay().
- * @return null to force a page reload.
- */
- public Object selectNext()
- {
- int count = displayedObjects.count();
- if ( count == 0 ) return null;
- if ( count == 1 )
- {
- selectObject( displayedObjects.objectAtIndex( 0 ) );
- return null;
- }
-
- int i = -1;
- Object selectedObject = selectedObject();
- if ( selectedObject != null )
- {
- i = indexOf( displayedObjects, selectedObject );
- }
- if ( i == NSArray.NotFound ) i = -1;
-
- // select next object
- i++;
- if ( i != displayedObjects.count() )
- {
- // set to next object
- selectedObject = displayedObjects.objectAtIndex( i );
- }
- else // out of range
- {
- // set to null
- selectedObject = displayedObjects.objectAtIndex( 0 );
- }
-
- selectObject( selectedObject );
- return null;
- }
-
- /**
- * Sets the selection to the specified object.
- * If the specified object is null or does not exist
- * in the list of displayed objects, the selection
- * will be cleared.
- * @return true if the object was selected.
- */
- public boolean selectObject ( Object anObject )
- {
- if ( ( anObject == null ) ||
- ( indexOf( displayedObjects, anObject )
- == NSArray.NotFound ) )
- {
- clearSelection();
- return false;
- }
-
- selectObjectsIdenticalTo( new NSArray( new Object[] { anObject } ) );
- return true;
- }
-
- /**
- * Sets the selection to the specified objects.
- * If the specified list is null or if none of the objects
- * in the list exist in the list of displayed objects, the
- * selection will be cleared.
- * @return true if all specified objects were selected.
- */
- public boolean selectObjectsIdenticalTo ( List anObjectList )
- {
- // optimization: check for resetting of selection
- if ( ( anObjectList != null ) && ( selectedObjects.size() == anObjectList.size() ) )
- {
- boolean identical = true;
- int size = selectedObjects.size();
- for ( int i = 0; ( i < size ) && identical; i++ )
- {
- // compare by reference
- if ( anObjectList.get( i ) != selectedObjects.get( i ) )
- {
- identical = false;
- }
- else if ( displayedObjects.indexOfIdenticalObject(
- anObjectList.get( i ) ) == NSArray.NotFound )
- {
- identical = false;
- }
- }
- if ( identical )
- {
- return true;
- }
- }
-
- Object result = notifyDelegate(
- "displayGroupShouldChangeSelection",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, anObjectList } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- // need to notify the calling component
- // to revert back to the previous selection
- selectionChanged = true;
- willChange();
- return false;
- }
-
- int i;
- selectionChanged = true;
- willChange();
- Object o;
- selectedObjects.removeAllObjects();
- selectedIndexes.removeAllObjects();
- Iterator it = anObjectList.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- if ( ( i = displayedObjects.indexOfIdenticalObject( o ) )
- != NSArray.NotFound )
- {
- selectedObjects.addObject( o );
- selectedIndexes.addObject( new Integer( i ) );
- }
- }
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
-
- return true;
- }
-
- /**
- * Calls selectObjectsIdenticalTo and if false is returned
- * and selectFirstIfNoMatch is true, selects the first object.
- */
- public boolean selectObjectsIdenticalToSelectFirstOnNoMatch(
- List anObjectList, boolean selectFirstIfNoMatch )
- {
- if ( selectObjectsIdenticalTo( anObjectList ) )
- {
- return true;
- }
- if ( selectFirstIfNoMatch )
- {
- clearSelection();
- selectNext();
- return true;
- }
- return false;
- }
-
- /**
- * Sets the selection to the previous displayed object before the current
- * selection. If the first object is selected, or if no object
- * is selected, then the last object becomes selected.
- * If multiple items are selected, the first selected item is
- * considered the selected item for the purposes of this method.
- * Does not call redisplay().
- * @return null to force a page reload.
- */
- public Object selectPrevious()
- {
- int i = displayedObjects.count();
- if ( i == 0 ) return null;
- if ( i == 1 )
- {
- selectObject( displayedObjects.objectAtIndex( 0 ) );
- return null;
- }
-
- Object selectedObject = selectedObject();
- if ( selectedObject != null )
- {
- i = indexOf( displayedObjects, selectedObject );
- }
- if ( i == NSArray.NotFound ) i = displayedObjects.count();
-
- // select next object
- i--;
- if ( i < 0 )
- {
- // out of range - select last object
- i = displayedObjects.count() - 1;
- }
-
- selectObject( displayedObjects.objectAtIndex( i ) );
- return null;
- }
-
- /**
- * Returns the currently selected object, or null if
- * there is no selection.
- */
- public Object selectedObject()
- {
- if ( selectedObjects.count() == 0 )
- {
- return null;
- }
- return selectedObjects.objectAtIndex( 0 );
- }
-
- /**
- * Returns a read-only List containing all selected objects, if any.
- * Returns an empty list if no objects are selected.
- */
- public NSArray selectedObjects()
- { // System.out.println( "avoided allocation: selectedObjects" );
- return selectedObjectsProxy;
- }
-
- /**
- * Returns a read-only List containing the indexes of all selected
- * objects, if any. The list contains instances of
- * java.lang.Number; call intValue() to retrieve the index.
- */
- public NSArray selectionIndexes()
- {
+ }
+
+ // remove from displayed objects
+ displayedObjects.removeObjectAtIndex(anIndex);
+ }
+
+ /**
+ * Deletes the currently selected objects. This implementation calls
+ * deleteObjectAtIndex() for each index in the selection list, immediately
+ * returning false if any delete operation fails.
+ *
+ * @return True if all selected objects were deleted, false if any deletion
+ * failed.
+ */
+ public boolean deleteSelection() {
+ int i;
+ boolean result = true;
+
+ Enumeration e = new NSArray(selectedObjects).objectEnumerator();
+ while (e.hasMoreElements()) {
+ i = indexOf(displayedObjects, e.nextElement());
+ if (i == NSArray.NotFound) {
+ // should never happen
+ throw new WotonomyException("Selected object not found in displayedObjects");
+ }
+ result = result && deleteObjectAtIndex(i);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a read-only List of all objects in the display group that are
+ * currently displayed by the associations.
+ */
+ public NSArray displayedObjects() { // System.out.println( "avoided allocation: displayedObjects" );
+ if (batchSize < 1)
+ return displayedObjectsProxy;
+ return displayedObjectsProxy.subarrayWithRange(new NSRange(batchIndex * batchSize, batchSize));
+ }
+
+ /**
+ * Requests a list of objects from the DataSource and calls setObjectArray to
+ * populate the list. More specifically, calls endEditing(), asks the delegate,
+ * fetches the objects, notifies the delegate, and populates the list. Returns
+ * null to force a page reload.
+ */
+ public Object fetch() {
+ endEditing();
+
+ if (dataSource == null) {
+ return null;
+ }
+
+ Object result = notifyDelegate("displayGroupShouldFetch", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return null;
+ }
+
+ NSNotificationCenter.defaultCenter().postNotification(DisplayGroupWillFetchNotification, this,
+ new NSDictionary());
+
+ NSArray objectList = dataSource.fetchObjects();
+
+ notifyDelegate("displayGroupDidFetchObjects", new Class[] { WODisplayGroup.class, List.class },
+ new Object[] { this, objectList });
+
+ setObjectArray(objectList);
+
+ if ((selectsFirstObjectAfterFetch) && (displayedObjects.size() > 0)) {
+ setSelectionIndexes(new NSArray(new Integer(0)));
+ }
+
+ return null;
+ }
+
+ /**
+ * Convenience to call insertNewObjectAtIndex with the current selection plus
+ * one, or at the end of the list if there is no selection. Returns null to
+ * force a page reload.
+ */
+ public Object insert() {
+ NSArray indexes = selectionIndexes();
+ int size = indexes.count();
+ if (size == 0) {
+ insertNewObjectAtIndex(displayedObjects.count());
+ } else {
+ insertNewObjectAtIndex(((Number) selectedIndexes.objectAtIndex(size - 1)).intValue() + 1);
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new object at the specified index. Calls insertObjectAtIndex() with
+ * the result from sending createObject() to the data source.
+ *
+ * @return the newly created object.
+ */
+ public Object insertNewObjectAtIndex(int anIndex) {
+ Object result = null;
+ if (dataSource != null) {
+ result = dataSource.createObject();
+ }
+ if (result != null) {
+ if (insertedObjectDefaultValues != null) {
+ Duplicator.writePropertiesForObject(insertedObjectDefaultValues, result);
+ }
+ insertObjectAtIndex(result, anIndex);
+ } else // create failed
+ {
+ if (delegate() != null) {
+ NSSelector selector = new NSSelector("displayGroupCreateObjectFailed",
+ new Class[] { WODisplayGroup.class, EODataSource.class });
+ if (selector.implementedByObject(delegate())) {
+ try {
+ selector.invoke(delegate(), new Object[] { this, dataSource });
+ return result;
+ } catch (Exception exc) {
+ System.err.println("Error notifying delegate: displayGroupCreateObjectFailed");
+ exc.printStackTrace();
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Inserts the specified object into the list at the specified index.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ Object result = notifyDelegate("displayGroupShouldInsertObject",
+ new Class[] { WODisplayGroup.class, Object.class, int.class },
+ new Object[] { this, anObject, new Integer(anIndex) });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return;
+ }
+
+ updatedObjectIndex = anIndex;
+ willChange();
+
+ int i;
+
+ // add to all objects
+ if (anIndex == displayedObjects.size()) {
+ allObjects.addObject(anObject);
+ } else // insert before same object
+ {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+ int targetIndex = indexOf(allObjects, target);
+ if (targetIndex != NSArray.NotFound) {
+ allObjects.insertObjectAtIndex(anObject, targetIndex);
+ } else // should never happen
+ {
+ throw new WotonomyException("Could not find displayed object in all objects list: " + target);
+ }
+ }
+
+ // add to displayed objects
+ displayedObjects.insertObjectAtIndex(anObject, anIndex);
+
+ if (dataSource != null) {
+ if (dataSource instanceof OrderedDataSource) {
+ ((OrderedDataSource) dataSource).insertObjectAtIndex(anObject, anIndex);
+ } else {
+ dataSource.insertObject(anObject);
+ }
+ }
+
+ notifyDelegate("displayGroupDidInsertObject", new Class[] { WODisplayGroup.class, Object.class },
+ new Object[] { this, anObject });
+ }
+
+ /**
+ * Sets contentsChanged to true and notifies all observers.
+ */
+ public void redisplay() {
+ willChange();
+ }
+
+ /**
+ * Sets the selection to the next displayed object after the current selection.
+ * If the last object is selected, or if no object is selected, then the first
+ * object becomes selected. If multiple items are selected, the first selected
+ * item is considered the selected item for the purposes of this method. Does
+ * not call redisplay().
+ *
+ * @return null to force a page reload.
+ */
+ public Object selectNext() {
+ int count = displayedObjects.count();
+ if (count == 0)
+ return null;
+ if (count == 1) {
+ selectObject(displayedObjects.objectAtIndex(0));
+ return null;
+ }
+
+ int i = -1;
+ Object selectedObject = selectedObject();
+ if (selectedObject != null) {
+ i = indexOf(displayedObjects, selectedObject);
+ }
+ if (i == NSArray.NotFound)
+ i = -1;
+
+ // select next object
+ i++;
+ if (i != displayedObjects.count()) {
+ // set to next object
+ selectedObject = displayedObjects.objectAtIndex(i);
+ } else // out of range
+ {
+ // set to null
+ selectedObject = displayedObjects.objectAtIndex(0);
+ }
+
+ selectObject(selectedObject);
+ return null;
+ }
+
+ /**
+ * Sets the selection to the specified object. If the specified object is null
+ * or does not exist in the list of displayed objects, the selection will be
+ * cleared.
+ *
+ * @return true if the object was selected.
+ */
+ public boolean selectObject(Object anObject) {
+ if ((anObject == null) || (indexOf(displayedObjects, anObject) == NSArray.NotFound)) {
+ clearSelection();
+ return false;
+ }
+
+ selectObjectsIdenticalTo(new NSArray(new Object[] { anObject }));
+ return true;
+ }
+
+ /**
+ * Sets the selection to the specified objects. If the specified list is null or
+ * if none of the objects in the list exist in the list of displayed objects,
+ * the selection will be cleared.
+ *
+ * @return true if all specified objects were selected.
+ */
+ public boolean selectObjectsIdenticalTo(List anObjectList) {
+ // optimization: check for resetting of selection
+ if ((anObjectList != null) && (selectedObjects.size() == anObjectList.size())) {
+ boolean identical = true;
+ int size = selectedObjects.size();
+ for (int i = 0; (i < size) && identical; i++) {
+ // compare by reference
+ if (anObjectList.get(i) != selectedObjects.get(i)) {
+ identical = false;
+ } else if (displayedObjects.indexOfIdenticalObject(anObjectList.get(i)) == NSArray.NotFound) {
+ identical = false;
+ }
+ }
+ if (identical) {
+ return true;
+ }
+ }
+
+ Object result = notifyDelegate("displayGroupShouldChangeSelection",
+ new Class[] { WODisplayGroup.class, List.class }, new Object[] { this, anObjectList });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ // need to notify the calling component
+ // to revert back to the previous selection
+ selectionChanged = true;
+ willChange();
+ return false;
+ }
+
+ int i;
+ selectionChanged = true;
+ willChange();
+ Object o;
+ selectedObjects.removeAllObjects();
+ selectedIndexes.removeAllObjects();
+ Iterator it = anObjectList.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ if ((i = displayedObjects.indexOfIdenticalObject(o)) != NSArray.NotFound) {
+ selectedObjects.addObject(o);
+ selectedIndexes.addObject(new Integer(i));
+ }
+ }
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { WODisplayGroup.class }, new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+
+ return true;
+ }
+
+ /**
+ * Calls selectObjectsIdenticalTo and if false is returned and
+ * selectFirstIfNoMatch is true, selects the first object.
+ */
+ public boolean selectObjectsIdenticalToSelectFirstOnNoMatch(List anObjectList, boolean selectFirstIfNoMatch) {
+ if (selectObjectsIdenticalTo(anObjectList)) {
+ return true;
+ }
+ if (selectFirstIfNoMatch) {
+ clearSelection();
+ selectNext();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sets the selection to the previous displayed object before the current
+ * selection. If the first object is selected, or if no object is selected, then
+ * the last object becomes selected. If multiple items are selected, the first
+ * selected item is considered the selected item for the purposes of this
+ * method. Does not call redisplay().
+ *
+ * @return null to force a page reload.
+ */
+ public Object selectPrevious() {
+ int i = displayedObjects.count();
+ if (i == 0)
+ return null;
+ if (i == 1) {
+ selectObject(displayedObjects.objectAtIndex(0));
+ return null;
+ }
+
+ Object selectedObject = selectedObject();
+ if (selectedObject != null) {
+ i = indexOf(displayedObjects, selectedObject);
+ }
+ if (i == NSArray.NotFound)
+ i = displayedObjects.count();
+
+ // select next object
+ i--;
+ if (i < 0) {
+ // out of range - select last object
+ i = displayedObjects.count() - 1;
+ }
+
+ selectObject(displayedObjects.objectAtIndex(i));
+ return null;
+ }
+
+ /**
+ * Returns the currently selected object, or null if there is no selection.
+ */
+ public Object selectedObject() {
+ if (selectedObjects.count() == 0) {
+ return null;
+ }
+ return selectedObjects.objectAtIndex(0);
+ }
+
+ /**
+ * Returns a read-only List containing all selected objects, if any. Returns an
+ * empty list if no objects are selected.
+ */
+ public NSArray selectedObjects() { // System.out.println( "avoided allocation: selectedObjects" );
+ return selectedObjectsProxy;
+ }
+
+ /**
+ * Returns a read-only List containing the indexes of all selected objects, if
+ * any. The list contains instances of java.lang.Number; call intValue() to
+ * retrieve the index.
+ */
+ public NSArray selectionIndexes() {
// return selectedIndexes;
- int i;
- NSMutableArray result = new NSMutableArray();
- Enumeration e = selectedObjects.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- i = indexOf( displayedObjects, e.nextElement() );
- if ( i != NSArray.NotFound )
- {
- result.addObject( new Integer( i ) );
- }
- else
- {
- System.err.println(
- "Should never happen: selected objects not in displayed objects" );
- new RuntimeException().printStackTrace( System.err );
- }
- }
- return result;
- }
-
- /**
- * Sets the objects managed by this display group.
- * updateDisplayedObjects() is called to filter the
- * display objects. The previous selection will be
- * maintained if possible. The data source is not
- * notified.
- */
- public void setObjectArray ( List anObjectList )
- {
- if ( anObjectList == null ) anObjectList = new NSArray();
-
- Object result = notifyDelegate(
- "displayGroupDisplayArrayForObjects",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, anObjectList } );
- if ( result != null )
- {
- anObjectList = (List) result;
- }
-
- willChange();
-
- NSArray oldSelectedObjects = new NSArray( selectedObjects ); // copy
-
- // reset allObjects to new list
- allObjects.removeAllObjects();
- allObjects.addObjectsFromArray( anObjectList );
-
- // update the displayed object list
- updateDisplayedObjects();
-
- // restore the selection if possible
- selectObjectsIdenticalTo( oldSelectedObjects );
-
- batchIndex = 0;
- displayBatchContainingSelectedObject();
- }
-
- /**
- * Sets the currently selected object, or clears the
- * selection if the object is not found or is null.
- * Note: it's not clear how this differs from
- * selectObject in the spec. It is recommended that
- * you call selectObject for now.
- */
- public void setSelectedObject ( Object anObject )
- {
- selectObject( anObject );
- }
-
- /**
- * Sets the current selection to the specified objects.
- * The previous selection is cleared, and any objects
- * in the display group that are in the specified list
- * are then selected. If no items in the specified list
- * are found in the display group, then the selection is
- * effectively cleared.
- * Note: it's not clear how this differs from
- * selectObjectsIdenticalTo in the spec.
- * It is recommended that you call that method for now.
- */
- public void setSelectedObjects ( List aList )
- {
- selectObjectsIdenticalTo( aList );
- }
-
- /**
- * Sets the current selection to the objects at the
- * specified indexes. Items in the list are assumed
- * to be instances of java.lang.Number.
- * The previous selection is cleared, and any objects
- * in the display group that are in the specified list
- * are then selected. If no items in the specified list
- * are found in the display group, then the selection is
- * effectively cleared.
- */
- public boolean setSelectionIndexes ( List aList )
- {
- Object o;
- int index;
- NSMutableArray objects = new NSMutableArray();
- Iterator it = aList.iterator();
- while ( it.hasNext() )
- {
- index = ((Number)it.next()).intValue();
- if ( index < displayedObjects.count() )
- {
- o = displayedObjects.objectAtIndex( index );
- if ( o != null )
- {
- objects.add( o );
- }
- }
- }
- return selectObjectsIdenticalTo( objects );
- }
-
- /**
- * Applies the qualifier to all objects and sorts
- * the results to update the list of displayed objects.
- * Observing associations are notified to reflect the changes.
- */
- public void updateDisplayedObjects()
- {
- updatedObjectIndex = -1;
- willChange();
-
- displayedObjects.removeAllObjects();
-
- displayedObjects.addObjectsFromArray( allObjects );
-
- // apply qualifier, if any
- if ( qualifier != null )
- {
- EOQualifier.filterArrayWithQualifier(
- displayedObjects, qualifier );
- }
-
- // apply sort orderings, if any
- NSArray orderings = sortOrderings();
- if ( orderings != null )
- {
- if ( orderings.count() > 0 )
- {
- selectionChanged = true;
- willChange();
- EOSortOrdering.sortArrayUsingKeyOrderArray(
- displayedObjects, orderings );
- }
- }
-
- // make sure the selectedObjects is a subset of displayedObjects
- int i;
- Object o;
- Iterator it = new LinkedList( selectedObjects ).iterator();
- boolean removeflag = false;
- selectedIndexes.removeAllObjects();
- while ( it.hasNext() )
- {
- o = it.next();
- if ( ( i = displayedObjects.indexOfIdenticalObject( o ) )
- == NSArray.NotFound )
- {
- selectedObjects.removeIdenticalObject( o );
- removeflag = true;
- }
- else
- {
- selectedIndexes.addObject( new Integer( i ) );
- }
- }
-
- //Note: it is important to put the
- //selectionChanged = true line below remove.
- if (removeflag)
- {
- selectionChanged = true;
- willChange();
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- }
- }
-
- /**
- * Returns the index of the changed object. If more than
- * one object has changed, -1 is returned.
- */
- public int updatedObjectIndex()
- {
- return updatedObjectIndex;
- }
-
- // getting and setting values in objects
-
- /**
- * Returns a value on the selected object for the specified key.
- */
- public Object selectedObjectValueForKey ( String aKey )
- {
- Object selectedObject = selectedObject();
- if ( selectedObject == null ) return null;
- return valueForObject( selectedObject, aKey );
- }
-
- /**
- * Sets the specified value for the specified key on
- * all selected objects.
- */
- public boolean setSelectedObjectValue (
- Object aValue, String aKey )
- {
- Object selectedObject = selectedObject();
- if ( selectedObject == null ) return false;
- return setValueForObject( aValue, selectedObject, aKey );
- }
-
- /**
- * Sets the specified value for the specified key on
- * the specified object. Validations may be triggered,
- * and error dialogs may appear to the user.
- * @return True if the value was set successfully,
- * false if the value could not be set and the update
- * operation should not continue.
- */
- public boolean setValueForObject (
- Object aValue, Object anObject, String aKey )
- {
- // notify object's observers:
- // this includes us, and will notify our observers
- EOObserverCenter.notifyObserversObjectWillChange( anObject );
-
- //TODO: if key is null, need to remove old object
- // and add new object instead of simply replacing it.
-
- try
- {
- if ( anObject instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)anObject).takeValueForKey( aValue, aKey );
- }
- else
- {
- EOKeyValueCodingSupport.takeValueForKey( anObject, aValue, aKey );
- }
- }
- catch ( RuntimeException exc )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { WODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", exc.getMessage() } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- throw exc;
- }
- return false;
- }
-
- notifyDelegate(
- "displayGroupDidSetValueForObject",
- new Class[] { WODisplayGroup.class, Object.class, Object.class, String.class },
- new Object[] { this, aValue, anObject, aKey } );
-
- return true;
- }
-
- /**
- * Calls setValueForObject() for the object at
- * the specified index.
- */
- public boolean setValueForObjectAtIndex (
- Object aValue, int anIndex, String aKey )
- {
- return setValueForObject(
- aValue, displayedObjects.objectAtIndex( anIndex ), aKey );
- }
-
- /**
- * Returns the value for the specified key on the specified object.
- */
- public Object valueForObject ( Object anObject, String aKey )
- {
- // empty string is considered the identity property
- if ( aKey == null ) return anObject;
- if ( aKey.equals( "" ) ) return anObject;
-
- try
- {
- if ( anObject instanceof EOKeyValueCoding )
- {
- return ((EOKeyValueCoding)anObject).valueForKey( aKey );
- }
- else
- {
- return EOKeyValueCodingSupport.valueForKey( anObject, aKey );
- }
- }
- catch ( RuntimeException exc )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { WODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", exc.getMessage() } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- throw exc;
- }
- return null;
- }
- }
-
- /**
- * Calls valueForObject() for the object at the specified index.
- * Returns null if out of bounds.
- */
- public Object valueForObjectAtIndex ( int anIndex, String aKey )
- {
- if ( displayedObjects.count() <= anIndex ) return null;
- Object o = displayedObjects.objectAtIndex( anIndex );
- return valueForObject( o, aKey );
- }
-
- /**
- * Prints out the list of displayed objects.
- */
- public String toString()
- {
- return displayedObjects.toString();
- }
-
-
- /**
- * Handles notifications from the data source's editing context,
- * looking for InvalidatedAllObjectsInStoreNotification and
- * ObjectsChangedInEditingContextNotification, refetching in
- * the former case and updating displayed objects in the latter.
- * Note: This method is not in the public specification.
- */
- public void objectsInvalidatedInEditingContext( NSNotification aNotification )
- {
- if ( EOObjectStore.InvalidatedAllObjectsInStoreNotification
- .equals( aNotification.name() ) )
- {
- Object result = notifyDelegate(
- "displayGroupShouldRefetch",
- new Class[] { WODisplayGroup.class, NSNotification.class },
- new Object[] { this, aNotification } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- fetch();
- }
- }
- else
- if ( EOEditingContext.ObjectsChangedInEditingContextNotification
- .equals( aNotification.name() ) )
- {
- Object result = notifyDelegate(
- "displayGroupShouldRedisplay",
- new Class[] { WODisplayGroup.class, NSNotification.class },
- new Object[] { this, aNotification } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- int index;
- Enumeration e;
- boolean didChange = false;
- NSDictionary userInfo = aNotification.userInfo();
-
- // inserts are ignored
-
- // mark updated objects as updated
- NSArray updates = (NSArray) userInfo.objectForKey(
- EOObjectStore.UpdatedKey );
- e = updates.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- index = indexOf( displayedObjects, e.nextElement() );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "WODisplayGroup: updated: " + index );
- if ( ! didChange )
- {
- didChange = true;
- willChange();
- updatedObjectIndex = index;
- }
- else
- {
- updatedObjectIndex = -1;
- }
- }
- }
-
- // treat invalidated objects as updated
- NSArray invalidates = (NSArray) userInfo.objectForKey(
- EOObjectStore.InvalidatedKey );
- e = invalidates.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- index = indexOf( displayedObjects, e.nextElement() );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "WODisplayGroup: invalidated: " + index );
- if ( ! didChange )
- {
- didChange = true;
- willChange();
- updatedObjectIndex = index;
- }
- else
- {
- updatedObjectIndex = -1;
- }
- }
- }
-
- // remove deletes from display group if they exist
- NSArray deletes = (NSArray) userInfo.objectForKey(
- EOObjectStore.DeletedKey );
- e = deletes.objectEnumerator();
- Object o;
- while ( e.hasMoreElements() )
- {
- o = e.nextElement();
- index = indexOf( displayedObjects, o );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "WODisplayGroup: deleted: " + o );
- deleteObjectAtIndexNoNotify( index );
- }
- }
-
- if ( !usesOptimisticRefresh() )
- {
- updateDisplayedObjects();
- }
- }
- }
-
- }
-
- // static methods
-
- /**
- * Specifies the default behavior for whether changes
- * should be validated immediately for all display groups.
- */
- public static boolean
- globalDefaultForValidatesChangesImmediately()
- {
- return globalDefaultForValidatesChangesImmediately;
- }
-
- /**
- * Specifies the default string matching format for all
- * display groups.
- */
- public static String globalDefaultStringMatchFormat()
- {
- return globalDefaultStringMatchFormat;
- }
-
- /**
- * Specifies the default string matching operator for all
- * display groups.
- */
- public static String globalDefaultStringMatchOperator()
- {
- return globalDefaultStringMatchOperator;
- }
-
- /**
- * Sets the default behavior for validating changes
- * for all display groups.
- */
- public static void
- setGlobalDefaultForValidatesChangesImmediately (
- boolean validatesImmediately )
- {
- globalDefaultForValidatesChangesImmediately =
- validatesImmediately;
- }
-
- /**
- * Sets the default string matching format that
- * will be used by all display groups.
- */
- public static void
- setGlobalDefaultStringMatchFormat ( String aFormat )
- {
- globalDefaultStringMatchFormat = aFormat;
- }
-
- /**
- * Sets the default string matching operator that
- * will be used by all display groups.
- */
- public static void
- setGlobalDefaultStringMatchOperator ( String anOperator )
- {
- globalDefaultStringMatchOperator = anOperator;
- }
-
- /**
- * Needed because we don't inherit from NSObject.
- * Calls EOObserverCenter.notifyObserversObjectWillChange.
- */
- protected void willChange()
- {
- EOObserverCenter.notifyObserversObjectWillChange( this );
- }
-
- /**
- * Returns the index of the specified object in the
- * specified NSArray, comparing by value or by reference
- * as determined by the private instance variable
- * compareByReference. If not found, returns NSArray.NotFound.
- */
- private int indexOf( NSArray anArray, Object anObject )
- {
- if ( compareByReference )
- {
- return anArray.indexOfIdenticalObject( anObject );
- }
- else
- {
- return anArray.indexOf( anObject );
- }
- }
-
- // interface EOObserving
-
- /**
- * Receives notifications of changes from objects that
- * are managed by this display group. This implementation
- * sets updatedObjectIndex as appropriate.
- */
- public void objectWillChange(Object anObject)
- {
- int index = indexOf( displayedObjects, anObject );
- if ( index != NSArray.NotFound )
- {
- updatedObjectIndex = index;
- willChange();
- }
- }
-
- // interface EOEditingContext.Editor
-
- /**
- * Called before the editing context begins to save changes.
- * This implementation calls endEditing().
- */
- public void editingContextWillSaveChanges(
- EOEditingContext anEditingContext )
- {
- endEditing();
- }
-
- /**
- * Called to determine whether this editor has changes
- * that have not been committed to the object in the context.
- * This implementation returns false.
- */
- public boolean editorHasChangesForEditingContext(
- EOEditingContext anEditingContext )
- {
- return false;
- }
-
- // interface EOEditingContext.MessageHandler
-
- /**
- * Called to display a message for an error that occurred
- * in the specified editing context. If the delegate allows,
- * this implementation writes a message to the standard output.
- * Override to customize.
- */
- public void editingContextPresentErrorMessage(
- EOEditingContext anEditingContext,
- String aMessage )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { WODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", aMessage } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- System.out.println( aMessage );
- }
- }
-
- /**
- * Called by the specified object store to determine whether
- * fetching should continue, where count is the current count
- * and limit is the limit as specified by the fetch specification.
- * This implementation returns true. Override to customize.
- */
- public boolean editingContextShouldContinueFetching(
- EOEditingContext anEditingContext,
- int count,
- int limit,
- EOObjectStore anObjectStore )
- {
- return true;
- }
-
- /**
- * Sends the specified message to the delegate.
- * Returns the return value of the method,
- * or null if no return value or no delegate
- * or no implementation.
- */
- private Object notifyDelegate(
- String aMethodName, Class[] types, Object[] params )
- {
- try
- {
- Object delegate = delegate();
- if ( delegate == null ) return null;
- return NSSelector.invoke(
- aMethodName, types, delegate, params );
- }
- catch ( NoSuchMethodException e )
- {
- // ignore: not implemented
- }
- catch ( Exception exc )
- {
- // log to standard error
- System.err.println(
- "Error while messaging delegate: " +
- delegate + " : " + aMethodName );
- exc.printStackTrace();
- }
-
- return null;
- }
-
- /**
- * DisplayGroups can delegate important decisions to a Delegate.
- * Note that DisplayGroup doesn't require its delegates to implement
- * this interface: rather, this interface defines the methods that
- * DisplayGroup will attempt to invoke dynamically on its delegate.
- * The delegate may choose to implement only a subset of the methods
- * on the interface.
- */
- public interface Delegate
- {
- /**
- * Called when the specified data source fails
- * to create an object for the specified display group.
- */
- void displayGroupCreateObjectFailed (
- WODisplayGroup aDisplayGroup,
- EODataSource aDataSource );
-
- /**
- * Called after the specified display group's
- * data source is changed.
- */
- void displayGroupDidChangeDataSource (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called after a change occurs in the specified
- * display group's selected objects.
- */
- void displayGroupDidChangeSelectedObjects (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called after the specified display group's
- * selection has changed.
- */
- void displayGroupDidChangeSelection (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called after the specified display group has
- * deleted the specified object.
- */
- void displayGroupDidDeleteObject (
- WODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called after the specified display group
- * has fetched the specified object list.
- */
- void displayGroupDidFetchObjects (
- WODisplayGroup aDisplayGroup,
- List anObjectList );
-
- /**
- * Called after the specified display group
- * has inserted the specified object into
- * its internal object list.
- */
- void displayGroupDidInsertObject (
- WODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called after the specified display group
- * has set the specified value for the specified
- * object and key.
- */
- void displayGroupDidSetValueForObject (
- WODisplayGroup aDisplayGroup,
- Object aValue,
- Object anObject,
- String aKey );
-
- /**
- * Called by the specified display group to
- * determine what objects should be displayed
- * for the objects in the specified list.
- * @return An NSArray containing the objects
- * to be displayed for the objects in the
- * specified list.
- */
- NSArray displayGroupDisplayArrayForObjects (
- WODisplayGroup aDisplayGroup,
- List aList );
-
- /**
- * Called by the specified display group before
- * it attempts to change the selection.
- * @return True to allow the selection to change,
- * false otherwise.
- */
- boolean displayGroupShouldChangeSelection (
- WODisplayGroup aDisplayGroup,
- List aSelectionList );
-
- /**
- * Called by the specified display group before
- * it attempts to delete the specified object.
- * @return True to allow the object to be deleted
- * false to prevent the deletion.
- */
- boolean displayGroupShouldDeleteObject (
- WODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called by the specified display group before
- * it attempts display the specified alert to
- * the user.
- * @return True to allow the message to be
- * displayed, false if you want to handle the
- * alert yourself and suppress the display group's
- * notification.
- */
- boolean displayGroupShouldDisplayAlert (
- WODisplayGroup aDisplayGroup,
- String aTitle,
- String aMessage );
-
- /**
- * Called by the specified display group before
- * it attempts fetch objects.
- * @return True to allow the fetch to take place,
- * false to prevent the fetch.
- */
- boolean displayGroupShouldFetch (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called by the specified display group before
- * it attempts to insert the specified object.
- * @return True to allow the object to be inserted
- * false to prevent the insertion.
- */
- boolean displayGroupShouldInsertObject (
- WODisplayGroup aDisplayGroup,
- Object anObject,
- int anIndex );
-
- /**
- * Called by the specified display group when
- * it receives the specified
- * ObjectsChangedInEditingContextNotification.
- * @return True to allow the display group to
- * update the display (recommended), false
- * to prevent the update.
- */
- boolean displayGroupShouldRedisplay (
- WODisplayGroup aDisplayGroup,
- NSNotification aNotification );
-
- /**
- * Called by the specified display group when
- * it receives the specified
- * InvalidatedAllObjectsInStoreNotification.
- * @return True to allow the display group to
- * refetch (recommended), false to prevent the
- * refetch.
- */
- boolean displayGroupShouldRefetch (
- WODisplayGroup aDisplayGroup,
- NSNotification aNotification );
-
- }
+ int i;
+ NSMutableArray result = new NSMutableArray();
+ Enumeration e = selectedObjects.objectEnumerator();
+ while (e.hasMoreElements()) {
+ i = indexOf(displayedObjects, e.nextElement());
+ if (i != NSArray.NotFound) {
+ result.addObject(new Integer(i));
+ } else {
+ System.err.println("Should never happen: selected objects not in displayed objects");
+ new RuntimeException().printStackTrace(System.err);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Sets the objects managed by this display group. updateDisplayedObjects() is
+ * called to filter the display objects. The previous selection will be
+ * maintained if possible. The data source is not notified.
+ */
+ public void setObjectArray(List anObjectList) {
+ if (anObjectList == null)
+ anObjectList = new NSArray();
+
+ Object result = notifyDelegate("displayGroupDisplayArrayForObjects",
+ new Class[] { WODisplayGroup.class, List.class }, new Object[] { this, anObjectList });
+ if (result != null) {
+ anObjectList = (List) result;
+ }
+
+ willChange();
+
+ NSArray oldSelectedObjects = new NSArray(selectedObjects); // copy
+
+ // reset allObjects to new list
+ allObjects.removeAllObjects();
+ allObjects.addObjectsFromArray(anObjectList);
+
+ // update the displayed object list
+ updateDisplayedObjects();
+
+ // restore the selection if possible
+ selectObjectsIdenticalTo(oldSelectedObjects);
+
+ batchIndex = 0;
+ displayBatchContainingSelectedObject();
+ }
+
+ /**
+ * Sets the currently selected object, or clears the selection if the object is
+ * not found or is null. Note: it's not clear how this differs from selectObject
+ * in the spec. It is recommended that you call selectObject for now.
+ */
+ public void setSelectedObject(Object anObject) {
+ selectObject(anObject);
+ }
+
+ /**
+ * Sets the current selection to the specified objects. The previous selection
+ * is cleared, and any objects in the display group that are in the specified
+ * list are then selected. If no items in the specified list are found in the
+ * display group, then the selection is effectively cleared. Note: it's not
+ * clear how this differs from selectObjectsIdenticalTo in the spec. It is
+ * recommended that you call that method for now.
+ */
+ public void setSelectedObjects(List aList) {
+ selectObjectsIdenticalTo(aList);
+ }
+
+ /**
+ * Sets the current selection to the objects at the specified indexes. Items in
+ * the list are assumed to be instances of java.lang.Number. The previous
+ * selection is cleared, and any objects in the display group that are in the
+ * specified list are then selected. If no items in the specified list are found
+ * in the display group, then the selection is effectively cleared.
+ */
+ public boolean setSelectionIndexes(List aList) {
+ Object o;
+ int index;
+ NSMutableArray objects = new NSMutableArray();
+ Iterator it = aList.iterator();
+ while (it.hasNext()) {
+ index = ((Number) it.next()).intValue();
+ if (index < displayedObjects.count()) {
+ o = displayedObjects.objectAtIndex(index);
+ if (o != null) {
+ objects.add(o);
+ }
+ }
+ }
+ return selectObjectsIdenticalTo(objects);
+ }
+
+ /**
+ * Applies the qualifier to all objects and sorts the results to update the list
+ * of displayed objects. Observing associations are notified to reflect the
+ * changes.
+ */
+ public void updateDisplayedObjects() {
+ updatedObjectIndex = -1;
+ willChange();
+
+ displayedObjects.removeAllObjects();
+
+ displayedObjects.addObjectsFromArray(allObjects);
+
+ // apply qualifier, if any
+ if (qualifier != null) {
+ EOQualifier.filterArrayWithQualifier(displayedObjects, qualifier);
+ }
+
+ // apply sort orderings, if any
+ NSArray orderings = sortOrderings();
+ if (orderings != null) {
+ if (orderings.count() > 0) {
+ selectionChanged = true;
+ willChange();
+ EOSortOrdering.sortArrayUsingKeyOrderArray(displayedObjects, orderings);
+ }
+ }
+
+ // make sure the selectedObjects is a subset of displayedObjects
+ int i;
+ Object o;
+ Iterator it = new LinkedList(selectedObjects).iterator();
+ boolean removeflag = false;
+ selectedIndexes.removeAllObjects();
+ while (it.hasNext()) {
+ o = it.next();
+ if ((i = displayedObjects.indexOfIdenticalObject(o)) == NSArray.NotFound) {
+ selectedObjects.removeIdenticalObject(o);
+ removeflag = true;
+ } else {
+ selectedIndexes.addObject(new Integer(i));
+ }
+ }
+
+ // Note: it is important to put the
+ // selectionChanged = true line below remove.
+ if (removeflag) {
+ selectionChanged = true;
+ willChange();
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+ }
+ }
+
+ /**
+ * Returns the index of the changed object. If more than one object has changed,
+ * -1 is returned.
+ */
+ public int updatedObjectIndex() {
+ return updatedObjectIndex;
+ }
+
+ // getting and setting values in objects
+
+ /**
+ * Returns a value on the selected object for the specified key.
+ */
+ public Object selectedObjectValueForKey(String aKey) {
+ Object selectedObject = selectedObject();
+ if (selectedObject == null)
+ return null;
+ return valueForObject(selectedObject, aKey);
+ }
+
+ /**
+ * Sets the specified value for the specified key on all selected objects.
+ */
+ public boolean setSelectedObjectValue(Object aValue, String aKey) {
+ Object selectedObject = selectedObject();
+ if (selectedObject == null)
+ return false;
+ return setValueForObject(aValue, selectedObject, aKey);
+ }
+
+ /**
+ * Sets the specified value for the specified key on the specified object.
+ * Validations may be triggered, and error dialogs may appear to the user.
+ *
+ * @return True if the value was set successfully, false if the value could not
+ * be set and the update operation should not continue.
+ */
+ public boolean setValueForObject(Object aValue, Object anObject, String aKey) {
+ // notify object's observers:
+ // this includes us, and will notify our observers
+ EOObserverCenter.notifyObserversObjectWillChange(anObject);
+
+ // TODO: if key is null, need to remove old object
+ // and add new object instead of simply replacing it.
+
+ try {
+ if (anObject instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) anObject).takeValueForKey(aValue, aKey);
+ } else {
+ EOKeyValueCodingSupport.takeValueForKey(anObject, aValue, aKey);
+ }
+ } catch (RuntimeException exc) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { WODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", exc.getMessage() });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ throw exc;
+ }
+ return false;
+ }
+
+ notifyDelegate("displayGroupDidSetValueForObject",
+ new Class[] { WODisplayGroup.class, Object.class, Object.class, String.class },
+ new Object[] { this, aValue, anObject, aKey });
+
+ return true;
+ }
+
+ /**
+ * Calls setValueForObject() for the object at the specified index.
+ */
+ public boolean setValueForObjectAtIndex(Object aValue, int anIndex, String aKey) {
+ return setValueForObject(aValue, displayedObjects.objectAtIndex(anIndex), aKey);
+ }
+
+ /**
+ * Returns the value for the specified key on the specified object.
+ */
+ public Object valueForObject(Object anObject, String aKey) {
+ // empty string is considered the identity property
+ if (aKey == null)
+ return anObject;
+ if (aKey.equals(""))
+ return anObject;
+
+ try {
+ if (anObject instanceof EOKeyValueCoding) {
+ return ((EOKeyValueCoding) anObject).valueForKey(aKey);
+ } else {
+ return EOKeyValueCodingSupport.valueForKey(anObject, aKey);
+ }
+ } catch (RuntimeException exc) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { WODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", exc.getMessage() });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ throw exc;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Calls valueForObject() for the object at the specified index. Returns null if
+ * out of bounds.
+ */
+ public Object valueForObjectAtIndex(int anIndex, String aKey) {
+ if (displayedObjects.count() <= anIndex)
+ return null;
+ Object o = displayedObjects.objectAtIndex(anIndex);
+ return valueForObject(o, aKey);
+ }
+
+ /**
+ * Prints out the list of displayed objects.
+ */
+ public String toString() {
+ return displayedObjects.toString();
+ }
+
+ /**
+ * Handles notifications from the data source's editing context, looking for
+ * InvalidatedAllObjectsInStoreNotification and
+ * ObjectsChangedInEditingContextNotification, refetching in the former case and
+ * updating displayed objects in the latter. Note: This method is not in the
+ * public specification.
+ */
+ public void objectsInvalidatedInEditingContext(NSNotification aNotification) {
+ if (EOObjectStore.InvalidatedAllObjectsInStoreNotification.equals(aNotification.name())) {
+ Object result = notifyDelegate("displayGroupShouldRefetch",
+ new Class[] { WODisplayGroup.class, NSNotification.class }, new Object[] { this, aNotification });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ fetch();
+ }
+ } else if (EOEditingContext.ObjectsChangedInEditingContextNotification.equals(aNotification.name())) {
+ Object result = notifyDelegate("displayGroupShouldRedisplay",
+ new Class[] { WODisplayGroup.class, NSNotification.class }, new Object[] { this, aNotification });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ int index;
+ Enumeration e;
+ boolean didChange = false;
+ NSDictionary userInfo = aNotification.userInfo();
+
+ // inserts are ignored
+
+ // mark updated objects as updated
+ NSArray updates = (NSArray) userInfo.objectForKey(EOObjectStore.UpdatedKey);
+ e = updates.objectEnumerator();
+ while (e.hasMoreElements()) {
+ index = indexOf(displayedObjects, e.nextElement());
+ if (index != NSArray.NotFound) {
+ // System.out.println( "WODisplayGroup: updated: " + index );
+ if (!didChange) {
+ didChange = true;
+ willChange();
+ updatedObjectIndex = index;
+ } else {
+ updatedObjectIndex = -1;
+ }
+ }
+ }
+
+ // treat invalidated objects as updated
+ NSArray invalidates = (NSArray) userInfo.objectForKey(EOObjectStore.InvalidatedKey);
+ e = invalidates.objectEnumerator();
+ while (e.hasMoreElements()) {
+ index = indexOf(displayedObjects, e.nextElement());
+ if (index != NSArray.NotFound) {
+ // System.out.println( "WODisplayGroup: invalidated: " + index );
+ if (!didChange) {
+ didChange = true;
+ willChange();
+ updatedObjectIndex = index;
+ } else {
+ updatedObjectIndex = -1;
+ }
+ }
+ }
+
+ // remove deletes from display group if they exist
+ NSArray deletes = (NSArray) userInfo.objectForKey(EOObjectStore.DeletedKey);
+ e = deletes.objectEnumerator();
+ Object o;
+ while (e.hasMoreElements()) {
+ o = e.nextElement();
+ index = indexOf(displayedObjects, o);
+ if (index != NSArray.NotFound) {
+ // System.out.println( "WODisplayGroup: deleted: " + o );
+ deleteObjectAtIndexNoNotify(index);
+ }
+ }
+
+ if (!usesOptimisticRefresh()) {
+ updateDisplayedObjects();
+ }
+ }
+ }
+
+ }
+
+ // static methods
+
+ /**
+ * Specifies the default behavior for whether changes should be validated
+ * immediately for all display groups.
+ */
+ public static boolean globalDefaultForValidatesChangesImmediately() {
+ return globalDefaultForValidatesChangesImmediately;
+ }
+
+ /**
+ * Specifies the default string matching format for all display groups.
+ */
+ public static String globalDefaultStringMatchFormat() {
+ return globalDefaultStringMatchFormat;
+ }
+
+ /**
+ * Specifies the default string matching operator for all display groups.
+ */
+ public static String globalDefaultStringMatchOperator() {
+ return globalDefaultStringMatchOperator;
+ }
+
+ /**
+ * Sets the default behavior for validating changes for all display groups.
+ */
+ public static void setGlobalDefaultForValidatesChangesImmediately(boolean validatesImmediately) {
+ globalDefaultForValidatesChangesImmediately = validatesImmediately;
+ }
+
+ /**
+ * Sets the default string matching format that will be used by all display
+ * groups.
+ */
+ public static void setGlobalDefaultStringMatchFormat(String aFormat) {
+ globalDefaultStringMatchFormat = aFormat;
+ }
+
+ /**
+ * Sets the default string matching operator that will be used by all display
+ * groups.
+ */
+ public static void setGlobalDefaultStringMatchOperator(String anOperator) {
+ globalDefaultStringMatchOperator = anOperator;
+ }
+
+ /**
+ * Needed because we don't inherit from NSObject. Calls
+ * EOObserverCenter.notifyObserversObjectWillChange.
+ */
+ protected void willChange() {
+ EOObserverCenter.notifyObserversObjectWillChange(this);
+ }
+
+ /**
+ * Returns the index of the specified object in the specified NSArray, comparing
+ * by value or by reference as determined by the private instance variable
+ * compareByReference. If not found, returns NSArray.NotFound.
+ */
+ private int indexOf(NSArray anArray, Object anObject) {
+ if (compareByReference) {
+ return anArray.indexOfIdenticalObject(anObject);
+ } else {
+ return anArray.indexOf(anObject);
+ }
+ }
+
+ // interface EOObserving
+
+ /**
+ * Receives notifications of changes from objects that are managed by this
+ * display group. This implementation sets updatedObjectIndex as appropriate.
+ */
+ public void objectWillChange(Object anObject) {
+ int index = indexOf(displayedObjects, anObject);
+ if (index != NSArray.NotFound) {
+ updatedObjectIndex = index;
+ willChange();
+ }
+ }
+
+ // interface EOEditingContext.Editor
+
+ /**
+ * Called before the editing context begins to save changes. This implementation
+ * calls endEditing().
+ */
+ public void editingContextWillSaveChanges(EOEditingContext anEditingContext) {
+ endEditing();
+ }
+
+ /**
+ * Called to determine whether this editor has changes that have not been
+ * committed to the object in the context. This implementation returns false.
+ */
+ public boolean editorHasChangesForEditingContext(EOEditingContext anEditingContext) {
+ return false;
+ }
+
+ // interface EOEditingContext.MessageHandler
+
+ /**
+ * Called to display a message for an error that occurred in the specified
+ * editing context. If the delegate allows, this implementation writes a message
+ * to the standard output. Override to customize.
+ */
+ public void editingContextPresentErrorMessage(EOEditingContext anEditingContext, String aMessage) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { WODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", aMessage });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ System.out.println(aMessage);
+ }
+ }
+
+ /**
+ * Called by the specified object store to determine whether fetching should
+ * continue, where count is the current count and limit is the limit as
+ * specified by the fetch specification. This implementation returns true.
+ * Override to customize.
+ */
+ public boolean editingContextShouldContinueFetching(EOEditingContext anEditingContext, int count, int limit,
+ EOObjectStore anObjectStore) {
+ return true;
+ }
+
+ /**
+ * Sends the specified message to the delegate. Returns the return value of the
+ * method, or null if no return value or no delegate or no implementation.
+ */
+ private Object notifyDelegate(String aMethodName, Class[] types, Object[] params) {
+ try {
+ Object delegate = delegate();
+ if (delegate == null)
+ return null;
+ return NSSelector.invoke(aMethodName, types, delegate, params);
+ } catch (NoSuchMethodException e) {
+ // ignore: not implemented
+ } catch (Exception exc) {
+ // log to standard error
+ System.err.println("Error while messaging delegate: " + delegate + " : " + aMethodName);
+ exc.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
+ * DisplayGroups can delegate important decisions to a Delegate. Note that
+ * DisplayGroup doesn't require its delegates to implement this interface:
+ * rather, this interface defines the methods that DisplayGroup will attempt to
+ * invoke dynamically on its delegate. The delegate may choose to implement only
+ * a subset of the methods on the interface.
+ */
+ public interface Delegate {
+ /**
+ * Called when the specified data source fails to create an object for the
+ * specified display group.
+ */
+ void displayGroupCreateObjectFailed(WODisplayGroup aDisplayGroup, EODataSource aDataSource);
+
+ /**
+ * Called after the specified display group's data source is changed.
+ */
+ void displayGroupDidChangeDataSource(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after a change occurs in the specified display group's selected
+ * objects.
+ */
+ void displayGroupDidChangeSelectedObjects(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after the specified display group's selection has changed.
+ */
+ void displayGroupDidChangeSelection(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after the specified display group has deleted the specified object.
+ */
+ void displayGroupDidDeleteObject(WODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called after the specified display group has fetched the specified object
+ * list.
+ */
+ void displayGroupDidFetchObjects(WODisplayGroup aDisplayGroup, List anObjectList);
+
+ /**
+ * Called after the specified display group has inserted the specified object
+ * into its internal object list.
+ */
+ void displayGroupDidInsertObject(WODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called after the specified display group has set the specified value for the
+ * specified object and key.
+ */
+ void displayGroupDidSetValueForObject(WODisplayGroup aDisplayGroup, Object aValue, Object anObject,
+ String aKey);
+
+ /**
+ * Called by the specified display group to determine what objects should be
+ * displayed for the objects in the specified list.
+ *
+ * @return An NSArray containing the objects to be displayed for the objects in
+ * the specified list.
+ */
+ NSArray displayGroupDisplayArrayForObjects(WODisplayGroup aDisplayGroup, List aList);
+
+ /**
+ * Called by the specified display group before it attempts to change the
+ * selection.
+ *
+ * @return True to allow the selection to change, false otherwise.
+ */
+ boolean displayGroupShouldChangeSelection(WODisplayGroup aDisplayGroup, List aSelectionList);
+
+ /**
+ * Called by the specified display group before it attempts to delete the
+ * specified object.
+ *
+ * @return True to allow the object to be deleted false to prevent the deletion.
+ */
+ boolean displayGroupShouldDeleteObject(WODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called by the specified display group before it attempts display the
+ * specified alert to the user.
+ *
+ * @return True to allow the message to be displayed, false if you want to
+ * handle the alert yourself and suppress the display group's
+ * notification.
+ */
+ boolean displayGroupShouldDisplayAlert(WODisplayGroup aDisplayGroup, String aTitle, String aMessage);
+
+ /**
+ * Called by the specified display group before it attempts fetch objects.
+ *
+ * @return True to allow the fetch to take place, false to prevent the fetch.
+ */
+ boolean displayGroupShouldFetch(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called by the specified display group before it attempts to insert the
+ * specified object.
+ *
+ * @return True to allow the object to be inserted false to prevent the
+ * insertion.
+ */
+ boolean displayGroupShouldInsertObject(WODisplayGroup aDisplayGroup, Object anObject, int anIndex);
+
+ /**
+ * Called by the specified display group when it receives the specified
+ * ObjectsChangedInEditingContextNotification.
+ *
+ * @return True to allow the display group to update the display (recommended),
+ * false to prevent the update.
+ */
+ boolean displayGroupShouldRedisplay(WODisplayGroup aDisplayGroup, NSNotification aNotification);
+
+ /**
+ * Called by the specified display group when it receives the specified
+ * InvalidatedAllObjectsInStoreNotification.
+ *
+ * @return True to allow the display group to refetch (recommended), false to
+ * prevent the refetch.
+ */
+ boolean displayGroupShouldRefetch(WODisplayGroup aDisplayGroup, NSNotification aNotification);
+
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.6 2003/08/07 00:15:15 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.6 2003/08/07 00:15:15 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.5 2003/01/22 23:01:06 mpowers
- * Better handling for index out of bounds.
+ * Revision 1.5 2003/01/22 23:01:06 mpowers Better handling for index out of
+ * bounds.
*
- * Revision 1.4 2003/01/21 22:27:02 mpowers
- * Corrected context id usage.
+ * Revision 1.4 2003/01/21 22:27:02 mpowers Corrected context id usage.
* Implemented backtracking.
*
- * Revision 1.3 2003/01/21 17:54:01 mpowers
- * Batch indices are one-based, not zero-based.
+ * Revision 1.3 2003/01/21 17:54:01 mpowers Batch indices are one-based, not
+ * zero-based.
*
- * Revision 1.2 2003/01/21 14:38:42 mpowers
- * Fixed batching.
+ * Revision 1.2 2003/01/21 14:38:42 mpowers Fixed batching.
*
- * Revision 1.1 2003/01/18 23:30:42 mpowers
- * WODisplayGroup now compiles.
+ * Revision 1.1 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles.
*
- * Revision 1.46 2002/10/24 21:15:36 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.46 2002/10/24 21:15:36 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.45 2002/10/24 18:20:20 mpowers
- * Because NSArray is read-only, we are returning our internal representations
- * to callers of allObjects(), displayedObjects(), and selectedObjects().
+ * Revision 1.45 2002/10/24 18:20:20 mpowers Because NSArray is read-only, we
+ * are returning our internal representations to callers of allObjects(),
+ * displayedObjects(), and selectedObjects().
*
- * Revision 1.44 2002/08/06 18:20:25 mpowers
- * Now posting DisplayGroupWillFetch notifications before fetch.
- * Implemented support for usesOptimisticRefresh.
- * No longer supporting inserted/updated/deleted lists: not part of spec.
+ * Revision 1.44 2002/08/06 18:20:25 mpowers Now posting DisplayGroupWillFetch
+ * notifications before fetch. Implemented support for usesOptimisticRefresh. No
+ * longer supporting inserted/updated/deleted lists: not part of spec.
*
- * Revision 1.43 2002/05/17 15:01:49 mpowers
- * Implemented dynamic lookup of delegate methods so delegates no longer
- * need to implement the DisplayGroup.Delegate interface.
+ * Revision 1.43 2002/05/17 15:01:49 mpowers Implemented dynamic lookup of
+ * delegate methods so delegates no longer need to implement the
+ * DisplayGroup.Delegate interface.
*
- * Revision 1.42 2002/03/26 21:46:06 mpowers
- * Contributing EditingContext as a java-friendly convenience.
+ * Revision 1.42 2002/03/26 21:46:06 mpowers Contributing EditingContext as a
+ * java-friendly convenience.
*
- * Revision 1.41 2002/03/11 03:17:56 mpowers
- * Provided control point for coalesced changes.
+ * Revision 1.41 2002/03/11 03:17:56 mpowers Provided control point for
+ * coalesced changes.
*
- * Revision 1.40 2002/03/05 23:18:28 mpowers
- * Added documentation.
- * Added isSelectionPaintedImmediate and isSelectionTracking attributes
- * to TableAssociation.
- * Added getTableAssociation to TableColumnAssociation.
+ * Revision 1.40 2002/03/05 23:18:28 mpowers Added documentation. Added
+ * isSelectionPaintedImmediate and isSelectionTracking attributes to
+ * TableAssociation. Added getTableAssociation to TableColumnAssociation.
*
- * Revision 1.39 2002/02/19 22:26:04 mpowers
- * Implemented EOEditingContext.MessageHandler support.
+ * Revision 1.39 2002/02/19 22:26:04 mpowers Implemented
+ * EOEditingContext.MessageHandler support.
*
- * Revision 1.38 2002/02/19 16:37:38 mpowers
- * Implemented support for EOEditingContext.Editor
+ * Revision 1.38 2002/02/19 16:37:38 mpowers Implemented support for
+ * EOEditingContext.Editor
*
- * Revision 1.37 2001/12/11 22:17:48 mpowers
- * Now properly handling exceptions in valueForObject.
- * No longer trying to retain selection based only on index.
+ * Revision 1.37 2001/12/11 22:17:48 mpowers Now properly handling exceptions in
+ * valueForObject. No longer trying to retain selection based only on index.
*
- * Revision 1.36 2001/11/08 21:42:00 mpowers
- * Now we know what to do with shouldRefetch and shouldRedisplay.
+ * Revision 1.36 2001/11/08 21:42:00 mpowers Now we know what to do with
+ * shouldRefetch and shouldRedisplay.
*
- * Revision 1.35 2001/11/04 18:26:58 mpowers
- * Fixed bug where exceptions were not properly reported when updating
- * a value and the display group did not have a delegate.
+ * Revision 1.35 2001/11/04 18:26:58 mpowers Fixed bug where exceptions were not
+ * properly reported when updating a value and the display group did not have a
+ * delegate.
*
- * Revision 1.34 2001/11/02 20:59:36 mpowers
- * Now correctly ensuring selected objects are a subset of displayed objects.
+ * Revision 1.34 2001/11/02 20:59:36 mpowers Now correctly ensuring selected
+ * objects are a subset of displayed objects.
*
- * Revision 1.33 2001/10/30 22:56:45 mpowers
- * Added support for EOQualifier.
+ * Revision 1.33 2001/10/30 22:56:45 mpowers Added support for EOQualifier.
*
- * Revision 1.32 2001/10/23 22:27:53 mpowers
- * Now running at ObserverPrioritySixth.
+ * Revision 1.32 2001/10/23 22:27:53 mpowers Now running at
+ * ObserverPrioritySixth.
*
- * Revision 1.31 2001/10/23 18:45:05 mpowers
- * Rolling back changes.
+ * Revision 1.31 2001/10/23 18:45:05 mpowers Rolling back changes.
*
- * Revision 1.28 2001/08/22 19:23:41 mpowers
- * No longer asserting objects in all objects list.
+ * Revision 1.28 2001/08/22 19:23:41 mpowers No longer asserting objects in all
+ * objects list.
*
- * Revision 1.27 2001/07/30 16:17:01 mpowers
- * Minor code cleanup.
+ * Revision 1.27 2001/07/30 16:17:01 mpowers Minor code cleanup.
*
- * Revision 1.26 2001/07/10 22:49:07 mpowers
- * Fixed bug in optimization for selectObjectsIdenticalTo (found by Dongzhi).
+ * Revision 1.26 2001/07/10 22:49:07 mpowers Fixed bug in optimization for
+ * selectObjectsIdenticalTo (found by Dongzhi).
*
- * Revision 1.25 2001/06/19 15:40:21 mpowers
- * Now only changing the selection if the new selection is different
- * from the old.
+ * Revision 1.25 2001/06/19 15:40:21 mpowers Now only changing the selection if
+ * the new selection is different from the old.
*
- * Revision 1.24 2001/05/24 17:36:15 mpowers
- * Fixed problem with selectedObjectsIdenticalTo: it was using compare
- * by value instead of compare by reference.
+ * Revision 1.24 2001/05/24 17:36:15 mpowers Fixed problem with
+ * selectedObjectsIdenticalTo: it was using compare by value instead of compare
+ * by reference.
*
- * Revision 1.23 2001/05/18 21:09:19 mpowers
- * Now throwing exceptions if the delegate cannot handle error from update.
+ * Revision 1.23 2001/05/18 21:09:19 mpowers Now throwing exceptions if the
+ * delegate cannot handle error from update.
*
- * Revision 1.22 2001/05/14 15:26:12 mpowers
- * Now checking for null delegate before and after selection change.
+ * Revision 1.22 2001/05/14 15:26:12 mpowers Now checking for null delegate
+ * before and after selection change.
*
- * Revision 1.21 2001/05/08 18:47:34 mpowers
- * Minor fixes for d3.
+ * Revision 1.21 2001/05/08 18:47:34 mpowers Minor fixes for d3.
*
- * Revision 1.20 2001/04/29 22:02:45 mpowers
- * Work on id transposing between editing contexts.
+ * Revision 1.20 2001/04/29 22:02:45 mpowers Work on id transposing between
+ * editing contexts.
*
- * Revision 1.19 2001/04/13 16:38:09 mpowers
- * Alpha3 release.
+ * Revision 1.19 2001/04/13 16:38:09 mpowers Alpha3 release.
*
- * Revision 1.18 2001/04/03 20:36:01 mpowers
- * Fixed refaulting/reverting/invalidating to be self-consistent.
+ * Revision 1.18 2001/04/03 20:36:01 mpowers Fixed
+ * refaulting/reverting/invalidating to be self-consistent.
*
- * Revision 1.17 2001/03/29 03:31:13 mpowers
- * No longer using Introspector.
+ * Revision 1.17 2001/03/29 03:31:13 mpowers No longer using Introspector.
*
- * Revision 1.16 2001/02/27 03:32:18 mpowers
- * Implemented default values for new objects.
+ * Revision 1.16 2001/02/27 03:32:18 mpowers Implemented default values for new
+ * objects.
*
- * Revision 1.15 2001/02/27 02:11:17 mpowers
- * Now throwing exception when cloning fails.
- * Removed debugging printlns.
+ * Revision 1.15 2001/02/27 02:11:17 mpowers Now throwing exception when cloning
+ * fails. Removed debugging printlns.
*
- * Revision 1.14 2001/02/26 22:41:51 mpowers
- * Implemented null placeholder classes.
- * Duplicator now uses NSNull.
- * No longer catching base exception class.
+ * Revision 1.14 2001/02/26 22:41:51 mpowers Implemented null placeholder
+ * classes. Duplicator now uses NSNull. No longer catching base exception class.
*
- * Revision 1.13 2001/02/26 15:53:22 mpowers
- * Fine-tuning notification firing.
+ * Revision 1.13 2001/02/26 15:53:22 mpowers Fine-tuning notification firing.
* Child display groups now update properly after parent save or invalidate.
*
- * Revision 1.12 2001/02/22 20:55:06 mpowers
- * Implemented notification handling.
+ * Revision 1.12 2001/02/22 20:55:06 mpowers Implemented notification handling.
*
- * Revision 1.11 2001/02/21 20:40:42 mpowers
- * setObjectArray now falls back to index when trying to retain the
- * same selection.
+ * Revision 1.11 2001/02/21 20:40:42 mpowers setObjectArray now falls back to
+ * index when trying to retain the same selection.
*
- * Revision 1.10 2001/02/20 16:38:55 mpowers
- * MasterDetailAssociations now observe their controlled display group's
- * objects for changes to that the parent object will be marked as updated.
- * Before, only inserts and deletes to an object's items are registered.
- * Also, moved ObservableArray to package access.
+ * Revision 1.10 2001/02/20 16:38:55 mpowers MasterDetailAssociations now
+ * observe their controlled display group's objects for changes to that the
+ * parent object will be marked as updated. Before, only inserts and deletes to
+ * an object's items are registered. Also, moved ObservableArray to package
+ * access.
*
- * Revision 1.9 2001/02/17 17:23:49 mpowers
- * More changes to support compiling with jdk1.1 collections.
+ * Revision 1.9 2001/02/17 17:23:49 mpowers More changes to support compiling
+ * with jdk1.1 collections.
*
- * Revision 1.8 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.8 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.7 2001/01/24 16:35:37 mpowers
- * Improved documentation on TreeAssociation.
- * SortOrderings are now inherited from parent nodes.
- * Updates after sorting are still lost on TreeController.
+ * Revision 1.7 2001/01/24 16:35:37 mpowers Improved documentation on
+ * TreeAssociation. SortOrderings are now inherited from parent nodes. Updates
+ * after sorting are still lost on TreeController.
*
- * Revision 1.6 2001/01/24 14:23:05 mpowers
- * Added support for OrderedDataSource.
+ * Revision 1.6 2001/01/24 14:23:05 mpowers Added support for OrderedDataSource.
*
- * Revision 1.5 2001/01/12 17:21:37 mpowers
- * Implicit creation of EOSortOrderings now happens in setSortOrderings.
+ * Revision 1.5 2001/01/12 17:21:37 mpowers Implicit creation of EOSortOrderings
+ * now happens in setSortOrderings.
*
- * Revision 1.4 2001/01/11 20:34:26 mpowers
- * Implemented EOSortOrdering and added support in framework.
- * Added header-click to sort table columns.
+ * Revision 1.4 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added
+ * support in framework. Added header-click to sort table columns.
*
- * Revision 1.3 2001/01/10 22:49:44 mpowers
- * Implemented similarly named selection methods instead of
- * throwing exceptions.
+ * Revision 1.3 2001/01/10 22:49:44 mpowers Implemented similarly named
+ * selection methods instead of throwing exceptions.
*
- * Revision 1.2 2001/01/09 20:12:52 mpowers
- * Moved inner classes to package access.
+ * Revision 1.2 2001/01/09 20:12:52 mpowers Moved inner classes to package
+ * access.
*
- * Revision 1.1.1.1 2000/12/21 15:48:20 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:20 mpowers Contributing wotonomy.
*
- * Revision 1.21 2000/12/20 16:25:39 michael
- * Added log to all files.
+ * Revision 1.21 2000/12/20 16:25:39 michael Added log to all files.
*
- * Revision 1.20 2000/12/15 15:04:42 michael
- * Added doc.
+ * Revision 1.20 2000/12/15 15:04:42 michael Added doc.
*
- * Revision 1.19 2000/12/11 13:32:48 michael
- * Finish the much better TreeAssociation implementation.
- * TreeAssociation now has no gui dependencies.
+ * Revision 1.19 2000/12/11 13:32:48 michael Finish the much better
+ * TreeAssociation implementation. TreeAssociation now has no gui dependencies.
*
- * Revision 1.18 2000/12/05 17:41:46 michael
- * Broadcasts selection change after delegate refuses selection change
- * so the initiating association gets refreshed.
+ * Revision 1.18 2000/12/05 17:41:46 michael Broadcasts selection change after
+ * delegate refuses selection change so the initiating association gets
+ * refreshed.
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODynamicElement.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODynamicElement.java
index 6e449c3..6abb7d6 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODynamicElement.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODynamicElement.java
@@ -27,182 +27,175 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* The base class for dynamic WOElements. Dynamic elements
-* are expected to do something useful with user-entered data
-* in the request and with any binding associations with the
-* context's current WOComponent.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public abstract class WODynamicElement
- extends WOElement
-{
+ * The base class for dynamic WOElements. Dynamic elements are expected to do
+ * something useful with user-entered data in the request and with any binding
+ * associations with the context's current WOComponent.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public abstract class WODynamicElement extends WOElement {
protected String name;
protected WOElement rootElement;
- protected NSDictionary associations;
-
- /**
- * The default constructor.
- */
- protected WODynamicElement ()
- {
- name = null;
- associations = new NSMutableDictionary();
- rootElement = null;
- }
-
- /**
- * Required constructor specifying the class name of the component,
- * a map of associations, and the root element of the tree that
- * contains this element (which may be null). The map keys
- * correspond to properties of this element, and the values are
- * associations to be applied to the context's current component.
- */
- public WODynamicElement (
- String aName, NSDictionary anAssociationMap, WOElement aRootElement)
- {
- this();
- name = aName;
- associations = anAssociationMap;
- rootElement = aRootElement;
- }
-
- /**
- * Package access only. Called to initialize the component with
- * the proper context before the start of the request-response cycle.
- * If the context has a current component, that component becomes
- * this component's parent.
- */
- void ensureAwakeInContext (WOContext aContext)
- {
- if ( rootElement != null )
- {
- rootElement.ensureAwakeInContext( aContext );
- }
- }
-
- /**
- * Use this method to get a map with the properties that start with
- * a question mark. These are supposed to go at the end of a URL, and it is
- * very useful for components that generate URLs, specially with direct
- * actions.
- * @param c The component where the values of the properties have to be
- * retrieved from.
- */
- Map urlFields(WOComponent c) {
- HashMap map = new HashMap(associations.count());
- Enumeration enumeration = associations.keyEnumerator();
- while (enumeration.hasMoreElements()) {
- String key = (String)enumeration.nextElement();
- if (key.charAt(0) == '?') {
- map.put(key.substring(1), valueForProperty(key, c));
- }
- }
- return map;
- }
-
- /** Convenience method for getting the value of an association. */
- Object valueForProperty(String key, WOComponent c) {
- WOAssociation a = (WOAssociation)associations.objectForKey(key);
- if (a != null)
- return a.valueInComponent(c);
- return null;
- }
-
- /** Convenience method for getting the string value of an association. */
- String stringForProperty(String key, WOComponent c) {
- WOAssociation a = (WOAssociation)associations.objectForKey(key);
- Object result = null;
- if (a != null) result = a.valueInComponent(c);
- if ( result == null ) return null;
- return result.toString();
- }
-
- /** Convenience method for getting the string value of an association. */
- boolean booleanForProperty(String key, WOComponent c) {
- WOAssociation a = (WOAssociation)associations.objectForKey(key);
- Object result = null;
- if (a != null) result = a.valueInComponent(c);
- if ( result == null ) return false;
- if ( result.toString().toLowerCase().equals( "true" ) ) return true;
- return Boolean.TRUE.equals( result );
- }
-
- /** Convenience method for setting the value of an association. */
- void setValueForProperty(String key, Object value, WOComponent c) {
- WOAssociation a = (WOAssociation)associations.objectForKey(key);
- if ( a != null && a.isValueSettable() )
- a.setValue(value, c);
- }
-
- /** this method composes a String suitable for inclusion inside a HTML tag. It includes
- the key-value pairs of all the associations not mentioned in the standardProperties
- parameter. This is very useful for including extra properties in tags without having to worry
- if the HTML specification has changed or if non-standard tags are being used.
- @param c The component where the associations' values should be retrieved from.
- @param standardProperties An array of Strings with all the associations that should be
- excluded from the resulting string. */
- String additionalHTMLProperties(WOComponent c, NSArray standardProperties) {
- Enumeration enumeration = associations.keyEnumerator();
- StringBuffer buf = new StringBuffer();
- while (enumeration.hasMoreElements()) {
- String key = (String)enumeration.nextElement();
- if (!(standardProperties.containsObject(key) || key.charAt(0)=='?')) {
- buf.append(' ');
- buf.append(key);
- buf.append("=\"");
- buf.append(valueForProperty(key, c));
- buf.append('\"');
- }
- }
- return buf.toString();
- }
-
- /**
- * This method is called to retrieve user-entered data from
- * the request. WOElements should retrieve data from the
- * request based on their elementID and set values in the
- * context's current WOComponent, typically those values that
- * are associated with the element in the binding. This
- * implementation does nothing.
- */
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
-
+ protected NSDictionary associations;
+
+ /**
+ * The default constructor.
+ */
+ protected WODynamicElement() {
+ name = null;
+ associations = new NSMutableDictionary();
+ rootElement = null;
+ }
+
+ /**
+ * Required constructor specifying the class name of the component, a map of
+ * associations, and the root element of the tree that contains this element
+ * (which may be null). The map keys correspond to properties of this element,
+ * and the values are associations to be applied to the context's current
+ * component.
+ */
+ public WODynamicElement(String aName, NSDictionary anAssociationMap, WOElement aRootElement) {
+ this();
+ name = aName;
+ associations = anAssociationMap;
+ rootElement = aRootElement;
+ }
+
+ /**
+ * Package access only. Called to initialize the component with the proper
+ * context before the start of the request-response cycle. If the context has a
+ * current component, that component becomes this component's parent.
+ */
+ void ensureAwakeInContext(WOContext aContext) {
+ if (rootElement != null) {
+ rootElement.ensureAwakeInContext(aContext);
+ }
+ }
+
+ /**
+ * Use this method to get a map with the properties that start with a question
+ * mark. These are supposed to go at the end of a URL, and it is very useful for
+ * components that generate URLs, specially with direct actions.
+ *
+ * @param c The component where the values of the properties have to be
+ * retrieved from.
+ */
+ Map urlFields(WOComponent c) {
+ HashMap map = new HashMap(associations.count());
+ Enumeration enumeration = associations.keyEnumerator();
+ while (enumeration.hasMoreElements()) {
+ String key = (String) enumeration.nextElement();
+ if (key.charAt(0) == '?') {
+ map.put(key.substring(1), valueForProperty(key, c));
+ }
+ }
+ return map;
+ }
+
+ /** Convenience method for getting the value of an association. */
+ Object valueForProperty(String key, WOComponent c) {
+ WOAssociation a = (WOAssociation) associations.objectForKey(key);
+ if (a != null)
+ return a.valueInComponent(c);
+ return null;
+ }
+
+ /** Convenience method for getting the string value of an association. */
+ String stringForProperty(String key, WOComponent c) {
+ WOAssociation a = (WOAssociation) associations.objectForKey(key);
+ Object result = null;
+ if (a != null)
+ result = a.valueInComponent(c);
+ if (result == null)
+ return null;
+ return result.toString();
+ }
+
+ /** Convenience method for getting the string value of an association. */
+ boolean booleanForProperty(String key, WOComponent c) {
+ WOAssociation a = (WOAssociation) associations.objectForKey(key);
+ Object result = null;
+ if (a != null)
+ result = a.valueInComponent(c);
+ if (result == null)
+ return false;
+ if (result.toString().toLowerCase().equals("true"))
+ return true;
+ return Boolean.TRUE.equals(result);
}
- /**
- * This method is called on all objects and elements of the
- * application until a non-null value is returned.
- * WOElements should first check to see if they are the
- * target of an action by checking the WOContext's senderID
- * to see if it matches this element's elementID.
- * If this element is the target, it should perform an
- * appropriate action on the context's current WOComponent,
- * usually the action specified in the binding, and return
- * the result of that action. This implementation returns null.
- */
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- return null;
- }
-
- /**
- * This method is called on all elements of the content tree
- * to build a response to a user request. The message should
- * be forwarded to any child elements so that the entire tree
- * is traversed. This implementation does nothing.
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- // does nothing
- }
-
- public WOResponse generateResponse()
- {
- return null;
- }
+ /** Convenience method for setting the value of an association. */
+ void setValueForProperty(String key, Object value, WOComponent c) {
+ WOAssociation a = (WOAssociation) associations.objectForKey(key);
+ if (a != null && a.isValueSettable())
+ a.setValue(value, c);
+ }
+
+ /**
+ * this method composes a String suitable for inclusion inside a HTML tag. It
+ * includes the key-value pairs of all the associations not mentioned in the
+ * standardProperties parameter. This is very useful for including extra
+ * properties in tags without having to worry if the HTML specification has
+ * changed or if non-standard tags are being used.
+ *
+ * @param c The component where the associations' values should
+ * be retrieved from.
+ * @param standardProperties An array of Strings with all the associations that
+ * should be excluded from the resulting string.
+ */
+ String additionalHTMLProperties(WOComponent c, NSArray standardProperties) {
+ Enumeration enumeration = associations.keyEnumerator();
+ StringBuffer buf = new StringBuffer();
+ while (enumeration.hasMoreElements()) {
+ String key = (String) enumeration.nextElement();
+ if (!(standardProperties.containsObject(key) || key.charAt(0) == '?')) {
+ buf.append(' ');
+ buf.append(key);
+ buf.append("=\"");
+ buf.append(valueForProperty(key, c));
+ buf.append('\"');
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * This method is called to retrieve user-entered data from the request.
+ * WOElements should retrieve data from the request based on their elementID and
+ * set values in the context's current WOComponent, typically those values that
+ * are associated with the element in the binding. This implementation does
+ * nothing.
+ */
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+
+ }
+
+ /**
+ * This method is called on all objects and elements of the application until a
+ * non-null value is returned. WOElements should first check to see if they are
+ * the target of an action by checking the WOContext's senderID to see if it
+ * matches this element's elementID. If this element is the target, it should
+ * perform an appropriate action on the context's current WOComponent, usually
+ * the action specified in the binding, and return the result of that action.
+ * This implementation returns null.
+ */
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ return null;
+ }
+
+ /**
+ * This method is called on all elements of the content tree to build a response
+ * to a user request. The message should be forwarded to any child elements so
+ * that the entire tree is traversed. This implementation does nothing.
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ // does nothing
+ }
+
+ public WOResponse generateResponse() {
+ return null;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOElement.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOElement.java
index 11944d3..184eeea 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOElement.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOElement.java
@@ -23,75 +23,62 @@ import java.io.Serializable;
import net.wotonomy.foundation.NSDictionary;
/**
-* This class represents a static or dynamic portion of the
-* content returned to a request. Each request walks a tree
-* of WOElements to generate a response.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public abstract class WOElement implements WOActionResults, Serializable
-{
+ * This class represents a static or dynamic portion of the content returned to
+ * a request. Each request walks a tree of WOElements to generate a response.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public abstract class WOElement implements WOActionResults, Serializable {
NSDictionary associations;
-
+
+ /**
+ * Default constructor. Performs necessary initialization.
+ */
+ public WOElement() {
+ }
+
/**
- * Default constructor. Performs necessary initialization.
- */
- public WOElement()
- {
+ * This method is called to retrieve user-entered data from the request.
+ * WOElements should retrieve data from the request based on their elementID and
+ * set values in the context's current WOComponent, typically those values that
+ * are associated with the element in the binding. This implementation does
+ * nothing.
+ */
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ // does nothing
}
/**
- * This method is called to retrieve user-entered data from
- * the request. WOElements should retrieve data from the
- * request based on their elementID and set values in the
- * context's current WOComponent, typically those values that
- * are associated with the element in the binding. This
- * implementation does nothing.
- */
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
- // does nothing
- }
+ * This method is called on all objects and elements of the application until a
+ * non-null value is returned. WOElements should first check to see if they are
+ * the target of an action by checking the WOContext's senderID to see if it
+ * matches this element's elementID. If this element is the target, it should
+ * perform an appropriate action on the context's current WOComponent, usually
+ * the action specified in the binding, and return the result of that action.
+ * This implementation returns null.
+ */
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ return null;
+ }
- /**
- * This method is called on all objects and elements of the
- * application until a non-null value is returned.
- * WOElements should first check to see if they are the
- * target of an action by checking the WOContext's senderID
- * to see if it matches this element's elementID.
- * If this element is the target, it should perform an
- * appropriate action on the context's current WOComponent,
- * usually the action specified in the binding, and return
- * the result of that action. This implementation returns null.
- */
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- return null;
- }
-
- /**
- * This method is called on all elements of the content tree
- * to build a response to a user request. The message should
- * be forwarded to any child elements so that the entire tree
- * is traversed. This implementation does nothing.
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- // does nothing
- }
-
- /**
- * Package access only. Called to initialize the component with
- * the proper context before the start of the request-response cycle.
- * If the context has a current component, that component becomes
- * this component's parent.
- */
- void ensureAwakeInContext (WOContext aContext)
- {
- // does nothing
- }
+ /**
+ * This method is called on all elements of the content tree to build a response
+ * to a user request. The message should be forwarded to any child elements so
+ * that the entire tree is traversed. This implementation does nothing.
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ // does nothing
+ }
+
+ /**
+ * Package access only. Called to initialize the component with the proper
+ * context before the start of the request-response cycle. If the context has a
+ * current component, that component becomes this component's parent.
+ */
+ void ensureAwakeInContext(WOContext aContext) {
+ // does nothing
+ }
-
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOForm.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOForm.java
index 887d1a3..b4dca91 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOForm.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOForm.java
@@ -21,104 +21,101 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
-/**
-* Implements a FORM element with dynamic bindings.
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+/**
+ * Implements a FORM element with dynamic bindings.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOForm extends WODynamicElement {
- public WOForm() {
- super();
- }
-
- public WOForm(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
-
- public String href(WOContext c) {
- return (String)valueForProperty("href", c.component());
- }
-
- public String directActionName(WOContext c) {
- return (String)valueForProperty("directAction", c.component());
- }
-
- public String directActionClass(WOContext c) {
- return (String)valueForProperty("actionClass", c.component());
- }
-
- public boolean multipleSubmit(WOContext c) {
- return booleanForProperty("multipleSubmit", c.component());
- }
-
- public void takeValuesFromRequest (
- WORequest aRequest, WOContext aContext)
- {
- if ( rootElement != null )
- {
- rootElement.takeValuesFromRequest( aRequest, aContext );
- }
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- //Append the opening tag
- r.appendContentString("<FORM");
- String link = href(c);
- //Append the href, if present
- if (link != null) {
- r.appendContentString(" HREF=\"");
- r.appendContentString(link);
- r.appendContentString("\"");
- link = null;
- } else {
- link = directActionName(c);
- }
-
- //otherwise, append Direct Action
- if (link != null) {
- r.appendContentString(" HREF=\"");
- if (directActionClass(c) != null)
- link = directActionClass(c) + "/" + link;
- r.appendContentString(c.directActionURLForActionNamed(link, urlFields(c.component())));
- r.appendContentString("\"");
- link = null;
+ public WOForm() {
+ super();
+ }
+
+ public WOForm(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
+
+ public String href(WOContext c) {
+ return (String) valueForProperty("href", c.component());
+ }
+
+ public String directActionName(WOContext c) {
+ return (String) valueForProperty("directAction", c.component());
+ }
+
+ public String directActionClass(WOContext c) {
+ return (String) valueForProperty("actionClass", c.component());
+ }
+
+ public boolean multipleSubmit(WOContext c) {
+ return booleanForProperty("multipleSubmit", c.component());
+ }
+
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ if (rootElement != null) {
+ rootElement.takeValuesFromRequest(aRequest, aContext);
+ }
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ // Append the opening tag
+ r.appendContentString("<FORM");
+ String link = href(c);
+ // Append the href, if present
+ if (link != null) {
+ r.appendContentString(" HREF=\"");
+ r.appendContentString(link);
+ r.appendContentString("\"");
+ link = null;
+ } else {
+ link = directActionName(c);
+ }
+
+ // otherwise, append Direct Action
+ if (link != null) {
+ r.appendContentString(" HREF=\"");
+ if (directActionClass(c) != null)
+ link = directActionClass(c) + "/" + link;
+ r.appendContentString(c.directActionURLForActionNamed(link, urlFields(c.component())));
+ r.appendContentString("\"");
+ link = null;
// } else if (associations.objectForKey("action") != null) {
- } else {
- //finally, append action
- r.appendContentString(" action=\"");
- r.appendContentString(c.componentActionURL());
- r.appendContentString("\"");
- } //else
+ } else {
+ // finally, append action
+ r.appendContentString(" action=\"");
+ r.appendContentString(c.componentActionURL());
+ r.appendContentString("\"");
+ } // else
// now defaulting to action if not specified(?): WOBuilder does generate WOForms without any bindings(!)
// throw new IllegalArgumentException("You must use one of directActionName, action, or href.");
- //Append any additional properties
- link = additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "href", "action", "directActionName", "actionClass", "multipleSubmit" }));
- if (link.length() > 0)
- r.appendContentString(link);
- r.appendContentString(">");
- //Notify that we're inside a form now
- c.setInForm(true);
- //Append the inner template
- rootElement.appendToResponse(r, c);
- //Close the tag
- r.appendContentString("</FORM>");
+ // Append any additional properties
+ link = additionalHTMLProperties(c.component(),
+ new NSArray(new Object[] { "href", "action", "directActionName", "actionClass", "multipleSubmit" }));
+ if (link.length() > 0)
+ r.appendContentString(link);
+ r.appendContentString(">");
+ // Notify that we're inside a form now
+ c.setInForm(true);
+ // Append the inner template
+ rootElement.appendToResponse(r, c);
+ // Close the tag
+ r.appendContentString("</FORM>");
// c.deleteLastElementIDComponent();
- c.setInForm(false);
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- //We only process the request if it's not a multipleSubmit (otherwise we leave it to the buttons)
- if (!multipleSubmit(c)
- && c.elementID().equals(c.senderID())
- && associations.objectForKey("action") != null ) {
- return (WOActionResults)valueForProperty("action", c.component());
- }
- WOActionResults res = rootElement.invokeAction(r, c);
- return res;
- }
+ c.setInForm(false);
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ // We only process the request if it's not a multipleSubmit (otherwise we leave
+ // it to the buttons)
+ if (!multipleSubmit(c) && c.elementID().equals(c.senderID()) && associations.objectForKey("action") != null) {
+ return (WOActionResults) valueForProperty("action", c.component());
+ }
+ WOActionResults res = rootElement.invokeAction(r, c);
+ return res;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOFrame.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOFrame.java
index 30dd4bc..06f4b7f 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOFrame.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOFrame.java
@@ -6,55 +6,54 @@ import net.wotonomy.foundation.NSDictionary;
public class WOFrame extends WODynamicElement {
- public WOFrame() {
- super();
- }
-
- public WOFrame(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
-
- public String frameName(WOContext c) {
- String x = (String)valueForProperty("name", c.component());
- if (x != null)
- return x;
- return c.elementID();
- }
-
- public String url(WOContext c) {
- //Check if the href property is set
- String href = stringForProperty("href", c.component());
- if (href != null)
- return href;
- href = stringForProperty("pageName", c.component());
- if (href != null || associations.objectForKey("action") != null) { //write this component's URL
- return c.componentActionURL();
- }
- href = stringForProperty("directActionName", c.component());
- if (href != null) { //compose the direct action URL
- String fullActionName = stringForProperty("actionClass", c.component());
- if (fullActionName != null)
- fullActionName = fullActionName + "/" + href;
- else
- fullActionName = href;
- return c.directActionURLForActionNamed(fullActionName,
- urlFields(c.component()));
- }
- //Coded needed here to support filename/framework and data/mimeType.
- return null;
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString("<FRAME NAME=\"");
- r.appendContentString(frameName(c));
- r.appendContentString("\" SRC=\"");
- r.appendContentString(url(c));
- r.appendContentString("\"");
- String moreFields = additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "name", "href", "pageName", "directActionName", "actionClass" }));
- if (moreFields != null && moreFields.length() > 0)
- r.appendContentString(moreFields);
- r.appendContentString(">");
- }
+ public WOFrame() {
+ super();
+ }
+
+ public WOFrame(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
+
+ public String frameName(WOContext c) {
+ String x = (String) valueForProperty("name", c.component());
+ if (x != null)
+ return x;
+ return c.elementID();
+ }
+
+ public String url(WOContext c) {
+ // Check if the href property is set
+ String href = stringForProperty("href", c.component());
+ if (href != null)
+ return href;
+ href = stringForProperty("pageName", c.component());
+ if (href != null || associations.objectForKey("action") != null) { // write this component's URL
+ return c.componentActionURL();
+ }
+ href = stringForProperty("directActionName", c.component());
+ if (href != null) { // compose the direct action URL
+ String fullActionName = stringForProperty("actionClass", c.component());
+ if (fullActionName != null)
+ fullActionName = fullActionName + "/" + href;
+ else
+ fullActionName = href;
+ return c.directActionURLForActionNamed(fullActionName, urlFields(c.component()));
+ }
+ // Coded needed here to support filename/framework and data/mimeType.
+ return null;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<FRAME NAME=\"");
+ r.appendContentString(frameName(c));
+ r.appendContentString("\" SRC=\"");
+ r.appendContentString(url(c));
+ r.appendContentString("\"");
+ String moreFields = additionalHTMLProperties(c.component(),
+ new NSArray(new Object[] { "name", "href", "pageName", "directActionName", "actionClass" }));
+ if (moreFields != null && moreFields.length() > 0)
+ r.appendContentString(moreFields);
+ r.appendContentString(">");
+ }
} \ No newline at end of file
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericContainer.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericContainer.java
index 9af5460..b883b0f 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericContainer.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericContainer.java
@@ -21,41 +21,42 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
- * Used to dynamically generate HTML containers (elements with opening and closing tags and something in between).
+ * Used to dynamically generate HTML containers (elements with opening and
+ * closing tags and something in between).
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOGenericContainer extends WOGenericElement {
- public WOGenericContainer() {
- super();
- }
-
- public WOGenericContainer(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- super.appendToResponse(r, c);
- rootElement.appendToResponse(r, c);
- r.appendContentString("</");
- r.appendContentString(elementName(c));
- r.appendContentString(">");
- }
-
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- super.takeValuesFromRequest( r, c );
- rootElement.takeValuesFromRequest(r, c);
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- WOActionResults result = super.invokeAction( r, c );
- if ( result == null )
- {
- result = rootElement.invokeAction(r, c);
- }
- return result;
- }
+ public WOGenericContainer() {
+ super();
+ }
+
+ public WOGenericContainer(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ super.appendToResponse(r, c);
+ rootElement.appendToResponse(r, c);
+ r.appendContentString("</");
+ r.appendContentString(elementName(c));
+ r.appendContentString(">");
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ super.takeValuesFromRequest(r, c);
+ rootElement.takeValuesFromRequest(r, c);
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ WOActionResults result = super.invokeAction(r, c);
+ if (result == null) {
+ result = rootElement.invokeAction(r, c);
+ }
+ return result;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericElement.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericElement.java
index 8894428..92d1b42 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericElement.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericElement.java
@@ -22,74 +22,70 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
/**
- * Used to generate any HTML element dynamically. It only creates the opening tag without a closing tag.
- * To generate HTML elements that have opening and closing tags, as well as some content in between,
- * use WOGenericContainer instead.
+ * Used to generate any HTML element dynamically. It only creates the opening
+ * tag without a closing tag. To generate HTML elements that have opening and
+ * closing tags, as well as some content in between, use WOGenericContainer
+ * instead.
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOGenericElement extends WODynamicElement {
- static NSArray bindings = new NSArray( new Object[]
- { "elementName", "omitTags", "elementID", "otherTagString",
- "formValue", "formValues", "invokeAction" } );
-
- public WOGenericElement() {
- super();
- }
+ static NSArray bindings = new NSArray(new Object[] { "elementName", "omitTags", "elementID", "otherTagString",
+ "formValue", "formValues", "invokeAction" });
- public WOGenericElement(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOGenericElement() {
+ super();
+ }
- public String elementName(WOContext c) {
- String x = (String)valueForProperty("elementName", c.component());
- if (x != null)
- return x;
- return c.elementID();
- }
+ public WOGenericElement(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- if ( c.elementID().equals( c.senderID() ) )
- {
- Object value;
- value = r.formValueForKey( c.elementID() );
- setValueForProperty( "formValue", value, c.component() );
- value = r.formValuesForKey( c.elementID() );
- setValueForProperty( "formValues", value, c.component() );
- }
- }
+ public String elementName(WOContext c) {
+ String x = (String) valueForProperty("elementName", c.component());
+ if (x != null)
+ return x;
+ return c.elementID();
+ }
- public WOActionResults invokeAction(WORequest r, WOContext c)
- {
- WOActionResults result = null;
- String action = stringForProperty( "invokeAction", c.component() );
- if ( action != null && c.elementID().equals( c.senderID() ) )
- {
- result = c.component().performAction( action );
- }
- return result;
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- WOComponent component = c.component();
- if ( !booleanForProperty( "omitTags", component ) )
- {
- r.appendContentString("<");
- r.appendContentString(elementName(c));
- String other = stringForProperty( "otherTagString", component );
- if ( other != null )
- {
- r.appendContentString( " " );
- r.appendContentString( other );
- }
- String add = additionalHTMLProperties(component, bindings);
- if (add.length() > 0)
- r.appendContentString(add);
- r.appendContentString(">");
- }
- setValueForProperty( "elementID", c.elementID(), component );
- }
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ if (c.elementID().equals(c.senderID())) {
+ Object value;
+ value = r.formValueForKey(c.elementID());
+ setValueForProperty("formValue", value, c.component());
+ value = r.formValuesForKey(c.elementID());
+ setValueForProperty("formValues", value, c.component());
+ }
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ WOActionResults result = null;
+ String action = stringForProperty("invokeAction", c.component());
+ if (action != null && c.elementID().equals(c.senderID())) {
+ result = c.component().performAction(action);
+ }
+ return result;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ WOComponent component = c.component();
+ if (!booleanForProperty("omitTags", component)) {
+ r.appendContentString("<");
+ r.appendContentString(elementName(c));
+ String other = stringForProperty("otherTagString", component);
+ if (other != null) {
+ r.appendContentString(" ");
+ r.appendContentString(other);
+ }
+ String add = additionalHTMLProperties(component, bindings);
+ if (add.length() > 0)
+ r.appendContentString(add);
+ r.appendContentString(">");
+ }
+ setValueForProperty("elementID", c.elementID(), component);
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHiddenField.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHiddenField.java
index c5d5711..ca4e6c2 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHiddenField.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHiddenField.java
@@ -21,22 +21,23 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
-* Used to dynamically generate a hidden field within a form.
+ * Used to dynamically generate a hidden field within a form.
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOHiddenField extends WOTextField {
- public WOHiddenField() {
- super();
- }
+ public WOHiddenField() {
+ super();
+ }
- public WOHiddenField(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOHiddenField(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- }
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHyperlink.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHyperlink.java
index d0f3ff7..e2041d5 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHyperlink.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHyperlink.java
@@ -25,26 +25,30 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
/**
-* WOHyperlink renders a dynamically generated hyperlink in the output.
- * Bindings are:
+ * WOHyperlink renders a dynamically generated hyperlink in the output. Bindings
+ * are:
* <ul>
- * <li>string: a string to be included between the hyperlink tags (optional).</li>
+ * <li>string: a string to be included between the hyperlink tags
+ * (optional).</li>
* <li>escapeHTML: a property returning a value convertable to a Boolean
- * indicating whether the any html characters in the output should be
- * escaped so they are shown as html characters rather than interpreted
- * as html.</li>
+ * indicating whether the any html characters in the output should be escaped so
+ * they are shown as html characters rather than interpreted as html.</li>
* <li>href: The URL that the hyperlink should point to.</li>
- * <li>pageName: The name of the WOComponent that the hyperlink should point to.</li>
- * <li>directActionName: The name of the direct action to call when the link is activated.</li>
- * <li>actionClass: The name of the WODirectAction subclass where the direct action resides.</li>
+ * <li>pageName: The name of the WOComponent that the hyperlink should point
+ * to.</li>
+ * <li>directActionName: The name of the direct action to call when the link is
+ * activated.</li>
+ * <li>actionClass: The name of the WODirectAction subclass where the direct
+ * action resides.</li>
* <li>anchorName: The name of the link, for anchor tags.</li>
- * <li>action: A pointer to a method on the component that contains this element. If the link is activated,
- * the method will be called.
+ * <li>action: A pointer to a method on the component that contains this
+ * element. If the link is activated, the method will be called.
* <li>ref: The name of the anchor to go to inside the resulting page.</li>
* </ul>
*
- * The href, pageName and directActionName/actionClass and name properties are mutually exclusive and you should
- * only use at most one of them simultaneously.
+ * The href, pageName and directActionName/actionClass and name properties are
+ * mutually exclusive and you should only use at most one of them
+ * simultaneously.
*
* @author ezamudio@nasoft.com
* @author $Author: cgruber $
@@ -52,198 +56,202 @@ import net.wotonomy.foundation.NSDictionary;
*/
public class WOHyperlink extends WODynamicElement {
- protected String string;
- protected String href;
- protected String pageName;
- protected String directActionName;
- protected String actionClass;
- protected String action;
- protected boolean escapeHTML;
- protected String anchorName;
- protected String ref;
-
- protected WOHyperlink() {
- super();
- }
-
- public WOHyperlink(String aName, NSDictionary aMap, WOElement aRootElement) {
- super(aName, aMap, aRootElement);
- escapeHTML = true;
- }
-
- public void setString(String value) {
- string = value;
- }
- public String string() {
- return string;
- }
-
- public void setHref(String value) {
- href = value;
- }
- public String href() {
- return href;
- }
-
- public void setAnchorName(String value) {
- anchorName = value;
- }
- public String anchorName() {
- return anchorName;
- }
-
- public void setPageName(String value) {
- pageName = value;
- }
- public String pageName() {
- return pageName;
- }
-
- public void setDirectActionName(String value) {
- directActionName = value;
- }
- public String directActionName() {
- return directActionName;
- }
-
- public void setActionClass(String value) {
- actionClass = value;
- }
- public String actionClass() {
- return actionClass;
- }
-
- /** Sets the escapeHTML property. */
- public void setEscapeHTML(boolean escape) {
- escapeHTML = escape;
- }
-
- /** If true, inserts escape codes in to the <B>string</B> string so
- * that HTML special characters (greater-than, less-than, etc.)
- * appear correctly. If false, those characters will get
- * interpreted by the browser. Defaults to true.
- */
- public boolean escapeHTML() {
- return escapeHTML;
- }
-
- public String actionURL(WOContext c) {
- //Check if the href property is set
- if (href() != null) {
- return href();
- } else if (pageName() != null || associations.objectForKey("action") != null) { //write this component's URL
- StringBuffer retval = new StringBuffer(c.componentActionURL());
- Map addFields = urlFields(c.component());
- if (addFields.size() > 0) {
- Iterator enumeration = addFields.keySet().iterator();
- retval.append('?');
- while (enumeration.hasNext()) {
- String encoding = c.response() != null ? c.response().contentEncoding() : c.request().contentEncoding();
- String key = (String)enumeration.next();
- try {
+ protected String string;
+ protected String href;
+ protected String pageName;
+ protected String directActionName;
+ protected String actionClass;
+ protected String action;
+ protected boolean escapeHTML;
+ protected String anchorName;
+ protected String ref;
+
+ protected WOHyperlink() {
+ super();
+ }
+
+ public WOHyperlink(String aName, NSDictionary aMap, WOElement aRootElement) {
+ super(aName, aMap, aRootElement);
+ escapeHTML = true;
+ }
+
+ public void setString(String value) {
+ string = value;
+ }
+
+ public String string() {
+ return string;
+ }
+
+ public void setHref(String value) {
+ href = value;
+ }
+
+ public String href() {
+ return href;
+ }
+
+ public void setAnchorName(String value) {
+ anchorName = value;
+ }
+
+ public String anchorName() {
+ return anchorName;
+ }
+
+ public void setPageName(String value) {
+ pageName = value;
+ }
+
+ public String pageName() {
+ return pageName;
+ }
+
+ public void setDirectActionName(String value) {
+ directActionName = value;
+ }
+
+ public String directActionName() {
+ return directActionName;
+ }
+
+ public void setActionClass(String value) {
+ actionClass = value;
+ }
+
+ public String actionClass() {
+ return actionClass;
+ }
+
+ /** Sets the escapeHTML property. */
+ public void setEscapeHTML(boolean escape) {
+ escapeHTML = escape;
+ }
+
+ /**
+ * If true, inserts escape codes in to the <B>string</B> string so that HTML
+ * special characters (greater-than, less-than, etc.) appear correctly. If
+ * false, those characters will get interpreted by the browser. Defaults to
+ * true.
+ */
+ public boolean escapeHTML() {
+ return escapeHTML;
+ }
+
+ public String actionURL(WOContext c) {
+ // Check if the href property is set
+ if (href() != null) {
+ return href();
+ } else if (pageName() != null || associations.objectForKey("action") != null) { // write this component's URL
+ StringBuffer retval = new StringBuffer(c.componentActionURL());
+ Map addFields = urlFields(c.component());
+ if (addFields.size() > 0) {
+ Iterator enumeration = addFields.keySet().iterator();
+ retval.append('?');
+ while (enumeration.hasNext()) {
+ String encoding = c.response() != null ? c.response().contentEncoding()
+ : c.request().contentEncoding();
+ String key = (String) enumeration.next();
+ try {
retval.append(java.net.URLEncoder.encode(key, encoding));
- } catch (java.io.UnsupportedEncodingException ex) {
- retval.append(key);
- }
- retval.append("=");
+ } catch (java.io.UnsupportedEncodingException ex) {
+ retval.append(key);
+ }
+ retval.append("=");
try {
retval.append(java.net.URLEncoder.encode(addFields.get(key).toString(), encoding));
} catch (java.io.UnsupportedEncodingException e) {
retval.append(addFields.get(key).toString());
}
- if (enumeration.hasNext())
- retval.append('&');
- }
- }
- return retval.toString();
- } else if (directActionName() != null) { //compose the direct action URL
- String fullActionName = null;
- if (actionClass() != null )
- fullActionName = actionClass() + "/" + directActionName();
- else
- fullActionName = directActionName();
- return c.directActionURLForActionNamed(fullActionName, urlFields(c.component()));
- }
- return null;
- }
-
- protected void pullValuesFromParent(WOComponent c) {
- string = stringForProperty("string", c);
- href = stringForProperty("href", c);
- pageName = stringForProperty("pageName", c);
- directActionName = stringForProperty("directActionName", c);
- actionClass = stringForProperty("actionClass", c);
- //action = stringForProperty("action", c);
- escapeHTML = booleanForProperty("escapeHTML", c);
- anchorName = stringForProperty("anchorName", c);
- ref = stringForProperty("ref", c);
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- pullValuesFromParent( c.component() );
- r.appendContentString("<A");
- boolean closeQuotes = false;
- //Check if the href property is set
- String _href = actionURL(c);
- if (_href != null) {
- closeQuotes = true;
- r.appendContentString(" HREF=\"");
- r.appendContentString(_href);
- } else if (anchorName() != null) {
- r.appendContentString(" NAME=\"");
- r.appendContentString(anchorName());
- closeQuotes = true;
- }
- if (ref != null) {
- if (!closeQuotes) {
- r.appendContentString(" HREF=\"#");
- closeQuotes = true;
- } else
- r.appendContentString("#");
- r.appendContentString(ref);
- }
- if (closeQuotes)
- r.appendContentString("\"");
- r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "name", "href", "pageName", "action", "directActionName", "actionClass", "anchorName",
- "escapeHTML", "string" })));
- r.appendContentString(">");
- //Append the string if present
- if (string() != null) {
- if (escapeHTML())
- r.appendContentHTMLString(string());
- else
- r.appendContentString(string());
- }
- //If there is a template, call appendToResponse on it
- if (rootElement != null) {
- rootElement.appendToResponse(r, c);
- }
- //Close the tag
- r.appendContentString("</A>");
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- System.out.println("invoke action with elementID=" + c.elementID() + " senderID=" + c.senderID());
- //Check if this element is the target
- if (c.senderID().equals(c.elementID())) {
- if (pageName() != null)
- {
- return WOApplication.application().pageWithName(pageName(), r);
- }
- else
- {
- WOAssociation ass = (WOAssociation) associations.objectForKey("action");
- if ( ass != null && ass.path != null ) //??
- return (WOActionResults)c.component().performAction( ass.path );
- }
- }
- return null;
- }
-
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- System.out.println("takeValuesFromRequest elementID=" + c.elementID() + " senderID=" + c.senderID());
- super.takeValuesFromRequest(r, c);
- }
+ if (enumeration.hasNext())
+ retval.append('&');
+ }
+ }
+ return retval.toString();
+ } else if (directActionName() != null) { // compose the direct action URL
+ String fullActionName = null;
+ if (actionClass() != null)
+ fullActionName = actionClass() + "/" + directActionName();
+ else
+ fullActionName = directActionName();
+ return c.directActionURLForActionNamed(fullActionName, urlFields(c.component()));
+ }
+ return null;
+ }
+
+ protected void pullValuesFromParent(WOComponent c) {
+ string = stringForProperty("string", c);
+ href = stringForProperty("href", c);
+ pageName = stringForProperty("pageName", c);
+ directActionName = stringForProperty("directActionName", c);
+ actionClass = stringForProperty("actionClass", c);
+ // action = stringForProperty("action", c);
+ escapeHTML = booleanForProperty("escapeHTML", c);
+ anchorName = stringForProperty("anchorName", c);
+ ref = stringForProperty("ref", c);
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ pullValuesFromParent(c.component());
+ r.appendContentString("<A");
+ boolean closeQuotes = false;
+ // Check if the href property is set
+ String _href = actionURL(c);
+ if (_href != null) {
+ closeQuotes = true;
+ r.appendContentString(" HREF=\"");
+ r.appendContentString(_href);
+ } else if (anchorName() != null) {
+ r.appendContentString(" NAME=\"");
+ r.appendContentString(anchorName());
+ closeQuotes = true;
+ }
+ if (ref != null) {
+ if (!closeQuotes) {
+ r.appendContentString(" HREF=\"#");
+ closeQuotes = true;
+ } else
+ r.appendContentString("#");
+ r.appendContentString(ref);
+ }
+ if (closeQuotes)
+ r.appendContentString("\"");
+ r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(new Object[] { "name", "href",
+ "pageName", "action", "directActionName", "actionClass", "anchorName", "escapeHTML", "string" })));
+ r.appendContentString(">");
+ // Append the string if present
+ if (string() != null) {
+ if (escapeHTML())
+ r.appendContentHTMLString(string());
+ else
+ r.appendContentString(string());
+ }
+ // If there is a template, call appendToResponse on it
+ if (rootElement != null) {
+ rootElement.appendToResponse(r, c);
+ }
+ // Close the tag
+ r.appendContentString("</A>");
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ System.out.println("invoke action with elementID=" + c.elementID() + " senderID=" + c.senderID());
+ // Check if this element is the target
+ if (c.senderID().equals(c.elementID())) {
+ if (pageName() != null) {
+ return WOApplication.application().pageWithName(pageName(), r);
+ } else {
+ WOAssociation ass = (WOAssociation) associations.objectForKey("action");
+ if (ass != null && ass.path != null) // ??
+ return (WOActionResults) c.component().performAction(ass.path);
+ }
+ }
+ return null;
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ System.out.println("takeValuesFromRequest elementID=" + c.elementID() + " senderID=" + c.senderID());
+ super.takeValuesFromRequest(r, c);
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImage.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImage.java
index 2673cd1..3f830b0 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImage.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImage.java
@@ -6,145 +6,146 @@ import net.wotonomy.foundation.NSData;
import net.wotonomy.foundation.NSDictionary;
/**
-* WOImage renders a dynamically generated IMG tag. The URL for the image SRC can be
-* static, or it can be generated dynamically to return a NSData object (with a mime-type)
-* or even return the contents of a file (not implemented yet).
-*
-* Bindings are:
-* <UL><LI>src: A static URL for the image source.</li>
-* <li>data: A NSData object with the image content. Must be used with mimeType.</li>
-* <li>mimeType: The MIME type for the image data. Can be used with filename or data bindings.</li>
-* <li>filename: The path to a file containing an image.</li>
-* <li>framework: The optional framework from whence the image should be retrieved (used in conjunction with filename).</li>
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+ * WOImage renders a dynamically generated IMG tag. The URL for the image SRC
+ * can be static, or it can be generated dynamically to return a NSData object
+ * (with a mime-type) or even return the contents of a file (not implemented
+ * yet).
+ *
+ * Bindings are:
+ * <UL>
+ * <LI>src: A static URL for the image source.</li>
+ * <li>data: A NSData object with the image content. Must be used with
+ * mimeType.</li>
+ * <li>mimeType: The MIME type for the image data. Can be used with filename or
+ * data bindings.</li>
+ * <li>filename: The path to a file containing an image.</li>
+ * <li>framework: The optional framework from whence the image should be
+ * retrieved (used in conjunction with filename).</li>
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOImage extends WODynamicElement {
- protected String src;
- protected String filename;
- protected String framework;
- protected NSData data;
- protected String mimeType;
-
- protected WOImage() {
- super();
- }
-
- public WOImage(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
-
- public void setSrc(String value) {
- src = value;
- }
- public String src() {
- return src;
- }
-
- public void setFilename(String value) {
- filename = value;
- }
-
- public String filename() {
- return filename;
- }
-
- public void setFramework(String value) {
- framework = value;
- }
- public String framework() {
- return framework;
- }
-
- public void setData(NSData value) {
- data = value;
- }
- public NSData data() {
- return data;
- }
-
- public void setMimeType(String value) {
- mimeType = value;
- }
- public String mimeType() {
- return mimeType();
- }
-
- public String sourceURL(WOContext c) {
- if (associations.objectForKey("src") != null)
- return (String)valueForProperty("src", c.component());
- if (associations.objectForKey("data") != null) {
- return c.componentActionURL();
- }
- if (associations.objectForKey("filename") != null) {
- WOComponent component = c.component();
-
- String framework = stringForProperty("framework", component);
- String filename = stringForProperty( "filename", component );
- if ( filename != null && framework == null )
- {
- if ( filename.startsWith("/" ) )
- {
- int i = filename.lastIndexOf( "/" );
- if ( i > 0 )
- {
- framework = filename.substring( 0, i );
- if ( i < filename.length() )
- {
- filename = filename.substring( i+1 );
- }
- }
- }
- else
- {
- // just until we figure out how we're handling bundles/localization
- framework = component.frameworkName();
- if ( framework != null )
- {
- framework = framework + '/' + component.name() + ".wo";
- }
- else
- {
- framework = '/' + component.name() + ".wo";
- }
- }
- }
- return WOApplication.application().resourceManager().urlForResourceNamed(
- filename, framework, c.request().browserLanguages(), c.request() );
- }
- return "NO SOURCE";
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString("<IMG SRC=\"");
- r.appendContentString(sourceURL(c));
- r.appendContentString("\"");
- r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "src", "filename", "framework", "data", "mimeType" })));
- r.appendContentString(">");
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- if (c.senderID().equals(c.elementID())) {
- Object data = valueForProperty("data", c.component());
- if (data instanceof byte[]) data = new NSData( (byte[]) data );
- if (data instanceof NSData) {
- String mt = stringForProperty("mimeType", c.component());
- if (mt == null)
- throw new IllegalArgumentException("WOImage: No mimeType specified for data.");
- WOResponse img = new WOResponse();
- img.setContent((NSData)data);
- img.setHeader(mt, "content-type");
- return img;
- } else if (filename() != null) {
- //will this thing use frameworks, or regular JAR files with resources?
- // mp: both/either, depending on which resource manager implementation
- }
- }
- return null;
- }
+ protected String src;
+ protected String filename;
+ protected String framework;
+ protected NSData data;
+ protected String mimeType;
+
+ protected WOImage() {
+ super();
+ }
+
+ public WOImage(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
+
+ public void setSrc(String value) {
+ src = value;
+ }
+
+ public String src() {
+ return src;
+ }
+
+ public void setFilename(String value) {
+ filename = value;
+ }
+
+ public String filename() {
+ return filename;
+ }
+
+ public void setFramework(String value) {
+ framework = value;
+ }
+
+ public String framework() {
+ return framework;
+ }
+
+ public void setData(NSData value) {
+ data = value;
+ }
+
+ public NSData data() {
+ return data;
+ }
+
+ public void setMimeType(String value) {
+ mimeType = value;
+ }
+
+ public String mimeType() {
+ return mimeType();
+ }
+
+ public String sourceURL(WOContext c) {
+ if (associations.objectForKey("src") != null)
+ return (String) valueForProperty("src", c.component());
+ if (associations.objectForKey("data") != null) {
+ return c.componentActionURL();
+ }
+ if (associations.objectForKey("filename") != null) {
+ WOComponent component = c.component();
+
+ String framework = stringForProperty("framework", component);
+ String filename = stringForProperty("filename", component);
+ if (filename != null && framework == null) {
+ if (filename.startsWith("/")) {
+ int i = filename.lastIndexOf("/");
+ if (i > 0) {
+ framework = filename.substring(0, i);
+ if (i < filename.length()) {
+ filename = filename.substring(i + 1);
+ }
+ }
+ } else {
+ // just until we figure out how we're handling bundles/localization
+ framework = component.frameworkName();
+ if (framework != null) {
+ framework = framework + '/' + component.name() + ".wo";
+ } else {
+ framework = '/' + component.name() + ".wo";
+ }
+ }
+ }
+ return WOApplication.application().resourceManager().urlForResourceNamed(filename, framework,
+ c.request().browserLanguages(), c.request());
+ }
+ return "NO SOURCE";
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<IMG SRC=\"");
+ r.appendContentString(sourceURL(c));
+ r.appendContentString("\"");
+ r.appendContentString(additionalHTMLProperties(c.component(),
+ new NSArray(new Object[] { "src", "filename", "framework", "data", "mimeType" })));
+ r.appendContentString(">");
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ if (c.senderID().equals(c.elementID())) {
+ Object data = valueForProperty("data", c.component());
+ if (data instanceof byte[])
+ data = new NSData((byte[]) data);
+ if (data instanceof NSData) {
+ String mt = stringForProperty("mimeType", c.component());
+ if (mt == null)
+ throw new IllegalArgumentException("WOImage: No mimeType specified for data.");
+ WOResponse img = new WOResponse();
+ img.setContent((NSData) data);
+ img.setHeader(mt, "content-type");
+ return img;
+ } else if (filename() != null) {
+ // will this thing use frameworks, or regular JAR files with resources?
+ // mp: both/either, depending on which resource manager implementation
+ }
+ }
+ return null;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImageButton.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImageButton.java
index 7c9f22e..ebb9ae1 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImageButton.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImageButton.java
@@ -5,17 +5,21 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
/**
- * WOImageButton renders a dynamically generated IMG tag or an INPUT tag, depending on whether the
- * element is inside a WOForm (in which case an INPUT of type IMAGE is generated) or not (in which
- * case the equivalent of a WOActiveImage)
+ * WOImageButton renders a dynamically generated IMG tag or an INPUT tag,
+ * depending on whether the element is inside a WOForm (in which case an INPUT
+ * of type IMAGE is generated) or not (in which case the equivalent of a
+ * WOActiveImage)
*
* Bindings are:
* <UL>
* <LI>src: A static URL for the image source.</li>
- * <li>data: A NSData object with the image content. Must be used with mimeType.</li>
- * <li>mimeType: The MIME type for the image data. Can be used with filename or data bindings.</li>
+ * <li>data: A NSData object with the image content. Must be used with
+ * mimeType.</li>
+ * <li>mimeType: The MIME type for the image data. Can be used with filename or
+ * data bindings.</li>
* <li>filename: The path to a file containing an image.</li>
- * <li>framework: The framework where the image should be retrieved from (used in conjunction with filename).</li>
+ * <li>framework: The framework where the image should be retrieved from (used
+ * in conjunction with filename).</li>
*
* @author ezamudio@nasoft.com
* @author $Author: cgruber $
@@ -23,36 +27,36 @@ import net.wotonomy.foundation.NSDictionary;
*/
public class WOImageButton extends WOImage {
- protected WOImageButton() {
- super();
- }
-
- public WOImageButton(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
-
- public String buttonName(WOContext c) {
- String x = (String)valueForProperty("name", c.component());
- if (x != null)
- return x;
- return c.elementID();
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- if (c.isInForm()) {
- //generate an INPUT
- r.appendContentString("<INPUT TYPE=IMAGE NAME=\"");
- r.appendContentString(buttonName(c));
- r.appendContentString("\" SRC=\"");
- r.appendContentString(sourceURL(c));
- r.appendContentString("\"");
- r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "name", "action", "src", "filename", "framework", "data", "mimeType" })));
- r.appendContentString(">");
- } else {
- //generate a WOActiveImage
- new WOActiveImage(name, associations, rootElement).appendToResponse(r, c);
- }
- }
+ protected WOImageButton() {
+ super();
+ }
+
+ public WOImageButton(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
+
+ public String buttonName(WOContext c) {
+ String x = (String) valueForProperty("name", c.component());
+ if (x != null)
+ return x;
+ return c.elementID();
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ if (c.isInForm()) {
+ // generate an INPUT
+ r.appendContentString("<INPUT TYPE=IMAGE NAME=\"");
+ r.appendContentString(buttonName(c));
+ r.appendContentString("\" SRC=\"");
+ r.appendContentString(sourceURL(c));
+ r.appendContentString("\"");
+ r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(
+ new Object[] { "name", "action", "src", "filename", "framework", "data", "mimeType" })));
+ r.appendContentString(">");
+ } else {
+ // generate a WOActiveImage
+ new WOActiveImage(name, associations, rootElement).appendToResponse(r, c);
+ }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOInput.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOInput.java
index a8c7daa..ddcdb9e 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOInput.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOInput.java
@@ -10,74 +10,75 @@ import net.wotonomy.foundation.NSMutableArray;
public abstract class WOInput extends WODynamicElement {
- public WOInput() {
- super();
- }
-
- public WOInput(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
-
- protected abstract String inputType();
- protected abstract Object value(WOContext c);
-
- protected NSMutableArray additionalAttributes() {
- return new NSMutableArray(new Object[]{
- "disabled", "type", "value", "name"
- });
- }
-
- public String inputName(WOContext c) {
- String x = (String)valueForProperty("name", c.component());
- if (x != null)
- return x;
- return c.elementID();
- }
-
- protected boolean disabled(WOContext c) {
- return booleanForProperty("disabled", c.component());
- }
-
- protected void appendExtras(WOResponse r, WOContext c) {
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString("<INPUT TYPE=\"");
- r.appendContentString(inputType());
- r.appendContentString("\" NAME=\"");
- r.appendContentString(inputName(c));
- r.appendContentString("\" VALUE=\"");
- r.appendContentString(value(c).toString());
- r.appendContentString("\"");
- String moreFields = additionalHTMLProperties(c.component(), additionalAttributes());
- if (moreFields != null && moreFields.length() > 0)
- r.appendContentString(moreFields);
- appendExtras(r, c);
- if (disabled(c)) {
- r.appendContentString(" DISABLED");
- }
- r.appendContentString(">");
- }
-
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- if (disabled(c))
- return;
- Object val = r.formValueForKey(inputName(c));
- WOAssociation va = (WOAssociation)associations.objectForKey("value");
- if (val != null && va != null && va.isValueSettable())
- setValueForProperty("value", val, c.component());
- }
-
- /** Formats a value as a date or number. Checks for
- * numberformat or dateformat associations; if one of them
- * exists, the value is formatter using the specified pattern.
+ public WOInput() {
+ super();
+ }
+
+ public WOInput(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
+
+ protected abstract String inputType();
+
+ protected abstract Object value(WOContext c);
+
+ protected NSMutableArray additionalAttributes() {
+ return new NSMutableArray(new Object[] { "disabled", "type", "value", "name" });
+ }
+
+ public String inputName(WOContext c) {
+ String x = (String) valueForProperty("name", c.component());
+ if (x != null)
+ return x;
+ return c.elementID();
+ }
+
+ protected boolean disabled(WOContext c) {
+ return booleanForProperty("disabled", c.component());
+ }
+
+ protected void appendExtras(WOResponse r, WOContext c) {
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<INPUT TYPE=\"");
+ r.appendContentString(inputType());
+ r.appendContentString("\" NAME=\"");
+ r.appendContentString(inputName(c));
+ r.appendContentString("\" VALUE=\"");
+ r.appendContentString(value(c).toString());
+ r.appendContentString("\"");
+ String moreFields = additionalHTMLProperties(c.component(), additionalAttributes());
+ if (moreFields != null && moreFields.length() > 0)
+ r.appendContentString(moreFields);
+ appendExtras(r, c);
+ if (disabled(c)) {
+ r.appendContentString(" DISABLED");
+ }
+ r.appendContentString(">");
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ if (disabled(c))
+ return;
+ Object val = r.formValueForKey(inputName(c));
+ WOAssociation va = (WOAssociation) associations.objectForKey("value");
+ if (val != null && va != null && va.isValueSettable())
+ setValueForProperty("value", val, c.component());
+ }
+
+ /**
+ * Formats a value as a date or number. Checks for numberformat or dateformat
+ * associations; if one of them exists, the value is formatter using the
+ * specified pattern.
+ *
* @param value The value to format.
- * @return The original object, or a date or number if the
- * receiver has a numberformat or dateformat association.
+ * @return The original object, or a date or number if the receiver has a
+ * numberformat or dateformat association.
*/
protected Object formattedValue(Object value, WOComponent c) {
- //Format the value in case of number
- String pattern = (String)valueForProperty("numberformat", c);
+ // Format the value in case of number
+ String pattern = (String) valueForProperty("numberformat", c);
if (pattern != null) {
DecimalFormat fmt = new DecimalFormat(pattern);
try {
@@ -86,8 +87,8 @@ public abstract class WOInput extends WODynamicElement {
return value;
}
}
- //Format the value in case of date
- pattern = (String)valueForProperty("dateformat", c);
+ // Format the value in case of date
+ pattern = (String) valueForProperty("dateformat", c);
if (pattern != null) {
SimpleDateFormat fmt = new SimpleDateFormat(pattern);
try {
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMailDelivery.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMailDelivery.java
index eccc489..69939f9 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMailDelivery.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMailDelivery.java
@@ -21,34 +21,30 @@ package net.wotonomy.web;
import java.util.List;
/**
-* A pure java implementation of WOMailDelivery.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public abstract class WOMailDelivery
-{
+ * A pure java implementation of WOMailDelivery.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public abstract class WOMailDelivery {
private static WOMailDelivery sharedInstance;
-
- protected WOMailDelivery ()
- {
- }
-
- public static WOMailDelivery sharedInstance ()
- {
- if ( sharedInstance == null )
- {
+
+ protected WOMailDelivery() {
+ }
+
+ public static WOMailDelivery sharedInstance() {
+ if (sharedInstance == null) {
// sharedInstance = new WOMailDelivery();
- }
- return sharedInstance;
- }
-
- public abstract String composePlainTextEmail (
- String aSender, List aToList, List aCcList,
- String aSubject, String aMessage, boolean sendImmediately );
- public abstract String composeComponentEmail (
- String aSender, List aToList, List aCcList,
- String aSubject, WOComponent aComponent, boolean sendImmediately );
- public abstract void sendEmail (String aMailMessage);
+ }
+ return sharedInstance;
+ }
+
+ public abstract String composePlainTextEmail(String aSender, List aToList, List aCcList, String aSubject,
+ String aMessage, boolean sendImmediately);
+
+ public abstract String composeComponentEmail(String aSender, List aToList, List aCcList, String aSubject,
+ WOComponent aComponent, boolean sendImmediately);
+
+ public abstract void sendEmail(String aMailMessage);
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMessage.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMessage.java
index be76be1..f2310c2 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMessage.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMessage.java
@@ -24,12 +24,12 @@ import net.wotonomy.foundation.NSMutableData;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* A pure java implementation of WOResponse.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+ * A pure java implementation of WOResponse.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOMessage {
protected String _contentEncoding = "ISO8859_1";
@@ -43,291 +43,233 @@ public class WOMessage {
}
/**
- * Sets the content encoding for the response.
- */
- public void setContentEncoding (String encoding)
- {
+ * Sets the content encoding for the response.
+ */
+ public void setContentEncoding(String encoding) {
_contentEncoding = encoding;
}
/**
- * Gets the current content encoding for the response.
- */
- public String contentEncoding () {
+ * Gets the current content encoding for the response.
+ */
+ public String contentEncoding() {
return _contentEncoding;
- }
+ }
/**
- * Sets the specified array of values as headers under
- * the specified key.
- */
- public void setHeaders (NSArray headerArray, String aKey) {
- _headers.setObjectForKey( headerArray, aKey );
+ * Sets the specified array of values as headers under the specified key.
+ */
+ public void setHeaders(NSArray headerArray, String aKey) {
+ _headers.setObjectForKey(headerArray, aKey);
}
/**
- * Sets the specified header value for the specified key.
- */
- public void setHeader (String aValue, String aKey) {
- _headers.setObjectForKey( new NSArray( aValue ), aKey );
+ * Sets the specified header value for the specified key.
+ */
+ public void setHeader(String aValue, String aKey) {
+ _headers.setObjectForKey(new NSArray(aValue), aKey);
}
/**
- * Returns an array of all the header keys that have been
- * set in the response.
- */
- public NSArray headerKeys () {
+ * Returns an array of all the header keys that have been set in the response.
+ */
+ public NSArray headerKeys() {
return _headers.allKeys();
}
/**
- * Returns an array of all the header values for the specified key,
- * or null if the key does not exist.
- */
- public NSArray headersForKey (String aKey) {
- return (NSArray)_headers.objectForKey( aKey );
+ * Returns an array of all the header values for the specified key, or null if
+ * the key does not exist.
+ */
+ public NSArray headersForKey(String aKey) {
+ return (NSArray) _headers.objectForKey(aKey);
}
/**
- * Returns one header value for the specified key.
- * Provided as a convenience, since most header keys
- * will have a single value.
- */
- public String headerForKey (String aKey) {
- NSArray values = (NSArray)_headers.objectForKey( aKey );
- if ( values != null && values.count() > 0 ) {
- return values.objectAtIndex( 0 ).toString();
+ * Returns one header value for the specified key. Provided as a convenience,
+ * since most header keys will have a single value.
+ */
+ public String headerForKey(String aKey) {
+ NSArray values = (NSArray) _headers.objectForKey(aKey);
+ if (values != null && values.count() > 0) {
+ return values.objectAtIndex(0).toString();
}
return null;
}
/**
- * Sets the content of the response to the bytes represented
- * by the specified data object.
- */
+ * Sets the content of the response to the bytes represented by the specified
+ * data object.
+ */
public void setContent(NSData aData) {
- _contentData.setData( aData );
+ _contentData.setData(aData);
setHeader(Integer.toString(aData.length()), "content-length");
}
/**
- * Retrieves the current content of the response.
- */
+ * Retrieves the current content of the response.
+ */
public NSData content() {
return _contentData;
}
/**
- * Sets the current user info dictionary. These values
- * are for application-specific uses and are available to
- * other actions and components in the request-response cycle.
- */
- public void setUserInfo (NSDictionary aDict) {
- _userInfo = new NSMutableDictionary( aDict );
+ * Sets the current user info dictionary. These values are for
+ * application-specific uses and are available to other actions and components
+ * in the request-response cycle.
+ */
+ public void setUserInfo(NSDictionary aDict) {
+ _userInfo = new NSMutableDictionary(aDict);
}
/**
- * Gets the current user info dictionary. These values
- * are for application-specific uses are are available to
- * other actions and components in the request-response cycle.
- */
- public NSDictionary userInfo () {
+ * Gets the current user info dictionary. These values are for
+ * application-specific uses are are available to other actions and components
+ * in the request-response cycle.
+ */
+ public NSDictionary userInfo() {
return new NSDictionary(_userInfo);
}
/**
- * Appends the bytes in the specified data object to the response.
- */
- public void appendContentData (NSData aData)
- {
- _contentData.appendData( aData );
+ * Appends the bytes in the specified data object to the response.
+ */
+ public void appendContentData(NSData aData) {
+ _contentData.appendData(aData);
setHeader(Integer.toString(_contentData.length()), "content-length");
}
/**
- * Appends the specified byte to the response.
- */
- public void appendContentCharacter (char character) {
- _contentData.appendByte((byte)character);
+ * Appends the specified byte to the response.
+ */
+ public void appendContentCharacter(char character) {
+ _contentData.appendByte((byte) character);
setHeader(Integer.toString(_contentData.length()), "content-length");
}
/**
- * Appends the specified string to the response.
- * Any special characters will not be escaped.
- * The string will be encoded in the current content encoding.
- */
- public void appendContentString (String aString)
- {
- _contentData.appendData( new NSData( aString.getBytes() ) );
+ * Appends the specified string to the response. Any special characters will not
+ * be escaped. The string will be encoded in the current content encoding.
+ */
+ public void appendContentString(String aString) {
+ _contentData.appendData(new NSData(aString.getBytes()));
setHeader(Integer.toString(_contentData.length()), "content-length");
}
/**
- * Appends the specified string containing HTML to the response.
- * Any special characters will be escaped appropriately.
- * The string will be encoded in the current content encoding.
- */
- public void appendContentHTMLString (String aString)
- {
- _contentData.appendData(
- new NSData( stringByEscapingHTMLString(
- aString ).getBytes() ) );
+ * Appends the specified string containing HTML to the response. Any special
+ * characters will be escaped appropriately. The string will be encoded in the
+ * current content encoding.
+ */
+ public void appendContentHTMLString(String aString) {
+ _contentData.appendData(new NSData(stringByEscapingHTMLString(aString).getBytes()));
setHeader(Integer.toString(_contentData.length()), "content-length");
}
/**
- * Appends the specified string containing HTML to the response.
- * Any special characters will be escaped appropriately.
- * This method escapes tabs and new-line characters as well.
- * The string will be encoded in the current content encoding.
- */
- public void appendContentHTMLAttributeValue (String aString)
- {
- _contentData.appendData (
- new NSData( stringByEscapingHTMLAttributeValue(
- aString ).getBytes() ) );
+ * Appends the specified string containing HTML to the response. Any special
+ * characters will be escaped appropriately. This method escapes tabs and
+ * new-line characters as well. The string will be encoded in the current
+ * content encoding.
+ */
+ public void appendContentHTMLAttributeValue(String aString) {
+ _contentData.appendData(new NSData(stringByEscapingHTMLAttributeValue(aString).getBytes()));
setHeader(Integer.toString(_contentData.length()), "content-length");
}
/**
- * Adds the specified cookie to the response.
- */
- public void addCookie (WOCookie aCookie)
- {
- _cookies.setObjectForKey( aCookie, aCookie.name() );
+ * Adds the specified cookie to the response.
+ */
+ public void addCookie(WOCookie aCookie) {
+ _cookies.setObjectForKey(aCookie, aCookie.name());
}
/**
- * Removes the specified cookie from the response.
- */
- public void removeCookie (WOCookie aCookie)
- {
- _cookies.removeObjectForKey( aCookie.name() );
+ * Removes the specified cookie from the response.
+ */
+ public void removeCookie(WOCookie aCookie) {
+ _cookies.removeObjectForKey(aCookie.name());
}
/**
- * Returns an array of cookies currently being sent with the response.
- * Contains whatever cookies have previously been set in this response.
- */
- public NSArray cookies ()
- {
- return _cookies.allValues();
+ * Returns an array of cookies currently being sent with the response. Contains
+ * whatever cookies have previously been set in this response.
+ */
+ public NSArray cookies() {
+ return _cookies.allValues();
}
/**
- * Sets the HTTP version header in the response.
- */
- public void setHTTPVersion (String aString)
- {
- setHeader( aString, "Protocol");
+ * Sets the HTTP version header in the response.
+ */
+ public void setHTTPVersion(String aString) {
+ setHeader(aString, "Protocol");
}
/**
- * Gets the current HTTP version header for the response.
- * Because servlet responses do not allow read access
- * to headers, this method returns null if setHTTPVersion
- * has not been called.
- */
- public String httpVersion ()
- {
- return headerForKey( "Protocol" );
+ * Gets the current HTTP version header for the response. Because servlet
+ * responses do not allow read access to headers, this method returns null if
+ * setHTTPVersion has not been called.
+ */
+ public String httpVersion() {
+ return headerForKey("Protocol");
}
/**
- * Returns a sting containing the contents of the specified
- * string after escaping all special HTML characters.
- */
- public static String stringByEscapingHTMLString
- (String aString)
- {
+ * Returns a sting containing the contents of the specified string after
+ * escaping all special HTML characters.
+ */
+ public static String stringByEscapingHTMLString(String aString) {
int len = aString.length();
StringBuffer result = new StringBuffer();
- char[] buf = new char[ len ];
- aString.getChars( 0, len, buf, 0 );
- for ( int i = 0; i < len; i++ )
- {
- if ( buf[i] == '&' )
- {
- result.append( "&amp;" );
- }
- else
- if ( buf[i] == '\\' )
- {
- result.append( "&quot;" );
- }
- else
- if ( buf[i] == '<' )
- {
- result.append( "&lt;" );
+ char[] buf = new char[len];
+ aString.getChars(0, len, buf, 0);
+ for (int i = 0; i < len; i++) {
+ if (buf[i] == '&') {
+ result.append("&amp;");
+ } else if (buf[i] == '\\') {
+ result.append("&quot;");
+ } else if (buf[i] == '<') {
+ result.append("&lt;");
+ } else if (buf[i] == '>') {
+ result.append("&gt;");
+ } else {
+ result.append(buf[i]);
}
- else
- if ( buf[i] == '>' )
- {
- result.append( "&gt;" );
- }
- else
- {
- result.append( buf[i] );
- }
- }
- return result.toString();
+ }
+ return result.toString();
}
-
+
/**
- * Returns a sting containing the contents of the specified
- * string after escaping all special HTML characters.
- * This method escapes tabs and new-line characters as well.
- */
- public static String stringByEscapingHTMLAttributeValue
- (String aString)
- {
+ * Returns a sting containing the contents of the specified string after
+ * escaping all special HTML characters. This method escapes tabs and new-line
+ * characters as well.
+ */
+ public static String stringByEscapingHTMLAttributeValue(String aString) {
int len = aString.length();
StringBuffer result = new StringBuffer();
- char[] buf = new char[ len ];
- aString.getChars( 0, len, buf, 0 );
- for ( int i = 0; i < len; i++ )
- {
- if ( buf[i] == '&' )
- {
- result.append( "&amp;" );
+ char[] buf = new char[len];
+ aString.getChars(0, len, buf, 0);
+ for (int i = 0; i < len; i++) {
+ if (buf[i] == '&') {
+ result.append("&amp;");
+ } else if (buf[i] == '\\') {
+ result.append("&quot;");
+ } else if (buf[i] == '<') {
+ result.append("&lt;");
+ } else if (buf[i] == '>') {
+ result.append("&gt;");
+ } else if (buf[i] == '\t') {
+ result.append("&#9;");
+ } else if (buf[i] == '\n') {
+ result.append("&#10;");
+ } else if (buf[i] == '\r') {
+ result.append("&#13;");
+ } else {
+ result.append(buf[i]);
}
- else
- if ( buf[i] == '\\' )
- {
- result.append( "&quot;" );
- }
- else
- if ( buf[i] == '<' )
- {
- result.append( "&lt;" );
- }
- else
- if ( buf[i] == '>' )
- {
- result.append( "&gt;" );
- }
- else
- if ( buf[i] == '\t' )
- {
- result.append( "&#9;" );
- }
- else
- if ( buf[i] == '\n' )
- {
- result.append( "&#10;" );
- }
- else
- if ( buf[i] == '\r' )
- {
- result.append( "&#13;" );
- }
- else
- {
- result.append( buf[i] );
- }
- }
- return result.toString();
+ }
+ return result.toString();
}
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOParentElement.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOParentElement.java
index 40ee618..cf84b17 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOParentElement.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOParentElement.java
@@ -24,155 +24,137 @@ import java.util.List;
import net.wotonomy.foundation.NSMutableArray;
/**
-* This class represents a parent node in an element tree.
-* It has no content in itself, and exists only to forward
-* messages to each of its children, in turn.
-* Package access only, as it is not in the specification.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-class WOParentElement extends WOElement
-{
+ * This class represents a parent node in an element tree. It has no content in
+ * itself, and exists only to forward messages to each of its children, in turn.
+ * Package access only, as it is not in the specification.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+class WOParentElement extends WOElement {
NSMutableArray children;
/**
- * Default constructor.
- */
- public WOParentElement()
- {
+ * Default constructor.
+ */
+ public WOParentElement() {
children = new NSMutableArray();
}
-
+
/**
- * Returns an element with the specified children.
- */
- public WOParentElement( List childElements )
- {
+ * Returns an element with the specified children.
+ */
+ public WOParentElement(List childElements) {
this();
- children.addAll( childElements );
+ children.addAll(childElements);
}
-
- /**
- * Package access only. Called to initialize the component with
- * the proper context before the start of the request-response cycle.
- * If the context has a current component, that component becomes
- * this component's parent.
- */
- void ensureAwakeInContext (WOContext aContext)
- {
- WOElement element;
- Iterator it = children.iterator();
- while ( it.hasNext() )
- {
- element = (WOElement) it.next();
- aContext.pushElement( element );
- element.ensureAwakeInContext( aContext );
- aContext.popElement();
- }
- }
/**
- * Forwards this message to all child elements.
- */
- public void takeValuesFromRequest (
- WORequest aRequest, WOContext aContext)
- {
- WOElement element;
-
+ * Package access only. Called to initialize the component with the proper
+ * context before the start of the request-response cycle. If the context has a
+ * current component, that component becomes this component's parent.
+ */
+ void ensureAwakeInContext(WOContext aContext) {
+ WOElement element;
+ Iterator it = children.iterator();
+ while (it.hasNext()) {
+ element = (WOElement) it.next();
+ aContext.pushElement(element);
+ element.ensureAwakeInContext(aContext);
+ aContext.popElement();
+ }
+ }
+
+ /**
+ * Forwards this message to all child elements.
+ */
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ WOElement element;
+
// aContext.incrementLastElementIDComponent();
- aContext.appendZeroElementIDComponent();
-
- Iterator it = children.iterator();
- while ( it.hasNext() )
- {
- element = (WOElement) it.next();
- aContext.pushElement( element );
- aContext.incrementLastElementIDComponent();
- element.takeValuesFromRequest( aRequest, aContext );
- aContext.popElement();
- }
-
- aContext.deleteLastElementIDComponent();
- }
-
- /**
- * Forwards this message to all child elements,
- * returning the first non-null result.
- */
- public WOActionResults invokeAction (
- WORequest aRequest, WOContext aContext)
- {
- WOElement element;
-
+ aContext.appendZeroElementIDComponent();
+
+ Iterator it = children.iterator();
+ while (it.hasNext()) {
+ element = (WOElement) it.next();
+ aContext.pushElement(element);
+ aContext.incrementLastElementIDComponent();
+ element.takeValuesFromRequest(aRequest, aContext);
+ aContext.popElement();
+ }
+
+ aContext.deleteLastElementIDComponent();
+ }
+
+ /**
+ * Forwards this message to all child elements, returning the first non-null
+ * result.
+ */
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ WOElement element;
+
// aContext.incrementLastElementIDComponent();
- aContext.appendZeroElementIDComponent();
-
- WOActionResults result = null;
- Iterator it = children.iterator();
- while ( it.hasNext() )
- {
- element = (WOElement) it.next();
- aContext.pushElement( element );
- aContext.incrementLastElementIDComponent();
- result = element.invokeAction( aRequest, aContext );
- aContext.popElement();
- if ( result != null ) break;
- }
-
- aContext.deleteLastElementIDComponent();
- return result;
- }
-
- /**
- * Forwards this message to all child elements.
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- WOElement element;
-
+ aContext.appendZeroElementIDComponent();
+
+ WOActionResults result = null;
+ Iterator it = children.iterator();
+ while (it.hasNext()) {
+ element = (WOElement) it.next();
+ aContext.pushElement(element);
+ aContext.incrementLastElementIDComponent();
+ result = element.invokeAction(aRequest, aContext);
+ aContext.popElement();
+ if (result != null)
+ break;
+ }
+
+ aContext.deleteLastElementIDComponent();
+ return result;
+ }
+
+ /**
+ * Forwards this message to all child elements.
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ WOElement element;
+
// aContext.incrementLastElementIDComponent();
- aContext.appendZeroElementIDComponent();
-
- // for each child element
- Iterator it = children.iterator();
- while ( it.hasNext() )
- {
- element = (WOElement) it.next();
- aContext.pushElement( element );
- aContext.incrementLastElementIDComponent();
-
- // forward the message
- element.appendToResponse(
- aResponse, aContext );
-
- aContext.popElement();
-
- }
- aContext.deleteLastElementIDComponent();
- }
-
- public WOResponse generateResponse()
- {
- WOResponse r = new WOResponse();
- return r;
- }
-
- public String toString()
- {
- StringBuffer result = new StringBuffer();
- result.append( "[WOParentElement: " );
- // for each child element
- Iterator it = children.iterator();
- while ( it.hasNext() )
- {
- result.append( "[ " );
- result.append( it.next().toString() );
- result.append( " ]" );
- }
- result.append( " ]" );
- return result.toString();
- }
-
+ aContext.appendZeroElementIDComponent();
+
+ // for each child element
+ Iterator it = children.iterator();
+ while (it.hasNext()) {
+ element = (WOElement) it.next();
+ aContext.pushElement(element);
+ aContext.incrementLastElementIDComponent();
+
+ // forward the message
+ element.appendToResponse(aResponse, aContext);
+
+ aContext.popElement();
+
+ }
+ aContext.deleteLastElementIDComponent();
+ }
+
+ public WOResponse generateResponse() {
+ WOResponse r = new WOResponse();
+ return r;
+ }
+
+ public String toString() {
+ StringBuffer result = new StringBuffer();
+ result.append("[WOParentElement: ");
+ // for each child element
+ Iterator it = children.iterator();
+ while (it.hasNext()) {
+ result.append("[ ");
+ result.append(it.next().toString());
+ result.append(" ]");
+ }
+ result.append(" ]");
+ return result.toString();
+ }
+
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPasswordField.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPasswordField.java
index 2d4f16e..4d81fe0 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPasswordField.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPasswordField.java
@@ -5,16 +5,16 @@ import net.wotonomy.foundation.NSDictionary;
public class WOPasswordField extends WOTextField {
- public WOPasswordField() {
- super();
- }
+ public WOPasswordField() {
+ super();
+ }
- public WOPasswordField(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
+ public WOPasswordField(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
- protected String inputType() {
- return "PASSWORD";
- }
+ protected String inputType() {
+ return "PASSWORD";
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPopUpButton.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPopUpButton.java
index a73636c..a40c828 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPopUpButton.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPopUpButton.java
@@ -7,129 +7,132 @@ import net.wotonomy.foundation.NSKeyValueCodingAdditions;
public class WOPopUpButton extends WOInput {
- public WOPopUpButton() {
- super();
- }
-
- public WOPopUpButton(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
-
- protected String inputType() {
- return "SELECT";
- }
-
- protected int inputSize() {
- return 1;
- }
-
- protected NSArray list(WOContext c) {
- NSArray l = (NSArray)valueForProperty("list", c.component());
- if (l == null)
- l = NSArray.EmptyArray;
- return l;
- }
-
- protected void setItem(Object v, WOContext c) {
- if (associations.objectForKey("item") == null)
- return;
- setValueForProperty("item", v, c.component());
- }
- protected Object item(WOContext c) {
- return valueForProperty("item", c.component());
- }
-
- protected void setSelection(Object v, WOContext c) {
- if (associations.objectForKey("selection") == null)
- return;
- setValueForProperty("selection", v, c.component());
- }
- protected Object selection(WOContext c) {
- return valueForProperty("selection", c.component());
- }
-
- public Object value(WOContext c) {
- return null;
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString("<SELECT NAME=\"");
- r.appendContentString(inputName(c));
- r.appendContentString("\" SIZE=");
- r.appendContentString(Integer.toString(inputSize()));
- r.appendContentString(">");
- java.util.Enumeration numerador = list(c).objectEnumerator();
- String displayKey = stringForProperty("displayString", c.component());
- String valueKey = stringForProperty("value", c.component());
- Object sel = selection(c);
- if (sel == null)
- sel = item(c);
- int pos = 0;
- while (numerador.hasMoreElements()) {
- Object item = numerador.nextElement();
- setItem(item, c);
- r.appendContentString("<OPTION ");
- //Append the "SELECTED" attribute if it's the selected item
- if (sel != null && item.equals(sel))
- r.appendContentString("SELECTED ");
- r.appendContentString("VALUE=\"");
- //Append the value
- if (valueKey != null && item instanceof NSKeyValueCodingAdditions) {
- Object val = ((NSKeyValueCodingAdditions)item).valueForKeyPath(valueKey);
- if (val == null)
- val = "null";
- r.appendContentString(val.toString());
- } else
- r.appendContentString(Integer.toString(pos));
- r.appendContentString("\">");
- //Append display string
- if (displayKey != null && item instanceof NSKeyValueCodingAdditions) {
- Object ds = ((NSKeyValueCodingAdditions)item).valueForKeyPath(displayKey);
- if (ds == null)
- ds = "";
- r.appendContentString(ds.toString());
- } else
- r.appendContentString(item.toString());
- r.appendContentString("\n");
- pos++;
- }
- r.appendContentString("</SELECT>");
- }
-
- protected void select(Object v, WOContext c) {
- if (associations.objectForKey("selection") != null) {
- setSelection(v, c);
- return;
- }
- if (associations.objectForKey("item") != null) {
- setItem(v,c);
- }
- }
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- Object val = r.formValueForKey(inputName(c));
- if (val == null)
- return;
- NSArray list = list(c);
- String valueKey = stringForProperty("value", c.component());
- //If no value binding, just get the index
- if (valueKey == null) {
- int pos = Integer.parseInt(val.toString());
- val = list.objectAtIndex(pos);
- select(val, c);
- return;
- }
- //If value binding is present, lookup the value
- java.util.Enumeration numerador = list.objectEnumerator();
- while (numerador.hasMoreElements()) {
- Object o = numerador.nextElement();
- if (o instanceof NSKeyValueCodingAdditions) {
- Object x = ((NSKeyValueCodingAdditions)o).valueForKeyPath(valueKey);
- if (x != null && x.equals(val)) {
- select(o, c);
- return;
- }
- }
- }
- }
+ public WOPopUpButton() {
+ super();
+ }
+
+ public WOPopUpButton(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
+
+ protected String inputType() {
+ return "SELECT";
+ }
+
+ protected int inputSize() {
+ return 1;
+ }
+
+ protected NSArray list(WOContext c) {
+ NSArray l = (NSArray) valueForProperty("list", c.component());
+ if (l == null)
+ l = NSArray.EmptyArray;
+ return l;
+ }
+
+ protected void setItem(Object v, WOContext c) {
+ if (associations.objectForKey("item") == null)
+ return;
+ setValueForProperty("item", v, c.component());
+ }
+
+ protected Object item(WOContext c) {
+ return valueForProperty("item", c.component());
+ }
+
+ protected void setSelection(Object v, WOContext c) {
+ if (associations.objectForKey("selection") == null)
+ return;
+ setValueForProperty("selection", v, c.component());
+ }
+
+ protected Object selection(WOContext c) {
+ return valueForProperty("selection", c.component());
+ }
+
+ public Object value(WOContext c) {
+ return null;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<SELECT NAME=\"");
+ r.appendContentString(inputName(c));
+ r.appendContentString("\" SIZE=");
+ r.appendContentString(Integer.toString(inputSize()));
+ r.appendContentString(">");
+ java.util.Enumeration numerador = list(c).objectEnumerator();
+ String displayKey = stringForProperty("displayString", c.component());
+ String valueKey = stringForProperty("value", c.component());
+ Object sel = selection(c);
+ if (sel == null)
+ sel = item(c);
+ int pos = 0;
+ while (numerador.hasMoreElements()) {
+ Object item = numerador.nextElement();
+ setItem(item, c);
+ r.appendContentString("<OPTION ");
+ // Append the "SELECTED" attribute if it's the selected item
+ if (sel != null && item.equals(sel))
+ r.appendContentString("SELECTED ");
+ r.appendContentString("VALUE=\"");
+ // Append the value
+ if (valueKey != null && item instanceof NSKeyValueCodingAdditions) {
+ Object val = ((NSKeyValueCodingAdditions) item).valueForKeyPath(valueKey);
+ if (val == null)
+ val = "null";
+ r.appendContentString(val.toString());
+ } else
+ r.appendContentString(Integer.toString(pos));
+ r.appendContentString("\">");
+ // Append display string
+ if (displayKey != null && item instanceof NSKeyValueCodingAdditions) {
+ Object ds = ((NSKeyValueCodingAdditions) item).valueForKeyPath(displayKey);
+ if (ds == null)
+ ds = "";
+ r.appendContentString(ds.toString());
+ } else
+ r.appendContentString(item.toString());
+ r.appendContentString("\n");
+ pos++;
+ }
+ r.appendContentString("</SELECT>");
+ }
+
+ protected void select(Object v, WOContext c) {
+ if (associations.objectForKey("selection") != null) {
+ setSelection(v, c);
+ return;
+ }
+ if (associations.objectForKey("item") != null) {
+ setItem(v, c);
+ }
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ Object val = r.formValueForKey(inputName(c));
+ if (val == null)
+ return;
+ NSArray list = list(c);
+ String valueKey = stringForProperty("value", c.component());
+ // If no value binding, just get the index
+ if (valueKey == null) {
+ int pos = Integer.parseInt(val.toString());
+ val = list.objectAtIndex(pos);
+ select(val, c);
+ return;
+ }
+ // If value binding is present, lookup the value
+ java.util.Enumeration numerador = list.objectEnumerator();
+ while (numerador.hasMoreElements()) {
+ Object o = numerador.nextElement();
+ if (o instanceof NSKeyValueCodingAdditions) {
+ Object x = ((NSKeyValueCodingAdditions) o).valueForKeyPath(valueKey);
+ if (x != null && x.equals(val)) {
+ select(o, c);
+ return;
+ }
+ }
+ }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORadioButton.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORadioButton.java
index 386218c..b06b052 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORadioButton.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORadioButton.java
@@ -5,16 +5,16 @@ import net.wotonomy.foundation.NSDictionary;
public class WORadioButton extends WOCheckBox {
- public WORadioButton() {
- super();
- }
+ public WORadioButton() {
+ super();
+ }
- public WORadioButton(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
+ public WORadioButton(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
- protected String inputType() {
- return "RADIO";
- }
+ protected String inputType() {
+ return "RADIO";
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORepetition.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORepetition.java
index afa118a..53615a4 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORepetition.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORepetition.java
@@ -25,155 +25,150 @@ import net.wotonomy.foundation.NSDictionary;
public class WORepetition extends WODynamicElement {
- protected int count;
- protected int index;
- protected Object item;
- protected Collection list;
- protected Iterator iterator;
-
- protected WORepetition() {
- super();
- }
-
- public WORepetition(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
-
- public void setCount(int value) {
- count = value;
- }
-
- public int count() {
- return count;
- }
-
- public void setIndex(int value) {
- index = value;
- }
- public int index() {
- return index;
- }
-
- public void setItem(Object value) {
- item = value;
- }
- public Object item() {
- return item;
- }
-
- public void setList(Collection value) {
- list = value;
- }
- public Collection list() {
- return list;
- }
-
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- c.appendZeroElementIDComponent();
- pullValuesFromParent(c.component());
- index = 0;
- WOAssociation countAsoc = (WOAssociation)associations.objectForKey("count");
- item = getNextItem();
- while (item != null) {
- pushValuesToParent(c.component());
- rootElement.takeValuesFromRequest(r, c);
- index++;
- c.incrementLastElementIDComponent();
- if (countAsoc != null && index >= count())
- item = null;
- else
- item = getNextItem();
- }
- iterator = null;
- c.deleteLastElementIDComponent();
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- c.appendZeroElementIDComponent();
- pullValuesFromParent(c.component());
- index = 0;
- WOAssociation countAsoc = (WOAssociation)associations.objectForKey("count");
- item = getNextItem();
- while (item != null) {
- pushValuesToParent(c.component());
- WOActionResults e = rootElement.invokeAction(r, c);
- if (e != null)
- {
- iterator = null;
- return e;
- }
- index++;
- c.incrementLastElementIDComponent();
- if (countAsoc != null && index >= count())
- item = null;
- else
- item = getNextItem();
- }
- iterator = null;
- c.deleteLastElementIDComponent();
- return null;
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- c.appendZeroElementIDComponent();
- pullValuesFromParent(c.component());
- index = 0;
- WOAssociation countAsoc = (WOAssociation)associations.objectForKey("count");
- item = getNextItem();
- while (item != null) {
- pushValuesToParent(c.component());
- rootElement.appendToResponse(r, c);
- index++;
- c.incrementLastElementIDComponent();
- if (countAsoc != null || index < count())
- item = null;
- else
- item = getNextItem();
- }
- iterator = null;
- c.deleteLastElementIDComponent();
- }
-
- protected Object getNextItem() {
- if ( iterator == null )
- {
- if ( list == null ) return null;
- iterator = list.iterator();
- }
- if ( iterator.hasNext() )
- {
- return iterator.next();
- }
- return null;
- }
-
- protected void pullValuesFromParent(WOComponent c) {
- Object value;
-
- value = valueForProperty("count", c);
- if ( value instanceof Number )
- {
- setCount( ((Number)value).intValue() );
- }
- else
- {
- setCount( -1 );
- }
-
- value = valueForProperty("list", c);
- if ( value instanceof Collection )
- {
- setList( (Collection) value );
- }
- else
- {
- setList( null );
- }
- }
-
- protected void pushValuesToParent(WOComponent c) {
- setValueForProperty("index", new Integer(index), c);
- setValueForProperty("item", item, c);
- }
+ protected int count;
+ protected int index;
+ protected Object item;
+ protected Collection list;
+ protected Iterator iterator;
+
+ protected WORepetition() {
+ super();
+ }
+
+ public WORepetition(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
+
+ public void setCount(int value) {
+ count = value;
+ }
+
+ public int count() {
+ return count;
+ }
+
+ public void setIndex(int value) {
+ index = value;
+ }
+
+ public int index() {
+ return index;
+ }
+
+ public void setItem(Object value) {
+ item = value;
+ }
+
+ public Object item() {
+ return item;
+ }
+
+ public void setList(Collection value) {
+ list = value;
+ }
+
+ public Collection list() {
+ return list;
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ c.appendZeroElementIDComponent();
+ pullValuesFromParent(c.component());
+ index = 0;
+ WOAssociation countAsoc = (WOAssociation) associations.objectForKey("count");
+ item = getNextItem();
+ while (item != null) {
+ pushValuesToParent(c.component());
+ rootElement.takeValuesFromRequest(r, c);
+ index++;
+ c.incrementLastElementIDComponent();
+ if (countAsoc != null && index >= count())
+ item = null;
+ else
+ item = getNextItem();
+ }
+ iterator = null;
+ c.deleteLastElementIDComponent();
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ c.appendZeroElementIDComponent();
+ pullValuesFromParent(c.component());
+ index = 0;
+ WOAssociation countAsoc = (WOAssociation) associations.objectForKey("count");
+ item = getNextItem();
+ while (item != null) {
+ pushValuesToParent(c.component());
+ WOActionResults e = rootElement.invokeAction(r, c);
+ if (e != null) {
+ iterator = null;
+ return e;
+ }
+ index++;
+ c.incrementLastElementIDComponent();
+ if (countAsoc != null && index >= count())
+ item = null;
+ else
+ item = getNextItem();
+ }
+ iterator = null;
+ c.deleteLastElementIDComponent();
+ return null;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ c.appendZeroElementIDComponent();
+ pullValuesFromParent(c.component());
+ index = 0;
+ WOAssociation countAsoc = (WOAssociation) associations.objectForKey("count");
+ item = getNextItem();
+ while (item != null) {
+ pushValuesToParent(c.component());
+ rootElement.appendToResponse(r, c);
+ index++;
+ c.incrementLastElementIDComponent();
+ if (countAsoc != null || index < count())
+ item = null;
+ else
+ item = getNextItem();
+ }
+ iterator = null;
+ c.deleteLastElementIDComponent();
+ }
+
+ protected Object getNextItem() {
+ if (iterator == null) {
+ if (list == null)
+ return null;
+ iterator = list.iterator();
+ }
+ if (iterator.hasNext()) {
+ return iterator.next();
+ }
+ return null;
+ }
+
+ protected void pullValuesFromParent(WOComponent c) {
+ Object value;
+
+ value = valueForProperty("count", c);
+ if (value instanceof Number) {
+ setCount(((Number) value).intValue());
+ } else {
+ setCount(-1);
+ }
+
+ value = valueForProperty("list", c);
+ if (value instanceof Collection) {
+ setList((Collection) value);
+ } else {
+ setList(null);
+ }
+ }
+
+ protected void pushValuesToParent(WOComponent c) {
+ setValueForProperty("index", new Integer(index), c);
+ setValueForProperty("item", item, c);
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequest.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequest.java
index 7d71223..34f7414 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequest.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequest.java
@@ -33,554 +33,479 @@ import net.wotonomy.foundation.NSMutableData;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* A pure java implementation of WORequest.
-* This implementation is backed by an HttpServletRequest,
-* and thus does not support application-specific subclassing.
-* Future implementations may remove this limitation.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WORequest extends WOResponse
-{
- HttpServletRequest request;
- private WOApplication application;
- private NSArray languages;
- private String requestHandlerKey;
- private String requestHandlerPath;
- private String pageName;
- private String contextID;
- private String senderID;
- private String defaultFormValueEncoding;
-
- /**
- * Parameterless constructor which should not be called.
- */
- public WORequest ()
- {
- throw new RuntimeException(
- "This constructor is not yet supported." );
- }
-
- /**
- * Standard constructor. Method and URL are required.
- * HeaderMap is a map of header names to arrays containing
- * one or more values. Data is the content of the request.
- * UserInfo contains application-defined paramters that get
- * passed to all objects involved in dispatching the request.
- */
- public WORequest
- (String aMethod, String aURL, String aProtocolName,
- NSDictionary headerMap, NSData aData, NSDictionary userInfo)
- {
- throw new RuntimeException(
- "This constructor is not yet supported." );
- }
-
- /**
- * The only supported constructor for this implementation.
- * This WORequest will wrap the specified servlet request.
- */
- public WORequest( HttpServletRequest aRequest, WOApplication anApplication )
- {
+ * A pure java implementation of WORequest. This implementation is backed by an
+ * HttpServletRequest, and thus does not support application-specific
+ * subclassing. Future implementations may remove this limitation.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WORequest extends WOResponse {
+ HttpServletRequest request;
+ private WOApplication application;
+ private NSArray languages;
+ private String requestHandlerKey;
+ private String requestHandlerPath;
+ private String pageName;
+ private String contextID;
+ private String senderID;
+ private String defaultFormValueEncoding;
+
+ /**
+ * Parameterless constructor which should not be called.
+ */
+ public WORequest() {
+ throw new RuntimeException("This constructor is not yet supported.");
+ }
+
+ /**
+ * Standard constructor. Method and URL are required. HeaderMap is a map of
+ * header names to arrays containing one or more values. Data is the content of
+ * the request. UserInfo contains application-defined paramters that get passed
+ * to all objects involved in dispatching the request.
+ */
+ public WORequest(String aMethod, String aURL, String aProtocolName, NSDictionary headerMap, NSData aData,
+ NSDictionary userInfo) {
+ throw new RuntimeException("This constructor is not yet supported.");
+ }
+
+ /**
+ * The only supported constructor for this implementation. This WORequest will
+ * wrap the specified servlet request.
+ */
+ public WORequest(HttpServletRequest aRequest, WOApplication anApplication) {
request = aRequest;
- application = anApplication;
-
- languages = null;
- senderID = null;
- pageName = null;
- contextID = null;
- defaultFormValueEncoding = "ISO8859_1";
- requestHandlerKey = WOApplication.directActionRequestHandlerKey();
- requestHandlerPath = request.getServletPath(); // request.getPathInfo();
- String remainder = requestHandlerPath;
- if ( requestHandlerPath == null ) requestHandlerPath = "";
- if ( requestHandlerPath.length() > 0 )
- {
- int i;
-
- // get request handler key
- i = requestHandlerPath.indexOf( "/", 1 );
- if ( i != -1 )
- {
- requestHandlerKey = requestHandlerPath.substring( 1, i );
- requestHandlerPath = requestHandlerPath.substring( i );
- }
-
- Enumeration e = requestHandlerPathArray().objectEnumerator();
- // skipping session ID for now
- if ( e.hasMoreElements() )
- {
- pageName = e.nextElement().toString();
- }
- if ( e.hasMoreElements() )
- {
- contextID = e.nextElement().toString();
- }
- if ( e.hasMoreElements() )
- {
- senderID = e.nextElement().toString();
- }
- }
- }
-
- /**
- * Returns the HTTP method of the request: "GET" or "POST",
- * or possibly "PUT".
- */
- public String method ()
- {
- return request.getMethod();
- }
-
- /**
- * Returns the Uniform Resource Identifier, which is the part
- * of the request URL after the protocol name (after the port
- * number) and before the query parameters (before the question mark).
- */
- public String uri ()
- {
- return request.getRequestURI();
- }
-
- /**
- * Returns the name of the protocol (presumably HTTP) and the
- * version used by the client as sent in the request headers.
- */
- public String httpVersion ()
- {
- return request.getProtocol();
- }
-
- /**
- * Returns an array of the header names in this request
- * in no particular order.
- */
- public NSArray headerKeys ()
- {
- return arrayFromEnumeration( request.getHeaderNames() );
- }
-
- /**
- * Returns an array of the header values for the specified key
- * in no particular order.
- */
- public NSArray headersForKey (String aString)
- {
- return arrayFromEnumeration( request.getHeaders( aString ) );
- }
-
- /**
- * Returns one value for the specified header key.
- * Provided as a convenience since most headers have
- * only one value. Returns null if not found.
- */
- public String headerForKey (String aKey)
- {
- return request.getHeader( aKey );
- }
-
- /**
- * Returns the content of the request, or null if no content.
- * The type of the content is determined by the "content-type" header.
- * On error, null is returned.
- */
- public NSData content ()
- {
- //TODO: This is broken!
- NSMutableData data = new NSMutableData();
- try
- {
- byte[] buf = new byte[ request.getContentLength() ];
- InputStream is = request.getInputStream();
-
+ application = anApplication;
+
+ languages = null;
+ senderID = null;
+ pageName = null;
+ contextID = null;
+ defaultFormValueEncoding = "ISO8859_1";
+ requestHandlerKey = WOApplication.directActionRequestHandlerKey();
+ requestHandlerPath = request.getServletPath(); // request.getPathInfo();
+ String remainder = requestHandlerPath;
+ if (requestHandlerPath == null)
+ requestHandlerPath = "";
+ if (requestHandlerPath.length() > 0) {
+ int i;
+
+ // get request handler key
+ i = requestHandlerPath.indexOf("/", 1);
+ if (i != -1) {
+ requestHandlerKey = requestHandlerPath.substring(1, i);
+ requestHandlerPath = requestHandlerPath.substring(i);
+ }
+
+ Enumeration e = requestHandlerPathArray().objectEnumerator();
+ // skipping session ID for now
+ if (e.hasMoreElements()) {
+ pageName = e.nextElement().toString();
+ }
+ if (e.hasMoreElements()) {
+ contextID = e.nextElement().toString();
+ }
+ if (e.hasMoreElements()) {
+ senderID = e.nextElement().toString();
+ }
+ }
+ }
+
+ /**
+ * Returns the HTTP method of the request: "GET" or "POST", or possibly "PUT".
+ */
+ public String method() {
+ return request.getMethod();
+ }
+
+ /**
+ * Returns the Uniform Resource Identifier, which is the part of the request URL
+ * after the protocol name (after the port number) and before the query
+ * parameters (before the question mark).
+ */
+ public String uri() {
+ return request.getRequestURI();
+ }
+
+ /**
+ * Returns the name of the protocol (presumably HTTP) and the version used by
+ * the client as sent in the request headers.
+ */
+ public String httpVersion() {
+ return request.getProtocol();
+ }
+
+ /**
+ * Returns an array of the header names in this request in no particular order.
+ */
+ public NSArray headerKeys() {
+ return arrayFromEnumeration(request.getHeaderNames());
+ }
+
+ /**
+ * Returns an array of the header values for the specified key in no particular
+ * order.
+ */
+ public NSArray headersForKey(String aString) {
+ return arrayFromEnumeration(request.getHeaders(aString));
+ }
+
+ /**
+ * Returns one value for the specified header key. Provided as a convenience
+ * since most headers have only one value. Returns null if not found.
+ */
+ public String headerForKey(String aKey) {
+ return request.getHeader(aKey);
+ }
+
+ /**
+ * Returns the content of the request, or null if no content. The type of the
+ * content is determined by the "content-type" header. On error, null is
+ * returned.
+ */
+ public NSData content() {
+ // TODO: This is broken!
+ NSMutableData data = new NSMutableData();
+ try {
+ byte[] buf = new byte[request.getContentLength()];
+ InputStream is = request.getInputStream();
+
// this is so very not efficient
int len;
- while ( ( len = is.read( buf ) ) > -1 )
- {
- // copies data twice...
- data.appendData( new NSData( buf, 0, len ) );
- }
- }
- catch ( Exception exc )
- {
+ while ((len = is.read(buf)) > -1) {
+ // copies data twice...
+ data.appendData(new NSData(buf, 0, len));
+ }
+ } catch (Exception exc) {
return null;
}
return data;
- }
-
- /**
- * Returns the application-specific userInfo dictionary.
- * This implementation returns the servlet attribute map.
- */
- public NSDictionary userInfo ()
- {
- //TODO: Test this logic.
- Object key, value;
- NSMutableDictionary info = new NSMutableDictionary();
- java.util.Enumeration e = request.getAttributeNames();
- while ( e.hasMoreElements() )
- {
- key = e.nextElement();
- value = request.getAttribute( e.nextElement().toString() );
- if ( value != null )
- {
- info.setObjectForKey( value, key );
- }
- }
- return info;
- }
-
- /**
- * Returns the items in the request handler path parsed
- * by the "/" delimiter and put into an array.
- */
- public NSArray requestHandlerPathArray ()
- {
- return NSArray.componentsSeparatedByString( requestHandlerPath(), "/" );
- }
-
- /**
- * Returns the client's preferred languages in decreasing
- * order of preference. The strings are returned in java
- * Locale format, meaning dashes (-) are converted to
- * underbars (_): see java.util.Locale.toString().
- */
- public NSArray browserLanguages ()
- {
- if ( languages == null )
- {
- languages = arrayFromEnumeration( request.getLocales() );
- }
- return languages;
- }
-
- /**
- * Returns the portion of the URI specifying the engine within which
- * this web application is running. This is important for generating
- * URLs to be used in the content of the response.
- */
- public String adaptorPrefix ()
- {
- //TODO: Test this logic.
- String name = request.getServletPath();
- return name;
-
+ }
+
+ /**
+ * Returns the application-specific userInfo dictionary. This implementation
+ * returns the servlet attribute map.
+ */
+ public NSDictionary userInfo() {
+ // TODO: Test this logic.
+ Object key, value;
+ NSMutableDictionary info = new NSMutableDictionary();
+ java.util.Enumeration e = request.getAttributeNames();
+ while (e.hasMoreElements()) {
+ key = e.nextElement();
+ value = request.getAttribute(e.nextElement().toString());
+ if (value != null) {
+ info.setObjectForKey(value, key);
+ }
+ }
+ return info;
+ }
+
+ /**
+ * Returns the items in the request handler path parsed by the "/" delimiter and
+ * put into an array.
+ */
+ public NSArray requestHandlerPathArray() {
+ return NSArray.componentsSeparatedByString(requestHandlerPath(), "/");
+ }
+
+ /**
+ * Returns the client's preferred languages in decreasing order of preference.
+ * The strings are returned in java Locale format, meaning dashes (-) are
+ * converted to underbars (_): see java.util.Locale.toString().
+ */
+ public NSArray browserLanguages() {
+ if (languages == null) {
+ languages = arrayFromEnumeration(request.getLocales());
+ }
+ return languages;
+ }
+
+ /**
+ * Returns the portion of the URI specifying the engine within which this web
+ * application is running. This is important for generating URLs to be used in
+ * the content of the response.
+ */
+ public String adaptorPrefix() {
+ // TODO: Test this logic.
+ String name = request.getServletPath();
+ return name;
+
// String uri = request.getRequestURI();
// int end = uri.indexOf( request.getPathInfo() );
// return uri.substring( request.getContextPath().length(), end );
- }
-
- /**
- * Returns the application name as specified in the request URI.
- * Note that wotonomy web applications do not typically have a .woa
- * extension, but the extension will be included for those that do.
- */
- public String applicationName ()
- {
- return request.getContextPath();
- }
-
- /**
- * Returns the id of the application instance that is needed to
- * service this request. -1 indicates that the request is not
- * specific to a particular instance of the application.
- * This implementation currently returns -1.
- */
- public int applicationNumber ()
- {
+ }
+
+ /**
+ * Returns the application name as specified in the request URI. Note that
+ * wotonomy web applications do not typically have a .woa extension, but the
+ * extension will be included for those that do.
+ */
+ public String applicationName() {
+ return request.getContextPath();
+ }
+
+ /**
+ * Returns the id of the application instance that is needed to service this
+ * request. -1 indicates that the request is not specific to a particular
+ * instance of the application. This implementation currently returns -1.
+ */
+ public int applicationNumber() {
return -1;
- }
-
- /**
- * Returns the portion of the URI that specifies which request handler
- * should handle the request.
- */
- public String requestHandlerKey ()
- {
- return requestHandlerKey;
- }
-
- /**
- * Returns the portion of the URI that specifies path information
- * for the request, not including the query string.
- */
- public String requestHandlerPath ()
- {
- return requestHandlerPath;
- }
-
- /**
- * Returns the unique identifier for the sessions associated with
- * this request, or null if no session is found.
- */
- public String sessionID ()
- {
- HttpSession session = request.getSession( false );
- if ( session == null ) return null;
- return session.getId();
- }
-
- /**
- * Returns an array containing all the form keys in the request.
- */
- public NSArray formValueKeys ()
- {
- return arrayFromEnumeration( request.getParameterNames() );
- }
-
- /**
- * Returns an array of the values for the specified key in
- * no particular order.
- */
- public NSArray formValuesForKey (String aKey)
- {
- NSMutableArray result = new NSMutableArray();
- String[] values = request.getParameterValues( aKey );
- if ( values != null )
- {
- for ( int i = 0; i < values.length; i++ )
- {
- result.addObject( values[i] );
- }
- }
- return result;
- }
-
- /**
- * Returns one value for the specified key.
- * Provided as a convenience since most keys have
- * only one value. Returns null if not found.
- */
- public Object formValueForKey (String aKey)
- {
- return request.getParameter( aKey );
- }
-
- /**
- * Returns the value for the specified key, as a String.
- */
- public String stringFormValueForKey(String key) {
- Object x = formValueForKey(key);
- if (x != null)
- return x.toString();
- return null;
- }
-
- /**
- * Returns a dictionary containing all the key-value
- * mappings in the request.
- */
- public NSDictionary formValues ()
- {
- NSMutableDictionary result = new NSMutableDictionary ();
- java.util.Enumeration e = request.getParameterNames();
- String key;
- while ( e.hasMoreElements() )
- {
- key = e.nextElement().toString();
- result.setObjectForKey( formValuesForKey( key ), key );
- }
- return result;
- }
-
- /**
- * Returns whether the request is from a java-based client component.
- * This implementation returns false.
- */
- public boolean isFromClientComponent ()
- {
- return false;
- }
-
- /**
- * Returns an array of cookie values for the specified key in
- * no particular order.
- */
- public NSArray cookieValuesForKey (String aKey)
- {
- // TODO: Test this logic.
- NSMutableArray result = new NSMutableArray();
- Cookie[] cookies = request.getCookies();
- if ( cookies == null ) return result;
-
- for ( int i = 0; i < cookies.length; i++ )
- {
- if ( cookies[i].getName().equals( aKey ) )
- {
- result.addObject( cookies[i].getValue() );
- }
- }
-
- return result;
- }
-
- /**
- * Returns one value for the specified cookie key.
- * Provided as a convenience since most cookies have
- * only one value. Returns null if not found.
- */
- public String cookieValueForKey (String aKey)
- {
- // TODO: Test this logic.
- Cookie[] cookies = request.getCookies();
- if ( cookies == null ) return null;
-
- for ( int i = 0; i < cookies.length; i++ )
- {
- if ( cookies[i].getName().equals( aKey ) )
- {
- return cookies[i].getValue();
- }
- }
-
- return null;
- }
-
- /**
- * Returns a dictionary of cookie key-value mappings.
- */
- public NSDictionary cookieValues ()
- {
- // TODO: Test this logic.
- NSMutableDictionary result = new NSMutableDictionary();
- Cookie[] cookies = request.getCookies();
- if ( cookies == null ) return result;
-
- NSMutableArray value;
- for ( int i = 0; i < cookies.length; i++ )
- {
- value = (NSMutableArray) result.objectForKey(
- cookies[i].getName() );
- if ( value == null )
- {
- value = new NSMutableArray();
- result.setObjectForKey(
- cookies[i].getValue(), cookies[i].getName() );
+ }
+
+ /**
+ * Returns the portion of the URI that specifies which request handler should
+ * handle the request.
+ */
+ public String requestHandlerKey() {
+ return requestHandlerKey;
+ }
+
+ /**
+ * Returns the portion of the URI that specifies path information for the
+ * request, not including the query string.
+ */
+ public String requestHandlerPath() {
+ return requestHandlerPath;
+ }
+
+ /**
+ * Returns the unique identifier for the sessions associated with this request,
+ * or null if no session is found.
+ */
+ public String sessionID() {
+ HttpSession session = request.getSession(false);
+ if (session == null)
+ return null;
+ return session.getId();
+ }
+
+ /**
+ * Returns an array containing all the form keys in the request.
+ */
+ public NSArray formValueKeys() {
+ return arrayFromEnumeration(request.getParameterNames());
+ }
+
+ /**
+ * Returns an array of the values for the specified key in no particular order.
+ */
+ public NSArray formValuesForKey(String aKey) {
+ NSMutableArray result = new NSMutableArray();
+ String[] values = request.getParameterValues(aKey);
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ result.addObject(values[i]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns one value for the specified key. Provided as a convenience since most
+ * keys have only one value. Returns null if not found.
+ */
+ public Object formValueForKey(String aKey) {
+ return request.getParameter(aKey);
+ }
+
+ /**
+ * Returns the value for the specified key, as a String.
+ */
+ public String stringFormValueForKey(String key) {
+ Object x = formValueForKey(key);
+ if (x != null)
+ return x.toString();
+ return null;
+ }
+
+ /**
+ * Returns a dictionary containing all the key-value mappings in the request.
+ */
+ public NSDictionary formValues() {
+ NSMutableDictionary result = new NSMutableDictionary();
+ java.util.Enumeration e = request.getParameterNames();
+ String key;
+ while (e.hasMoreElements()) {
+ key = e.nextElement().toString();
+ result.setObjectForKey(formValuesForKey(key), key);
+ }
+ return result;
+ }
+
+ /**
+ * Returns whether the request is from a java-based client component. This
+ * implementation returns false.
+ */
+ public boolean isFromClientComponent() {
+ return false;
+ }
+
+ /**
+ * Returns an array of cookie values for the specified key in no particular
+ * order.
+ */
+ public NSArray cookieValuesForKey(String aKey) {
+ // TODO: Test this logic.
+ NSMutableArray result = new NSMutableArray();
+ Cookie[] cookies = request.getCookies();
+ if (cookies == null)
+ return result;
+
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].getName().equals(aKey)) {
+ result.addObject(cookies[i].getValue());
}
- value.addObject( cookies[i].getValue() );
- }
-
- return result;
- }
-
- /**
- * Sets the default character encoding.
- */
- public void setDefaultFormValueEncoding (String encoding)
- {
- defaultFormValueEncoding = encoding;
- }
-
- /**
- * Returns the default form value encoding ("ISO8859_1").
- */
- public String defaultFormValueEncoding ()
- {
- return defaultFormValueEncoding;
- }
-
- /**
- * Sets whether the appropriate encoding scheme for decoding
- * the form values will be automatically determined.
- */
- public void setFormValueEncodingDetectionEnabled (boolean enabled)
- {
- throw new RuntimeException( "Not yet implemented." );
- }
-
- /**
- * Gets whether the appropriate encoding scheme for decoding
- * the form values is currently automatically determined.
- */
- public boolean isFormValueEncodingDetectionEnabled ()
- {
- throw new RuntimeException( "Not yet implemented." );
- }
-
- /**
- * Gets the current method used for decoding form values.
- */
- public int formValueEncoding ()
- {
- throw new RuntimeException( "Not yet implemented." );
- }
-
- /**
- * Returns the host name of the server that is the target of this request.
- * NOTE: This method is not published in the WORequest specification.
- */
- String applicationHost ()
- {
- // FIXME: this should call WOApplication.hostname();
- return request.getServerName();
- }
-
- /**
- * Returns the port of the server that is the target of this request.
- * NOTE: This method is not published in the WORequest specification.
- */
- int port()
- {
- // FIXME: this should call WOApplication.port();
- return request.getServerPort();
- }
-
- /**
- * Returns the backing HttpServletRequest.
- */
- HttpServletRequest servletRequest ()
- {
- return request;
- }
-
- /**
- * Returns the application that was the target of this request.
- * This method is not published in the WORequest specification.
- */
- WOApplication application ()
- {
- return application;
- }
-
- /**
- * This method is not published in the WORequest specification.
- * This sender id from the URI, which is the id of the element
- * that generated this request.
- */
- String senderID ()
- {
- return senderID;
- }
-
- /**
- * This method is not published in the WORequest specification.
- * This returns the context id from the URI.
- */
- String contextID ()
- {
- return contextID;
- }
-
- /**
- * This method is not published in the WORequest specification.
- */
- String pageName ()
- {
- return pageName;
- }
-
- /**
- * Convenience method to populate an NSArray from an Enumeration.
- */
- private static NSArray arrayFromEnumeration( java.util.Enumeration e )
- {
- NSMutableArray result = new NSMutableArray();
- while ( e.hasMoreElements() )
- {
- result.addObject( e.nextElement() );
- }
- return result;
- }
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns one value for the specified cookie key. Provided as a convenience
+ * since most cookies have only one value. Returns null if not found.
+ */
+ public String cookieValueForKey(String aKey) {
+ // TODO: Test this logic.
+ Cookie[] cookies = request.getCookies();
+ if (cookies == null)
+ return null;
+
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].getName().equals(aKey)) {
+ return cookies[i].getValue();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a dictionary of cookie key-value mappings.
+ */
+ public NSDictionary cookieValues() {
+ // TODO: Test this logic.
+ NSMutableDictionary result = new NSMutableDictionary();
+ Cookie[] cookies = request.getCookies();
+ if (cookies == null)
+ return result;
+
+ NSMutableArray value;
+ for (int i = 0; i < cookies.length; i++) {
+ value = (NSMutableArray) result.objectForKey(cookies[i].getName());
+ if (value == null) {
+ value = new NSMutableArray();
+ result.setObjectForKey(cookies[i].getValue(), cookies[i].getName());
+ }
+ value.addObject(cookies[i].getValue());
+ }
+
+ return result;
+ }
+
+ /**
+ * Sets the default character encoding.
+ */
+ public void setDefaultFormValueEncoding(String encoding) {
+ defaultFormValueEncoding = encoding;
+ }
+
+ /**
+ * Returns the default form value encoding ("ISO8859_1").
+ */
+ public String defaultFormValueEncoding() {
+ return defaultFormValueEncoding;
+ }
+
+ /**
+ * Sets whether the appropriate encoding scheme for decoding the form values
+ * will be automatically determined.
+ */
+ public void setFormValueEncodingDetectionEnabled(boolean enabled) {
+ throw new RuntimeException("Not yet implemented.");
+ }
+
+ /**
+ * Gets whether the appropriate encoding scheme for decoding the form values is
+ * currently automatically determined.
+ */
+ public boolean isFormValueEncodingDetectionEnabled() {
+ throw new RuntimeException("Not yet implemented.");
+ }
+
+ /**
+ * Gets the current method used for decoding form values.
+ */
+ public int formValueEncoding() {
+ throw new RuntimeException("Not yet implemented.");
+ }
+
+ /**
+ * Returns the host name of the server that is the target of this request. NOTE:
+ * This method is not published in the WORequest specification.
+ */
+ String applicationHost() {
+ // FIXME: this should call WOApplication.hostname();
+ return request.getServerName();
+ }
+
+ /**
+ * Returns the port of the server that is the target of this request. NOTE: This
+ * method is not published in the WORequest specification.
+ */
+ int port() {
+ // FIXME: this should call WOApplication.port();
+ return request.getServerPort();
+ }
+
+ /**
+ * Returns the backing HttpServletRequest.
+ */
+ HttpServletRequest servletRequest() {
+ return request;
+ }
+
+ /**
+ * Returns the application that was the target of this request. This method is
+ * not published in the WORequest specification.
+ */
+ WOApplication application() {
+ return application;
+ }
+
+ /**
+ * This method is not published in the WORequest specification. This sender id
+ * from the URI, which is the id of the element that generated this request.
+ */
+ String senderID() {
+ return senderID;
+ }
+
+ /**
+ * This method is not published in the WORequest specification. This returns the
+ * context id from the URI.
+ */
+ String contextID() {
+ return contextID;
+ }
+
+ /**
+ * This method is not published in the WORequest specification.
+ */
+ String pageName() {
+ return pageName;
+ }
+
+ /**
+ * Convenience method to populate an NSArray from an Enumeration.
+ */
+ private static NSArray arrayFromEnumeration(java.util.Enumeration e) {
+ NSMutableArray result = new NSMutableArray();
+ while (e.hasMoreElements()) {
+ result.addObject(e.nextElement());
+ }
+ return result;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequestHandler.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequestHandler.java
index 957cf25..7e3c624 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequestHandler.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequestHandler.java
@@ -21,44 +21,37 @@ package net.wotonomy.web;
import net.wotonomy.foundation.internal.NetworkClassLoader;
/**
-* A pure java implementation that corresponds
-* to the abstract class WORequestHandler.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public abstract class WORequestHandler
-{
+ * A pure java implementation that corresponds to the abstract class
+ * WORequestHandler.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public abstract class WORequestHandler {
private NetworkClassLoader loader;
-
+
/**
- * Default constructor.
- */
- public WORequestHandler()
- {
- loader = new NetworkClassLoader( WOApplication.application().getClass().getClassLoader() );
+ * Default constructor.
+ */
+ public WORequestHandler() {
+ loader = new NetworkClassLoader(WOApplication.application().getClass().getClassLoader());
}
-
+
/**
- * Dispatches the request and returns the response.
- */
- abstract public WOResponse handleRequest (WORequest aRequest);
-
+ * Dispatches the request and returns the response.
+ */
+ abstract public WOResponse handleRequest(WORequest aRequest);
+
/**
- * Gets the specified class, loading it if it has not already been
- * loaded or if it has been modified. Returns null if not found.
- * Because this method is not in the specification, it has only
- * package access.
- */
- Class loadClass( String aName )
- {
- try
- {
- return loader.loadClass( aName, true );
- }
- catch ( ClassNotFoundException cnfe )
- {
+ * Gets the specified class, loading it if it has not already been loaded or if
+ * it has been modified. Returns null if not found. Because this method is not
+ * in the specification, it has only package access.
+ */
+ Class loadClass(String aName) {
+ try {
+ return loader.loadClass(aName, true);
+ } catch (ClassNotFoundException cnfe) {
return null;
}
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResetButton.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResetButton.java
index 8428681..f4fb49f 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResetButton.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResetButton.java
@@ -21,30 +21,31 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
-* Implements a reset button with dynamic bindings.
+ * Implements a reset button with dynamic bindings.
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOResetButton extends WOInput {
- public WOResetButton() {
- super();
- }
+ public WOResetButton() {
+ super();
+ }
- public WOResetButton(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOResetButton(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- protected String inputType() {
- return "RESET";
- }
+ protected String inputType() {
+ return "RESET";
+ }
- protected Object value(WOContext c) {
- Object v = valueForProperty("value", c.component());
- if (v == null)
- return "Reset";
- return v;
- }
+ protected Object value(WOContext c) {
+ Object v = valueForProperty("value", c.component());
+ if (v == null)
+ return "Reset";
+ return v;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java
index c69c9db..5941ad2 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java
@@ -37,453 +37,353 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.internal.PropertyListParser;
/**
-* Manages all resources vended by the application.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOResourceManager
-{
- private NSMutableDictionary resourceCache;
- private NSMutableDictionary dynamicDataCache;
- private NSMutableDictionary stringTableCache;
- private Map localeCache; // used for wo-style i18n
- private Locale californiaLocale; // used for wo-style i18n
-
- /**
- * Constructor is only accessible to subclasses.
- */
- protected WOResourceManager()
- {
- resourceCache = new NSMutableDictionary();
- dynamicDataCache = new NSMutableDictionary();
- stringTableCache = new NSMutableDictionary();
- localeCache = new HashMap();
- californiaLocale = new Locale( "en", "US" );
- localeCache.put( "en", californiaLocale );
- }
-
- /**
- * Returns the raw data corresponding to the specified resource.
- * Any data retrieved by this method will be placed in the
- * resource manager's global cache.
- */
- public byte[] bytesForResourceNamed(String aFileName,
- String aFrameworkName,
- NSArray aLanguagesList)
- {
- String mash = aFileName + aFrameworkName;
- if ( aLanguagesList != null )
- {
- mash = mash + aLanguagesList.componentsJoinedByString(":");
- }
-
- byte[] result = (byte[]) resourceCache.objectForKey( mash );
- if ( result == null )
- {
- InputStream input = inputStreamForResourceNamed(
- aFileName, aFrameworkName, aLanguagesList );
- if ( input != null )
- {
- try
- {
- int c;
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- while ( ( c = input.read() ) != -1 )
- {
- output.write( c );
- }
- output.flush();
- input.close();
- output.close();
- result = output.toByteArray();
- synchronized ( resourceCache )
- {
- resourceCache.setObjectForKey( result, mash );
- }
- }
- catch ( Throwable t )
- {
- System.err.println( "WOResourceManager: Error reading bytes: " + aFileName );
- t.printStackTrace();
- }
- }
- }
- return result;
- }
-
- /**
- * Returns the content type corresponding to the specified resource.
- * This implementation recognizes gif, jpg, png, html, and xml extensions.
- * Otherwise, "text/plain" is returned.
- */
- public String contentTypeForResourceNamed(String aResourcePath)
- {
- if ( aResourcePath.endsWith( ".gif" ) ) return "image/gif";
- if ( aResourcePath.endsWith( ".jpg" ) ) return "image/jpeg";
- if ( aResourcePath.endsWith( ".png" ) ) return "image/png";
- if ( aResourcePath.endsWith( ".html" ) ) return "text/html";
- if ( aResourcePath.endsWith( ".xml" ) ) return "text/xml";
- return "text/plain";
- }
-
- /**
- * Returns a url to be used when errors occur while retrieving a resource.
- */
- public String errorMessageUrlForResourceNamed(String aResourceName,
- String aFrameworkName)
- {
- if ( aResourceName == null ) aResourceName = "null";
- if ( aFrameworkName == null )
- {
- return "/ERROR/NOT_FOUND/app=" +
- WOApplication.application().name() +
- "/filename=" + aResourceName;
- }
- else
- {
- return "/ERROR/NOT_FOUND/framework=" +
- aFrameworkName + "/filename=" + aResourceName;
- }
-
- }
-
- /**
- * Clears all cached system-wide resource data.
- */
- public void flushDataCache()
- {
- synchronized ( resourceCache )
- {
- resourceCache.removeAllObjects();
- }
- synchronized ( dynamicDataCache )
- {
- dynamicDataCache.removeAllObjects();
- }
- synchronized ( stringTableCache )
- {
- stringTableCache.removeAllObjects();
- }
- }
-
- /**
- * Returns the file-system path for the specified resource.
- * Deprecated and not implemented.
- * @deprecated Use inputStreamForResourceNamed instead.
- */
- public String pathForResourceNamed(String aResourceName,
- String aFrameworkName,
- NSArray aLanguagesList)
- {
- throw new RuntimeException( "ResourceManager.pathForResourceNamed: deprecated" );
- }
-
- /**
- * Removes the data from the dynamic data cache for the specified session.
- * If aSession is null, the data is removed from the application-wide
- * data cache.
- */
- public void removeDataForKey(String aKey,
- WOSession aSession)
- {
- if ( aSession != null )
- {
- if ( aSession.dynamicDataCache != null )
- {
- aSession.dynamicDataCache.removeObjectForKey( aKey );
- }
- }
- else
- {
- synchronized ( dynamicDataCache )
- {
- dynamicDataCache.removeObjectForKey( aKey );
- }
- }
- }
-
- /**
- * Sets the data in the dynamic data cache for the specified session.
- * If aSession is null, the data is placed in the application-wide
- * data cache. If the key is a system-generated key, the data will
- * be removed by calling removeData() the next time it is requested.
- */
- public void setData(NSData someData,
- String key,
- String type,
- WOSession aSession)
- {
- if ( aSession != null )
- {
- if ( aSession.dynamicDataCache != null )
- {
- aSession.dynamicDataCache.setObjectForKey(
- new TypedData( type, someData ), key );
- }
- }
- else
- {
- synchronized ( dynamicDataCache )
- {
- dynamicDataCache.setObjectForKey(
- new TypedData( type, someData ), key );
- }
- }
- }
-
- /**
- * Returns a localized string from a property list for
- * a given key. If the key doesn't exist, aDefaultValue
- * is returned.
- */
- public String stringForKey(String aKey,
- String aFileName,
- String aDefaultValue,
- String aFrameworkName,
- NSArray aLanguagesList)
- {
-
- String mash = aFileName + aFrameworkName;
- if ( aLanguagesList != null )
- {
- mash = mash + aLanguagesList.componentsJoinedByString(":");
- }
-
- Object table = stringTableCache.objectForKey( mash );
- if ( table == null )
- {
- try
- {
- InputStream input = (InputStream) inputStreamForResourceNamed(
- aFileName, aFrameworkName, aLanguagesList);
- if ( input != null )
- {
- Reader reader =
- new BufferedReader(new InputStreamReader(input));
- table = PropertyListParser.propertyListFromReader( reader );
- synchronized ( stringTableCache )
- {
- stringTableCache.setObjectForKey( table, mash );
- }
- }
- }
- catch ( IOException ioe )
- {
- System.err.println( "WOResourceManager: error reading: " + aFileName );
- ioe.printStackTrace();
- }
- catch ( Throwable t )
- {
- // could not parse
- System.err.println( "WOResourceManager: could not parse: " + aFileName );
- System.err.println( t );
- }
- }
-
- Object result = null;
- if ( table != null )
- {
- result = NSKeyValueCoding.DefaultImplementation.valueForKey( table, aKey );
- }
- if ( result == null )
- {
- result = aDefaultValue;
- }
- else
- {
- result = result.toString();
- }
-
- return (String) result;
- }
-
- /**
- * Returns a url that invokes the resource manager for the
- * specified resource.
- */
- public String urlForResourceNamed(String aResourceName,
- String aFrameworkName,
- NSArray aLanguagesList,
- WORequest aRequest)
- {
- StringBuffer buffer = new StringBuffer();
- if ( aFrameworkName == null )
- {
- aFrameworkName = "application";
- }
- buffer.append( aRequest.applicationName() );
- buffer.append( '/' );
- buffer.append( WOApplication.resourceRequestHandlerKey() );
- if ( !aFrameworkName.startsWith("/") )
- {
- buffer.append( '/' );
- }
- buffer.append( aFrameworkName );
- buffer.append( '/' );
- buffer.append( aResourceName );
- return buffer.toString();
- }
-
- /**
- * Returns an input for the raw resource. Data returned by
- * this method will not be put in the resource manager's global cache.
- */
- public InputStream inputStreamForResourceNamed(String aResourceName,
- String aFrameworkName,
- NSArray aLanguagesList)
- {
- if ( aResourceName == null ) return null;
- InputStream result = null;
-
- StringBuffer path = new StringBuffer();
- path.append( '/' );
- if ( aFrameworkName != null )
- {
- path.append( aFrameworkName ).append( '/' );
- }
-
- int i = aResourceName.lastIndexOf( "." );
- if ( i != -1 )
- path.append( aResourceName.substring( 0, i ) );
- else
- path.append( aResourceName );
-
- String location = path.toString();
- if ( aLanguagesList != null )
- {
- String language;
- Locale locale;
- HashSet tried = new HashSet(5);
- Enumeration e = aLanguagesList.objectEnumerator();
- while ( e.hasMoreElements() && result == null )
- {
- language = e.nextElement().toString();
-
- // look for java-style localization
- if ( i != -1 )
- {
- result = getStream( location + '_'
- + language + aResourceName.substring( i ) );
- }
- else // no dot extension
- {
- result = getStream( location + '_' + language );
- }
-
- // look for wo-style localization
- if ( result == null )
- {
- locale = (Locale) localeCache.get( language );
- if ( locale == null )
- {
- if ( language.length() == 5 )
- {
- locale = new Locale(
- language.substring( 0, 2 ),
- language.substring( 3, 5 ) );
- }
- else
- {
- locale = new Locale( language, "" );
- }
- synchronized ( localeCache )
- {
- localeCache.put( language, locale );
- }
- }
-
- language = '/'+locale.getDisplayLanguage( californiaLocale )+".lproj";
- if ( !tried.contains( language ) )
- {
- if ( aFrameworkName != null )
- {
- int j = aFrameworkName.length()+1;
- path.insert( j, language );
- result = getStream( path.toString() + aResourceName.substring( i ) );
- path.delete( j, j+language.length() );
- }
- else
- {
- result = getStream( language + path.toString() + aResourceName.substring( i ) );
- }
- tried.add( language );
- }
- }
- }
- }
-
- // look for file in package
- if ( result == null )
- {
- if ( i != -1 )
- {
- result = getStream( path.append(
- aResourceName.substring( i ) ).toString() );
- }
- else // no dot extension
- {
- result = getStream( location );
- }
- }
-
- return result;
- }
-
- private static final InputStream getStream( String path )
- { //System.out.println( "getStream: " + path );
- InputStream input =
- WOApplication.application().getClass().getResourceAsStream( path );
- if ( input == null )
- {
- // in case the local class loader doesn't delegate to its parent
- input = ClassLoader.getSystemResourceAsStream( path );
- }
- return input;
- }
-
- private static final class TypedData
- {
- String type;
- NSData data;
-
- public TypedData( String aType, NSData aData )
- {
- type = aType;
- data = aData;
- }
- }
+ * Manages all resources vended by the application.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOResourceManager {
+ private NSMutableDictionary resourceCache;
+ private NSMutableDictionary dynamicDataCache;
+ private NSMutableDictionary stringTableCache;
+ private Map localeCache; // used for wo-style i18n
+ private Locale californiaLocale; // used for wo-style i18n
+
+ /**
+ * Constructor is only accessible to subclasses.
+ */
+ protected WOResourceManager() {
+ resourceCache = new NSMutableDictionary();
+ dynamicDataCache = new NSMutableDictionary();
+ stringTableCache = new NSMutableDictionary();
+ localeCache = new HashMap();
+ californiaLocale = new Locale("en", "US");
+ localeCache.put("en", californiaLocale);
+ }
+
+ /**
+ * Returns the raw data corresponding to the specified resource. Any data
+ * retrieved by this method will be placed in the resource manager's global
+ * cache.
+ */
+ public byte[] bytesForResourceNamed(String aFileName, String aFrameworkName, NSArray aLanguagesList) {
+ String mash = aFileName + aFrameworkName;
+ if (aLanguagesList != null) {
+ mash = mash + aLanguagesList.componentsJoinedByString(":");
+ }
+
+ byte[] result = (byte[]) resourceCache.objectForKey(mash);
+ if (result == null) {
+ InputStream input = inputStreamForResourceNamed(aFileName, aFrameworkName, aLanguagesList);
+ if (input != null) {
+ try {
+ int c;
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ while ((c = input.read()) != -1) {
+ output.write(c);
+ }
+ output.flush();
+ input.close();
+ output.close();
+ result = output.toByteArray();
+ synchronized (resourceCache) {
+ resourceCache.setObjectForKey(result, mash);
+ }
+ } catch (Throwable t) {
+ System.err.println("WOResourceManager: Error reading bytes: " + aFileName);
+ t.printStackTrace();
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the content type corresponding to the specified resource. This
+ * implementation recognizes gif, jpg, png, html, and xml extensions. Otherwise,
+ * "text/plain" is returned.
+ */
+ public String contentTypeForResourceNamed(String aResourcePath) {
+ if (aResourcePath.endsWith(".gif"))
+ return "image/gif";
+ if (aResourcePath.endsWith(".jpg"))
+ return "image/jpeg";
+ if (aResourcePath.endsWith(".png"))
+ return "image/png";
+ if (aResourcePath.endsWith(".html"))
+ return "text/html";
+ if (aResourcePath.endsWith(".xml"))
+ return "text/xml";
+ return "text/plain";
+ }
+
+ /**
+ * Returns a url to be used when errors occur while retrieving a resource.
+ */
+ public String errorMessageUrlForResourceNamed(String aResourceName, String aFrameworkName) {
+ if (aResourceName == null)
+ aResourceName = "null";
+ if (aFrameworkName == null) {
+ return "/ERROR/NOT_FOUND/app=" + WOApplication.application().name() + "/filename=" + aResourceName;
+ } else {
+ return "/ERROR/NOT_FOUND/framework=" + aFrameworkName + "/filename=" + aResourceName;
+ }
+
+ }
+
+ /**
+ * Clears all cached system-wide resource data.
+ */
+ public void flushDataCache() {
+ synchronized (resourceCache) {
+ resourceCache.removeAllObjects();
+ }
+ synchronized (dynamicDataCache) {
+ dynamicDataCache.removeAllObjects();
+ }
+ synchronized (stringTableCache) {
+ stringTableCache.removeAllObjects();
+ }
+ }
+
+ /**
+ * Returns the file-system path for the specified resource. Deprecated and not
+ * implemented.
+ *
+ * @deprecated Use inputStreamForResourceNamed instead.
+ */
+ public String pathForResourceNamed(String aResourceName, String aFrameworkName, NSArray aLanguagesList) {
+ throw new RuntimeException("ResourceManager.pathForResourceNamed: deprecated");
+ }
+
+ /**
+ * Removes the data from the dynamic data cache for the specified session. If
+ * aSession is null, the data is removed from the application-wide data cache.
+ */
+ public void removeDataForKey(String aKey, WOSession aSession) {
+ if (aSession != null) {
+ if (aSession.dynamicDataCache != null) {
+ aSession.dynamicDataCache.removeObjectForKey(aKey);
+ }
+ } else {
+ synchronized (dynamicDataCache) {
+ dynamicDataCache.removeObjectForKey(aKey);
+ }
+ }
+ }
+
+ /**
+ * Sets the data in the dynamic data cache for the specified session. If
+ * aSession is null, the data is placed in the application-wide data cache. If
+ * the key is a system-generated key, the data will be removed by calling
+ * removeData() the next time it is requested.
+ */
+ public void setData(NSData someData, String key, String type, WOSession aSession) {
+ if (aSession != null) {
+ if (aSession.dynamicDataCache != null) {
+ aSession.dynamicDataCache.setObjectForKey(new TypedData(type, someData), key);
+ }
+ } else {
+ synchronized (dynamicDataCache) {
+ dynamicDataCache.setObjectForKey(new TypedData(type, someData), key);
+ }
+ }
+ }
+
+ /**
+ * Returns a localized string from a property list for a given key. If the key
+ * doesn't exist, aDefaultValue is returned.
+ */
+ public String stringForKey(String aKey, String aFileName, String aDefaultValue, String aFrameworkName,
+ NSArray aLanguagesList) {
+
+ String mash = aFileName + aFrameworkName;
+ if (aLanguagesList != null) {
+ mash = mash + aLanguagesList.componentsJoinedByString(":");
+ }
+
+ Object table = stringTableCache.objectForKey(mash);
+ if (table == null) {
+ try {
+ InputStream input = (InputStream) inputStreamForResourceNamed(aFileName, aFrameworkName,
+ aLanguagesList);
+ if (input != null) {
+ Reader reader = new BufferedReader(new InputStreamReader(input));
+ table = PropertyListParser.propertyListFromReader(reader);
+ synchronized (stringTableCache) {
+ stringTableCache.setObjectForKey(table, mash);
+ }
+ }
+ } catch (IOException ioe) {
+ System.err.println("WOResourceManager: error reading: " + aFileName);
+ ioe.printStackTrace();
+ } catch (Throwable t) {
+ // could not parse
+ System.err.println("WOResourceManager: could not parse: " + aFileName);
+ System.err.println(t);
+ }
+ }
+
+ Object result = null;
+ if (table != null) {
+ result = NSKeyValueCoding.DefaultImplementation.valueForKey(table, aKey);
+ }
+ if (result == null) {
+ result = aDefaultValue;
+ } else {
+ result = result.toString();
+ }
+
+ return (String) result;
+ }
+
+ /**
+ * Returns a url that invokes the resource manager for the specified resource.
+ */
+ public String urlForResourceNamed(String aResourceName, String aFrameworkName, NSArray aLanguagesList,
+ WORequest aRequest) {
+ StringBuffer buffer = new StringBuffer();
+ if (aFrameworkName == null) {
+ aFrameworkName = "application";
+ }
+ buffer.append(aRequest.applicationName());
+ buffer.append('/');
+ buffer.append(WOApplication.resourceRequestHandlerKey());
+ if (!aFrameworkName.startsWith("/")) {
+ buffer.append('/');
+ }
+ buffer.append(aFrameworkName);
+ buffer.append('/');
+ buffer.append(aResourceName);
+ return buffer.toString();
+ }
+
+ /**
+ * Returns an input for the raw resource. Data returned by this method will not
+ * be put in the resource manager's global cache.
+ */
+ public InputStream inputStreamForResourceNamed(String aResourceName, String aFrameworkName,
+ NSArray aLanguagesList) {
+ if (aResourceName == null)
+ return null;
+ InputStream result = null;
+
+ StringBuffer path = new StringBuffer();
+ path.append('/');
+ if (aFrameworkName != null) {
+ path.append(aFrameworkName).append('/');
+ }
+
+ int i = aResourceName.lastIndexOf(".");
+ if (i != -1)
+ path.append(aResourceName.substring(0, i));
+ else
+ path.append(aResourceName);
+
+ String location = path.toString();
+ if (aLanguagesList != null) {
+ String language;
+ Locale locale;
+ HashSet tried = new HashSet(5);
+ Enumeration e = aLanguagesList.objectEnumerator();
+ while (e.hasMoreElements() && result == null) {
+ language = e.nextElement().toString();
+
+ // look for java-style localization
+ if (i != -1) {
+ result = getStream(location + '_' + language + aResourceName.substring(i));
+ } else // no dot extension
+ {
+ result = getStream(location + '_' + language);
+ }
+
+ // look for wo-style localization
+ if (result == null) {
+ locale = (Locale) localeCache.get(language);
+ if (locale == null) {
+ if (language.length() == 5) {
+ locale = new Locale(language.substring(0, 2), language.substring(3, 5));
+ } else {
+ locale = new Locale(language, "");
+ }
+ synchronized (localeCache) {
+ localeCache.put(language, locale);
+ }
+ }
+
+ language = '/' + locale.getDisplayLanguage(californiaLocale) + ".lproj";
+ if (!tried.contains(language)) {
+ if (aFrameworkName != null) {
+ int j = aFrameworkName.length() + 1;
+ path.insert(j, language);
+ result = getStream(path.toString() + aResourceName.substring(i));
+ path.delete(j, j + language.length());
+ } else {
+ result = getStream(language + path.toString() + aResourceName.substring(i));
+ }
+ tried.add(language);
+ }
+ }
+ }
+ }
+
+ // look for file in package
+ if (result == null) {
+ if (i != -1) {
+ result = getStream(path.append(aResourceName.substring(i)).toString());
+ } else // no dot extension
+ {
+ result = getStream(location);
+ }
+ }
+
+ return result;
+ }
+
+ private static final InputStream getStream(String path) { // System.out.println( "getStream: " + path );
+ InputStream input = WOApplication.application().getClass().getResourceAsStream(path);
+ if (input == null) {
+ // in case the local class loader doesn't delegate to its parent
+ input = ClassLoader.getSystemResourceAsStream(path);
+ }
+ return input;
+ }
+
+ private static final class TypedData {
+ String type;
+ NSData data;
+
+ public TypedData(String aType, NSData aData) {
+ type = aType;
+ data = aData;
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2003/08/07 00:15:15 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.5 2003/08/07 00:15:15 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.4 2003/02/28 22:58:57 mpowers
- * Added support for wo-style localization (*.lproj).
+ * Revision 1.4 2003/02/28 22:58:57 mpowers Added support for wo-style
+ * localization (*.lproj).
*
- * Revision 1.3 2003/02/21 16:40:24 mpowers
- * Now reading port and smtp host from system properties.
- * Implemented WOApplication.main.
+ * Revision 1.3 2003/02/21 16:40:24 mpowers Now reading port and smtp host from
+ * system properties. Implemented WOApplication.main.
*
- * Revision 1.2 2003/01/28 19:33:52 mpowers
- * Implemented the rest of WOResourceManager.
- * Implemented support for java-style i18n.
- * Components now use the resource manager to load templates.
+ * Revision 1.2 2003/01/28 19:33:52 mpowers Implemented the rest of
+ * WOResourceManager. Implemented support for java-style i18n. Components now
+ * use the resource manager to load templates.
*
- * Revision 1.1 2003/01/27 15:08:00 mpowers
- * Implemented WOResourceManager, using java resources for now.
+ * Revision 1.1 2003/01/27 15:08:00 mpowers Implemented WOResourceManager, using
+ * java resources for now.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceRequestHandler.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceRequestHandler.java
index 4d25128..f611149 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceRequestHandler.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceRequestHandler.java
@@ -24,99 +24,81 @@ import net.wotonomy.foundation.NSData;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* An implementation of WORequestHandler that
-* retrieves resources from the deployed application.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOResourceRequestHandler
- extends WORequestHandler
-{
- private NSMutableDictionary resourceCache;
- private WOResourceManager resourceManager;
-
- public WOResourceRequestHandler()
- {
- //TODO: should probably have some kind of limit on the cache
- resourceCache = new NSMutableDictionary();
- resourceManager = WOApplication.application().resourceManager();
- }
-
- public WOResponse handleRequest( WORequest aRequest )
- {
- WOResponse response = new WOResponse();
-
- StringBuffer buf = new StringBuffer();
-
- //TODO: this is just to get things working...
- String framework = null;
- Enumeration e = aRequest.requestHandlerPathArray().objectEnumerator();
- if ( e.hasMoreElements() )
- {
- framework = e.nextElement().toString();
- if ( framework.equals( "application" ) )
- {
- buf.append('/').append( framework );
- framework = null;
- }
- }
- if ( e.hasMoreElements() )
- {
- buf.append( e.nextElement() );
- }
- while ( e.hasMoreElements() )
- {
- buf.append('/').append( e.nextElement() );
- }
-
- String resource;
- if ( buf.length() > 0 )
- {
- resource = buf.toString();
- byte[] data = resourceManager.bytesForResourceNamed(
- resource, framework, aRequest.browserLanguages() );
- if ( data != null )
- {
- response.setHeader(
- resourceManager.contentTypeForResourceNamed( resource ),
- "Content-Type" );
- response.setContent( new NSData( data ) );
- return response;
- }
- }
- response.setStatus( 404 ); // not found
- return response;
- }
+ * An implementation of WORequestHandler that retrieves resources from the
+ * deployed application.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOResourceRequestHandler extends WORequestHandler {
+ private NSMutableDictionary resourceCache;
+ private WOResourceManager resourceManager;
+
+ public WOResourceRequestHandler() {
+ // TODO: should probably have some kind of limit on the cache
+ resourceCache = new NSMutableDictionary();
+ resourceManager = WOApplication.application().resourceManager();
+ }
+
+ public WOResponse handleRequest(WORequest aRequest) {
+ WOResponse response = new WOResponse();
+
+ StringBuffer buf = new StringBuffer();
+
+ // TODO: this is just to get things working...
+ String framework = null;
+ Enumeration e = aRequest.requestHandlerPathArray().objectEnumerator();
+ if (e.hasMoreElements()) {
+ framework = e.nextElement().toString();
+ if (framework.equals("application")) {
+ buf.append('/').append(framework);
+ framework = null;
+ }
+ }
+ if (e.hasMoreElements()) {
+ buf.append(e.nextElement());
+ }
+ while (e.hasMoreElements()) {
+ buf.append('/').append(e.nextElement());
+ }
+
+ String resource;
+ if (buf.length() > 0) {
+ resource = buf.toString();
+ byte[] data = resourceManager.bytesForResourceNamed(resource, framework, aRequest.browserLanguages());
+ if (data != null) {
+ response.setHeader(resourceManager.contentTypeForResourceNamed(resource), "Content-Type");
+ response.setContent(new NSData(data));
+ return response;
+ }
+ }
+ response.setStatus(404); // not found
+ return response;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.6 2003/08/07 00:15:15 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.6 2003/08/07 00:15:15 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.5 2003/01/27 15:08:00 mpowers
- * Implemented WOResourceManager, using java resources for now.
+ * Revision 1.5 2003/01/27 15:08:00 mpowers Implemented WOResourceManager, using
+ * java resources for now.
*
- * Revision 1.4 2003/01/22 23:01:36 mpowers
- * Better handling for request handler path.
- * Better support for resources with absolute path.
+ * Revision 1.4 2003/01/22 23:01:36 mpowers Better handling for request handler
+ * path. Better support for resources with absolute path.
*
- * Revision 1.3 2003/01/20 16:18:22 mpowers
- * Fixed class loading issues with resource retrieval.
+ * Revision 1.3 2003/01/20 16:18:22 mpowers Fixed class loading issues with
+ * resource retrieval.
*
- * Revision 1.2 2003/01/17 20:58:20 mpowers
- * Fixed up WOHyperlink.
+ * Revision 1.2 2003/01/17 20:58:20 mpowers Fixed up WOHyperlink.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceURL.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceURL.java
index 862c6dc..14c1c87 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceURL.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceURL.java
@@ -6,26 +6,26 @@ import net.wotonomy.foundation.NSDictionary;
public class WOResourceURL extends WODynamicElement {
- public WOResourceURL() {
- super();
- }
+ public WOResourceURL() {
+ super();
+ }
- public WOResourceURL(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
+ public WOResourceURL(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- String fname = stringForProperty("filename", c.component());
- if (fname != null) {
- String fwk = stringForProperty("framework", c.component());
- return;
- }
- NSData data = (NSData)valueForProperty("data", c.component());
- if (data != null) {
- String mime = stringForProperty("mimeType", c.component());
- String key = stringForProperty("key", c.component());
- return;
- }
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ String fname = stringForProperty("filename", c.component());
+ if (fname != null) {
+ String fwk = stringForProperty("framework", c.component());
+ return;
+ }
+ NSData data = (NSData) valueForProperty("data", c.component());
+ if (data != null) {
+ String mime = stringForProperty("mimeType", c.component());
+ String key = stringForProperty("key", c.component());
+ return;
+ }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResponse.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResponse.java
index d9fbade..6362a03 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResponse.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResponse.java
@@ -25,160 +25,133 @@ import java.util.TimeZone;
import net.wotonomy.foundation.NSArray;
/**
-* A pure java implementation of WOResponse.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOResponse extends WOMessage
- implements WOActionResults
-{
+ * A pure java implementation of WOResponse.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOResponse extends WOMessage implements WOActionResults {
protected static String defaultEncoding;
- private static SimpleDateFormat htmlDateFormat;
- static
- {
- defaultEncoding = "ISO8859_1";
- htmlDateFormat = new SimpleDateFormat(
- "EEE, dd MMM yyyy HH:mm:ss z" );
- htmlDateFormat.setTimeZone(
- TimeZone.getTimeZone( "GMT" ) );
- }
+ private static SimpleDateFormat htmlDateFormat;
+ static {
+ defaultEncoding = "ISO8859_1";
+ htmlDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
+ htmlDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
private int status;
/**
- * Parameterless constructor which should not be called.
- */
- public WOResponse ()
- {
+ * Parameterless constructor which should not be called.
+ */
+ public WOResponse() {
status = -1; // -1 indicates not yet set
- }
+ }
+
+ /**
+ * Sets the status code of the response. You should use the constants defined in
+ * HttpServletResponse.
+ */
+ public void setStatus(int code) {
+ status = code;
+ }
/**
- * Sets the status code of the response.
- * You should use the constants defined in HttpServletResponse.
- */
- public void setStatus (int code)
- {
- status = code;
- }
+ * Gets the current status code for the response.
+ */
+ public int status() {
+ return status;
+ }
/**
- * Gets the current status code for the response.
- */
- public int status ()
- {
- return status;
- }
+ * Sets a header in the response to disable client caching. (Whether this works
+ * depends on the client implementation.)
+ */
+ public void disableClientCaching() {
+ String dateString = htmlDateFormat.format(new Date());
+ setHeader(dateString, "Date");
+ setHeader(dateString, "Expires");
+ setHeader("no-cache", "Pragma");
+ setHeaders(new NSArray(new Object[] { "private", "no-cache", "max-age = 0" }), "Cache-Control");
+ // System.out.println( "disableClientCaching: " + dateString );
+ }
/**
- * Sets a header in the response to disable client caching.
- * (Whether this works depends on the client implementation.)
- */
- public void disableClientCaching ()
- {
- String dateString = htmlDateFormat.format( new Date() );
- setHeader( dateString, "Date" );
- setHeader( dateString, "Expires" );
- setHeader( "no-cache", "Pragma" );
- setHeaders( new NSArray( new Object[] {
- "private", "no-cache", "max-age = 0" } ), "Cache-Control" );
- //System.out.println( "disableClientCaching: " + dateString );
- }
-
- /**
- * Returns this object. (Implements the WOActionResults interface.)
- */
- public WOResponse generateResponse()
- {
- return this;
- }
+ * Returns this object. (Implements the WOActionResults interface.)
+ */
+ public WOResponse generateResponse() {
+ return this;
+ }
/**
- * Generates the response using the specified servlet response,
- * but does not flush the buffer. The caller is responsible
- * for sending the response to the client. <br><br>
- * Note that this method is currently responsible for setting
- * the content type to "text/html". As far as I can tell, WORequests
- * have no way to set the content type and therefore must always
- * be of type "text/html".
- */
- void generateServletResponse
- (javax.servlet.http.HttpServletResponse response)
- {
- if ( WOApplication.application().isPageRefreshOnBacktrackEnabled() )
- {
- disableClientCaching();
- }
-
- String key;
- java.util.Enumeration e, f;
-
- // set content type: might be overwritten by headers below
- response.setContentType( "text/html" );
-
- // set status
- if ( status != -1 )
- {
- response.setStatus( status );
+ * Generates the response using the specified servlet response, but does not
+ * flush the buffer. The caller is responsible for sending the response to the
+ * client. <br>
+ * <br>
+ * Note that this method is currently responsible for setting the content type
+ * to "text/html". As far as I can tell, WORequests have no way to set the
+ * content type and therefore must always be of type "text/html".
+ */
+ void generateServletResponse(javax.servlet.http.HttpServletResponse response) {
+ if (WOApplication.application().isPageRefreshOnBacktrackEnabled()) {
+ disableClientCaching();
+ }
+
+ String key;
+ java.util.Enumeration e, f;
+
+ // set content type: might be overwritten by headers below
+ response.setContentType("text/html");
+
+ // set status
+ if (status != -1) {
+ response.setStatus(status);
}
- // set headers
- f = _headers.allKeys().objectEnumerator();
- while ( f.hasMoreElements() )
- {
- key = f.nextElement().toString();
- e = ((NSArray)_headers.objectForKey( key )).objectEnumerator();
- if ( e.hasMoreElements() )
- {
- // overwrite existing header
- response.setHeader( key, e.nextElement().toString() );
- }
- while ( e.hasMoreElements() )
- {
- response.addHeader( key, e.nextElement().toString() );
- }
+ // set headers
+ f = _headers.allKeys().objectEnumerator();
+ while (f.hasMoreElements()) {
+ key = f.nextElement().toString();
+ e = ((NSArray) _headers.objectForKey(key)).objectEnumerator();
+ if (e.hasMoreElements()) {
+ // overwrite existing header
+ response.setHeader(key, e.nextElement().toString());
+ }
+ while (e.hasMoreElements()) {
+ response.addHeader(key, e.nextElement().toString());
+ }
}
- // set cookies
- e = _cookies.allValues().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- response.addCookie( (WOCookie) e.nextElement() );
- }
-
- try
- {
- // write content
- response.getOutputStream().write(_contentData.bytes() );
- if ( status > 299 )
- {
- response.sendError( status );
- }
- }
- catch ( Exception exc )
- {
- throw new RuntimeException(
- "Error writing response: " + exc );
+ // set cookies
+ e = _cookies.allValues().objectEnumerator();
+ while (e.hasMoreElements()) {
+ response.addCookie((WOCookie) e.nextElement());
}
- }
+ try {
+ // write content
+ response.getOutputStream().write(_contentData.bytes());
+ if (status > 299) {
+ response.sendError(status);
+ }
+ } catch (Exception exc) {
+ throw new RuntimeException("Error writing response: " + exc);
+ }
+ }
/**
- * Returns the current default encoding seting.
- */
- public static String defaultEncoding ()
- {
- return defaultEncoding;
- }
+ * Returns the current default encoding seting.
+ */
+ public static String defaultEncoding() {
+ return defaultEncoding;
+ }
/**
- * Sets the default encoding setting.
- */
- public static void setDefaultEncoding (String encoding)
- {
- defaultEncoding = encoding;
- }
+ * Sets the default encoding setting.
+ */
+ public static void setDefaultEncoding(String encoding) {
+ defaultEncoding = encoding;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOServletSessionStore.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOServletSessionStore.java
index 0f2898c..647346c 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOServletSessionStore.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOServletSessionStore.java
@@ -28,161 +28,135 @@ import java.io.ObjectStreamClass;
import javax.servlet.http.HttpSession;
-
/**
-* An implementation of WOSessionStore that stores WOSessions
-* inside of HttpSessions, to take advantage of the servlet
-* containers built-in distribution capabilities.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOServletSessionStore extends WOSessionStore
-{
- private static final String ServletSessionKey = "WOServletSessionStoreKey";
-
- /**
- * This implementation currently does nothing and returns null, as we rely on the
- * servlet container to dispose of the HttpSession which contains our WOSession.
- */
- public WOSession removeSessionWithID(String sessionID)
- {
- return null;
- }
-
- /**
- * Returns the WOSession for the specified ID from the store.
- * The sessionID parameter is ignored, and the session is removed from
- * the store until saveSessionForContext is called.
- */
- public WOSession restoreSessionWithID(String sessionID, WORequest aRequest)
- {
- WOSession result = null;
- HttpSession servletSession = aRequest.servletRequest().getSession();
- if ( servletSession != null )
- {
- try
- {
- result = (WOSession) servletSession.getAttribute( ServletSessionKey );
- if ( result != null )
- {
- // if the servlet's class loader has changed, we need to reload
- if ( result.getClass().getClassLoader() !=
- WOApplication.application().getClass().getClassLoader() )
- {
- throw new ClassCastException( result.getClass().toString() );
- }
- }
- }
- catch ( ClassCastException exc )
- {
- // we're having an issue with the container's class loader:
- // try serializing and deserializing to see if it is reloaded correctly
- try
- {
-
- ByteArrayOutputStream bytes = new ByteArrayOutputStream();
- ObjectOutputStream output = new ObjectOutputStream( bytes );
- Object o = servletSession.getAttribute( ServletSessionKey );
- output.writeObject( o );
- output.flush();
- output.close();
-
- System.out.println(
- "WOServletSessionStore: reloaded session with size: " +
- bytes.toByteArray().length );
-
- ObjectInputStream input = new CustomObjectInputStream(
- new ByteArrayInputStream( bytes.toByteArray() ),
- WOApplication.application().getClass().getClassLoader() );
-
- o = input.readObject();
- input.close();
-
- // try it again
- result = (WOSession) o;
- }
- catch ( Exception e )
- {
- e.printStackTrace();
- // give up: remove the attribute and allow a new session
- servletSession.removeAttribute( ServletSessionKey );
- }
- }
-
- if ( result != null )
- {
- servletSession.removeAttribute( ServletSessionKey );
- }
- }
- //System.out.println( "restoreSessionWithID: " + sessionID + " : " + result );
- return result;
- }
-
- /**
- * Places the context's session into the store.
- */
- public void saveSessionForContext(WOContext context)
- {
- //System.out.println( "saveSessionForContext: " + context + " : " + context.session() );
- context.request().servletRequest().getSession( true ).setAttribute(
- ServletSessionKey, context.session() );
- }
-
- /**
- * Needed to specify a class loader which may be different that the
- * one used to load the ObjectInputStream class.
- */
- private static class CustomObjectInputStream extends ObjectInputStream
- {
- ClassLoader loader;
-
- public CustomObjectInputStream(
- InputStream anInputStream, ClassLoader aClassLoader )
- throws java.io.IOException, java.io.StreamCorruptedException
- {
- super( anInputStream );
- loader = aClassLoader;
- }
-
- protected Class resolveClass(ObjectStreamClass v)
- throws IOException, ClassNotFoundException
- {
- return loader.loadClass( v.getName() );
- }
- }
+ * An implementation of WOSessionStore that stores WOSessions inside of
+ * HttpSessions, to take advantage of the servlet containers built-in
+ * distribution capabilities.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOServletSessionStore extends WOSessionStore {
+ private static final String ServletSessionKey = "WOServletSessionStoreKey";
+
+ /**
+ * This implementation currently does nothing and returns null, as we rely on
+ * the servlet container to dispose of the HttpSession which contains our
+ * WOSession.
+ */
+ public WOSession removeSessionWithID(String sessionID) {
+ return null;
+ }
+
+ /**
+ * Returns the WOSession for the specified ID from the store. The sessionID
+ * parameter is ignored, and the session is removed from the store until
+ * saveSessionForContext is called.
+ */
+ public WOSession restoreSessionWithID(String sessionID, WORequest aRequest) {
+ WOSession result = null;
+ HttpSession servletSession = aRequest.servletRequest().getSession();
+ if (servletSession != null) {
+ try {
+ result = (WOSession) servletSession.getAttribute(ServletSessionKey);
+ if (result != null) {
+ // if the servlet's class loader has changed, we need to reload
+ if (result.getClass().getClassLoader() != WOApplication.application().getClass().getClassLoader()) {
+ throw new ClassCastException(result.getClass().toString());
+ }
+ }
+ } catch (ClassCastException exc) {
+ // we're having an issue with the container's class loader:
+ // try serializing and deserializing to see if it is reloaded correctly
+ try {
+
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ ObjectOutputStream output = new ObjectOutputStream(bytes);
+ Object o = servletSession.getAttribute(ServletSessionKey);
+ output.writeObject(o);
+ output.flush();
+ output.close();
+
+ System.out.println(
+ "WOServletSessionStore: reloaded session with size: " + bytes.toByteArray().length);
+
+ ObjectInputStream input = new CustomObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()),
+ WOApplication.application().getClass().getClassLoader());
+
+ o = input.readObject();
+ input.close();
+
+ // try it again
+ result = (WOSession) o;
+ } catch (Exception e) {
+ e.printStackTrace();
+ // give up: remove the attribute and allow a new session
+ servletSession.removeAttribute(ServletSessionKey);
+ }
+ }
+
+ if (result != null) {
+ servletSession.removeAttribute(ServletSessionKey);
+ }
+ }
+ // System.out.println( "restoreSessionWithID: " + sessionID + " : " + result );
+ return result;
+ }
+
+ /**
+ * Places the context's session into the store.
+ */
+ public void saveSessionForContext(WOContext context) {
+ // System.out.println( "saveSessionForContext: " + context + " : " +
+ // context.session() );
+ context.request().servletRequest().getSession(true).setAttribute(ServletSessionKey, context.session());
+ }
+
+ /**
+ * Needed to specify a class loader which may be different that the one used to
+ * load the ObjectInputStream class.
+ */
+ private static class CustomObjectInputStream extends ObjectInputStream {
+ ClassLoader loader;
+
+ public CustomObjectInputStream(InputStream anInputStream, ClassLoader aClassLoader)
+ throws java.io.IOException, java.io.StreamCorruptedException {
+ super(anInputStream);
+ loader = aClassLoader;
+ }
+
+ protected Class resolveClass(ObjectStreamClass v) throws IOException, ClassNotFoundException {
+ return loader.loadClass(v.getName());
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.7 2003/01/22 23:00:32 mpowers
- * Now keeping the most recent page around.
+ * Revision 1.7 2003/01/22 23:00:32 mpowers Now keeping the most recent page
+ * around.
*
- * Revision 1.6 2003/01/21 17:53:16 mpowers
- * Now handling reloading when wotonomy is on the system class path.
+ * Revision 1.6 2003/01/21 17:53:16 mpowers Now handling reloading when wotonomy
+ * is on the system class path.
*
- * Revision 1.5 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.5 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.3 2003/01/14 16:05:19 mpowers
- * Removed extraneous printlns.
+ * Revision 1.3 2003/01/14 16:05:19 mpowers Removed extraneous printlns.
*
- * Revision 1.2 2003/01/13 22:25:07 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.2 2003/01/13 22:25:07 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.1 2003/01/07 20:48:24 mpowers
- * Implemented WOSessionStore and WOServletSessionStore.
+ * Revision 1.1 2003/01/07 20:48:24 mpowers Implemented WOSessionStore and
+ * WOServletSessionStore.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSession.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSession.java
index e187567..82df58b 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSession.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSession.java
@@ -36,493 +36,433 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* A pure java implementation of WOSession.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOSession implements Serializable, NSKeyValueCodingAdditions
-{
- //NOTE: need to set this when deserialized and on creation
- transient private HttpSession session;
-
- // the current context
- transient private WOContext context;
-
- // the last requested page: an optimization
- transient private WOComponent currentPage;
- // the last requested page's context id
- transient private String currentContextID;
-
- //FIXME: transient until ec's implement serializable
- private transient EOEditingContext defaultEditingContext;
-
- private NSMutableDictionary state;
- private NSMutableDictionary pages;
- private NSMutableDictionary permanentPages;
- private NSMutableArray stateStack;
- private NSMutableArray pageStack;
- private NSMutableArray permanentPageStack;
- private boolean terminating;
-
- // used by WOResourceManager to cache dynamic resources
- transient NSMutableDictionary dynamicDataCache;
-
- public static final String WOSessionDidTimeOutNotification
- = "WOSessionDidTimeOutNotification";
- public static final String WOSessionDidRestoreNotification
- = "WOSessionDidRestoreNotification";
- public static final String WOSessionDidCreateNotification
- = "WOSessionDidCreateNotification";
-
- /**
- * Default constructor. This is called implicitly by
- * subclasses in all cases.
- */
- public WOSession ()
- {
- session = null;
- state = new NSMutableDictionary();
- pages = new NSMutableDictionary();
- permanentPages = new NSMutableDictionary();
- stateStack = NSMutableArray.mutableArrayBackedByList( new LinkedList() );
- pageStack = NSMutableArray.mutableArrayBackedByList( new LinkedList() );
- permanentPageStack = NSMutableArray.mutableArrayBackedByList( new LinkedList() );
- defaultEditingContext = null;
- terminating = false;
- }
-
- /**
- * Package method to initialize the backing session.
- */
- void setServletSession( HttpSession aSession )
- {
- session = aSession;
- }
-
- /**
- * Package method to set the current context.
- */
- void setContext( WOContext aContext )
- {
- context = aContext;
- }
-
- /**
- * Returns the id of the current session. If no session
- * currently exists, return null.
- */
- public String sessionID ()
- {
- if ( session != null )
- {
- return session.getId();
- }
- return null;
- }
-
- /**
- * Sets whether distribution is currently enabled.
- * This method is not implemented by this implementation
- * as the servlet container manages distribution.
- */
- public void setDistributionEnabled (boolean enabled)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether the session is part of a distributed application.
- * This implementation always returns false.
- */
- public boolean isDistributionEnabled ()
- {
- return false;
- }
-
- /**
- * Sets whether session ids should be stored in cookies.
- * This method is not implemented in this implementation
- * as the servlet container manages sessions with cookies.
- */
- public void setStoresIDsInCookies (boolean cookies)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether session ids are currently stored in cookies.
- * This implementation always returns true.
- */
- public boolean storesIDsInCookies ()
- {
- return true;
- }
-
- /**
- * Returns the current expiration date for cookies that store session ids.
- */
- public NSDate expirationDateForIDCookies ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets whether session ids should be stored in urls.
- * This method is not implemented in this implementation
- * as the servlet container manages sessions with cookies.
- */
- public void setStoresIDsInURLs (boolean urls)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether session ids are currently stored in urls.
- * This implementation always returns false.
- */
- public boolean storesIDsInURLs ()
- {
- return false;
- }
-
- /**
- * Returns the current domain for cookies containing session ids.
- */
- public String domainForIDCookies ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Terminates this session after the completion of the current response.
- */
- public void terminate ()
- {
- terminating = true;
- session.invalidate();
- }
-
- /**
- * Returns whether the current session will terminate at the completion
- * of the current response.
- */
- public boolean isTerminating ()
- {
- return terminating;
- }
-
- /**
- * Sets the number of seconds after the last request before
- * the session should be terminated.
- */
- public void setTimeOut (double timeout)
- {
- session.setMaxInactiveInterval( (int) timeout );
- }
-
- /**
- * Returns the number of seconds after the last request before
- * the session should be terminated.
- */
- public double timeOut ()
- {
- return session.getMaxInactiveInterval();
- }
-
- /**
- * Sets the languages for which this session has been localized,
- * in order of preference. The application will be responsible for
- * localizing the content based on the languages found in this array.
- */
- public void setLanguages (NSArray anArray)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns the languages for which this session has been localized,
- * in order of preference. The application will be responsible for
- * localizing the content based on the languages found in this array.
- */
- public NSArray languages ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Stores the specified key-value pair in the session.
- */
- public void setObjectForKey (Object anObject, String aKey)
- {
- state.setObjectForKey( anObject, aKey );
- }
-
- /**
- * Returns the session value associated with the specified key.
- */
- public Object objectForKey (String aKey)
- {
- return state.objectForKey( aKey );
- }
-
- /**
- * Removes the session value associated with the specified key.
- */
- public void removeObjectForKey (String aKey)
- {
- state.removeObjectForKey( aKey );
- }
-
- /**
- * Returns the context for the current request.
- */
- public WOContext context ()
- {
- return context;
- }
-
- /**
- * Invoked at the beginning of the request-response cycle.
- * Override to perform any kind of initialization at the
- * start of a request. This implementation does nothing.
- */
- public void awake ()
- {
-
- }
-
- /**
- * Invoked by the Application to extract user-assigned balues
- * and assign them to attributes. This implementation calls
- * takeValuesFromRequest on the top-level component.
- */
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
- context().component().takeValuesFromRequest( aRequest, aContext );
- }
-
- /**
- * Invoked by the Application to determine which component is the
- * intended recipient of the user's action. This implementation calls
- * invokeAction on the top-level component.
- */
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- return context().component().invokeAction( aRequest, aContext );
- }
-
- /**
- * Invoked by the Application to generate the content of the response.
- * This implementation calls appendToResponse on the top-level component.
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- context().component().appendToResponse( aResponse, aContext );
- }
-
- /**
- * Invoked at the end of the request-response cycle.
- * Override to perform any kind of clean-up at the
- * end of a request. This implementation does nothing.
- */
- public void sleep ()
- {
-
- }
-
- /**
- * Returns a list of pages accessed by this session in order
- * of their access and named by calling WOComponent.descriptionForResponse.
- */
- public NSArray statistics ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Puts this page in the session's page cache using the current
- * context id as the key.
- */
- public void savePage (WOComponent aComponent)
- {
- currentPage = aComponent;
- currentContextID = context.contextID();
-
- if ( pages.objectForKey( currentContextID ) == null )
- {
- byte[] data = KeyValueCodingUtilities.freeze(
- aComponent, defaultEditingContext(), aComponent, true );
- System.out.println( "WOSession.savePage: " + currentContextID + " : " + data.length );
-
- pages.setObjectForKey( data, currentContextID );
- pageStack.addObject( currentContextID );
- if ( pageStack.count() > context().application().pageCacheSize() )
- {
- String id = pageStack.remove( 0 ).toString(); // removeObjectAtIndex
- System.out.println( "WOSession.savePage: removing from cache: " + id );
- pages.removeObjectForKey( id );
- }
- }
- //System.out.println( "savePage: " + this + " : " + id + " : " + pages );
- }
-
- /**
- * Returns the page in the session's page cache corresponding to
- * the specified context id. Any special permanent caches are
- * searched before the standard page cache.
- */
- public WOComponent restorePageForContextID (String anID)
- {
- if ( anID == null ) return null;
- if ( anID.equals( currentContextID ) ) return currentPage;
-
- WOComponent result = null;
- byte[] data = (byte[]) permanentPages.objectForKey( anID );
- if ( data == null ) data = (byte[]) pages.objectForKey( anID );
- if ( data != null )
- {
- System.out.println( "WOSession.restorePageForContextID: " + anID + " : " + data.length );
- result = (WOComponent) KeyValueCodingUtilities.thaw(
- data, defaultEditingContext(),
- WOApplication.application().getClass().getClassLoader(), true );
- }
- //System.out.println( "restorePageForContextID: " + this + " : " + anID + " : " + result + " : " + pages );
- return result;
- }
-
- /**
- * Puts this page in the special cache is will not get automatically
- * flushed like the session page cache. Use this if the page
- * is likely to be around for a while, specifically pages within
- * frames.
- */
- public void savePageInPermanentCache (WOComponent aComponent)
- {
- currentPage = aComponent;
- currentContextID = context.contextID();
-
- if ( permanentPages.objectForKey( currentContextID ) == null )
- {
- byte[] data = KeyValueCodingUtilities.freeze(
- aComponent, defaultEditingContext(), aComponent, true );
- //System.out.println( "WOSession.savePageInPermanentCache: "
- // + currentContextID + " : " + data.length );
-
- permanentPages.setObjectForKey( data, currentContextID );
- permanentPageStack.addObject( currentContextID );
- if ( permanentPageStack.count() > context().application().pageCacheSize() )
- {
- String id = permanentPageStack.remove( 0 ).toString(); // removeObjectAtIndex
- permanentPages.removeObjectForKey( id );
- }
- }
- }
-
- /**
- * Writes a message to the standard error stream.
- */
- public static void logString (String aString)
- {
- System.err.println( aString );
- }
-
- /**
- * Writes a message to the standard error stream
- * if debugging is activated.
- */
- public static void debugString (String aString)
- {
- // TODO: Check to see if debugging is enabled.
- System.err.println( aString );
- }
-
- /**
- * Returns the default editing context used by this session.
- * Defaults to null.
- */
- public EOEditingContext defaultEditingContext ()
- {
- return defaultEditingContext;
- }
-
- /**
- * Sets the default editing context used by this session.
- */
- public void setDefaultEditingContext (EOEditingContext aContext)
- {
- defaultEditingContext = aContext;
- }
-
- // interface NSKeyValueCodingAdditions
-
- public Object valueForKeyPath (String aPath)
- {
- // currently key value coding support also handles keypaths
- return valueForKey( aPath );
- }
-
- public void takeValueForKeyPath (Object aValue, String aPath)
- {
- // currently key value coding support also handles keypaths
- takeValueForKey( aValue, aPath );
- }
-
- public NSDictionary valuesForKeys (List aKeyList)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public void takeValuesFromDictionary (Map aValueMap)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public Object valueForKey (String aKey)
- { // System.out.println( "valueForKey: " + aKey + "->" + this );
- Object result = objectForKey( aKey );
- if ( result == null )
- result = NSKeyValueCodingSupport.valueForKey( this, aKey );
- return result;
- }
-
- public void takeValueForKey (Object aValue, String aKey)
- { // System.out.println( "takeValueForKey: " + aKey + " : " + aValue + "->" + this );
- setObjectForKey( aValue, aKey );
- }
-
- public Object storedValueForKey (String aKey)
- {
- Object result = objectForKey( aKey );
- if ( result == null )
- NSKeyValueCodingSupport.storedValueForKey( this, aKey );
- return result;
- }
-
- public void takeStoredValueForKey (Object aValue, String aKey)
- {
- setObjectForKey( aValue, aKey );
- }
-
- public Object handleQueryWithUnboundKey (String aKey)
- {
- return NSKeyValueCodingSupport.handleQueryWithUnboundKey( this, aKey );
- }
-
- public void handleTakeValueForUnboundKey (Object aValue, String aKey)
- {
- NSKeyValueCodingSupport.handleTakeValueForUnboundKey( this, aValue, aKey );
- }
-
- public void unableToSetNullForKey (String aKey)
- {
- NSKeyValueCodingSupport.unableToSetNullForKey( this, aKey );
- }
-
- public Object validateTakeValueForKeyPath (Object aValue, String aKey)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
+ * A pure java implementation of WOSession.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOSession implements Serializable, NSKeyValueCodingAdditions {
+ // NOTE: need to set this when deserialized and on creation
+ transient private HttpSession session;
+
+ // the current context
+ transient private WOContext context;
+
+ // the last requested page: an optimization
+ transient private WOComponent currentPage;
+ // the last requested page's context id
+ transient private String currentContextID;
+
+ // FIXME: transient until ec's implement serializable
+ private transient EOEditingContext defaultEditingContext;
+
+ private NSMutableDictionary state;
+ private NSMutableDictionary pages;
+ private NSMutableDictionary permanentPages;
+ private NSMutableArray stateStack;
+ private NSMutableArray pageStack;
+ private NSMutableArray permanentPageStack;
+ private boolean terminating;
+
+ // used by WOResourceManager to cache dynamic resources
+ transient NSMutableDictionary dynamicDataCache;
+
+ public static final String WOSessionDidTimeOutNotification = "WOSessionDidTimeOutNotification";
+ public static final String WOSessionDidRestoreNotification = "WOSessionDidRestoreNotification";
+ public static final String WOSessionDidCreateNotification = "WOSessionDidCreateNotification";
+
+ /**
+ * Default constructor. This is called implicitly by subclasses in all cases.
+ */
+ public WOSession() {
+ session = null;
+ state = new NSMutableDictionary();
+ pages = new NSMutableDictionary();
+ permanentPages = new NSMutableDictionary();
+ stateStack = NSMutableArray.mutableArrayBackedByList(new LinkedList());
+ pageStack = NSMutableArray.mutableArrayBackedByList(new LinkedList());
+ permanentPageStack = NSMutableArray.mutableArrayBackedByList(new LinkedList());
+ defaultEditingContext = null;
+ terminating = false;
+ }
+
+ /**
+ * Package method to initialize the backing session.
+ */
+ void setServletSession(HttpSession aSession) {
+ session = aSession;
+ }
+
+ /**
+ * Package method to set the current context.
+ */
+ void setContext(WOContext aContext) {
+ context = aContext;
+ }
+
+ /**
+ * Returns the id of the current session. If no session currently exists, return
+ * null.
+ */
+ public String sessionID() {
+ if (session != null) {
+ return session.getId();
+ }
+ return null;
+ }
+
+ /**
+ * Sets whether distribution is currently enabled. This method is not
+ * implemented by this implementation as the servlet container manages
+ * distribution.
+ */
+ public void setDistributionEnabled(boolean enabled) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether the session is part of a distributed application. This
+ * implementation always returns false.
+ */
+ public boolean isDistributionEnabled() {
+ return false;
+ }
+
+ /**
+ * Sets whether session ids should be stored in cookies. This method is not
+ * implemented in this implementation as the servlet container manages sessions
+ * with cookies.
+ */
+ public void setStoresIDsInCookies(boolean cookies) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether session ids are currently stored in cookies. This
+ * implementation always returns true.
+ */
+ public boolean storesIDsInCookies() {
+ return true;
+ }
+
+ /**
+ * Returns the current expiration date for cookies that store session ids.
+ */
+ public NSDate expirationDateForIDCookies() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets whether session ids should be stored in urls. This method is not
+ * implemented in this implementation as the servlet container manages sessions
+ * with cookies.
+ */
+ public void setStoresIDsInURLs(boolean urls) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether session ids are currently stored in urls. This implementation
+ * always returns false.
+ */
+ public boolean storesIDsInURLs() {
+ return false;
+ }
+
+ /**
+ * Returns the current domain for cookies containing session ids.
+ */
+ public String domainForIDCookies() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Terminates this session after the completion of the current response.
+ */
+ public void terminate() {
+ terminating = true;
+ session.invalidate();
+ }
+
+ /**
+ * Returns whether the current session will terminate at the completion of the
+ * current response.
+ */
+ public boolean isTerminating() {
+ return terminating;
+ }
+
+ /**
+ * Sets the number of seconds after the last request before the session should
+ * be terminated.
+ */
+ public void setTimeOut(double timeout) {
+ session.setMaxInactiveInterval((int) timeout);
+ }
+
+ /**
+ * Returns the number of seconds after the last request before the session
+ * should be terminated.
+ */
+ public double timeOut() {
+ return session.getMaxInactiveInterval();
+ }
+
+ /**
+ * Sets the languages for which this session has been localized, in order of
+ * preference. The application will be responsible for localizing the content
+ * based on the languages found in this array.
+ */
+ public void setLanguages(NSArray anArray) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns the languages for which this session has been localized, in order of
+ * preference. The application will be responsible for localizing the content
+ * based on the languages found in this array.
+ */
+ public NSArray languages() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Stores the specified key-value pair in the session.
+ */
+ public void setObjectForKey(Object anObject, String aKey) {
+ state.setObjectForKey(anObject, aKey);
+ }
+
+ /**
+ * Returns the session value associated with the specified key.
+ */
+ public Object objectForKey(String aKey) {
+ return state.objectForKey(aKey);
+ }
+
+ /**
+ * Removes the session value associated with the specified key.
+ */
+ public void removeObjectForKey(String aKey) {
+ state.removeObjectForKey(aKey);
+ }
+
+ /**
+ * Returns the context for the current request.
+ */
+ public WOContext context() {
+ return context;
+ }
+
+ /**
+ * Invoked at the beginning of the request-response cycle. Override to perform
+ * any kind of initialization at the start of a request. This implementation
+ * does nothing.
+ */
+ public void awake() {
+
+ }
+
+ /**
+ * Invoked by the Application to extract user-assigned balues and assign them to
+ * attributes. This implementation calls takeValuesFromRequest on the top-level
+ * component.
+ */
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ context().component().takeValuesFromRequest(aRequest, aContext);
+ }
+
+ /**
+ * Invoked by the Application to determine which component is the intended
+ * recipient of the user's action. This implementation calls invokeAction on the
+ * top-level component.
+ */
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ return context().component().invokeAction(aRequest, aContext);
+ }
+
+ /**
+ * Invoked by the Application to generate the content of the response. This
+ * implementation calls appendToResponse on the top-level component.
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ context().component().appendToResponse(aResponse, aContext);
+ }
+
+ /**
+ * Invoked at the end of the request-response cycle. Override to perform any
+ * kind of clean-up at the end of a request. This implementation does nothing.
+ */
+ public void sleep() {
+
+ }
+
+ /**
+ * Returns a list of pages accessed by this session in order of their access and
+ * named by calling WOComponent.descriptionForResponse.
+ */
+ public NSArray statistics() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Puts this page in the session's page cache using the current context id as
+ * the key.
+ */
+ public void savePage(WOComponent aComponent) {
+ currentPage = aComponent;
+ currentContextID = context.contextID();
+
+ if (pages.objectForKey(currentContextID) == null) {
+ byte[] data = KeyValueCodingUtilities.freeze(aComponent, defaultEditingContext(), aComponent, true);
+ System.out.println("WOSession.savePage: " + currentContextID + " : " + data.length);
+
+ pages.setObjectForKey(data, currentContextID);
+ pageStack.addObject(currentContextID);
+ if (pageStack.count() > context().application().pageCacheSize()) {
+ String id = pageStack.remove(0).toString(); // removeObjectAtIndex
+ System.out.println("WOSession.savePage: removing from cache: " + id);
+ pages.removeObjectForKey(id);
+ }
+ }
+ // System.out.println( "savePage: " + this + " : " + id + " : " + pages );
+ }
+
+ /**
+ * Returns the page in the session's page cache corresponding to the specified
+ * context id. Any special permanent caches are searched before the standard
+ * page cache.
+ */
+ public WOComponent restorePageForContextID(String anID) {
+ if (anID == null)
+ return null;
+ if (anID.equals(currentContextID))
+ return currentPage;
+
+ WOComponent result = null;
+ byte[] data = (byte[]) permanentPages.objectForKey(anID);
+ if (data == null)
+ data = (byte[]) pages.objectForKey(anID);
+ if (data != null) {
+ System.out.println("WOSession.restorePageForContextID: " + anID + " : " + data.length);
+ result = (WOComponent) KeyValueCodingUtilities.thaw(data, defaultEditingContext(),
+ WOApplication.application().getClass().getClassLoader(), true);
+ }
+ // System.out.println( "restorePageForContextID: " + this + " : " + anID + " : "
+ // + result + " : " + pages );
+ return result;
+ }
+
+ /**
+ * Puts this page in the special cache is will not get automatically flushed
+ * like the session page cache. Use this if the page is likely to be around for
+ * a while, specifically pages within frames.
+ */
+ public void savePageInPermanentCache(WOComponent aComponent) {
+ currentPage = aComponent;
+ currentContextID = context.contextID();
+
+ if (permanentPages.objectForKey(currentContextID) == null) {
+ byte[] data = KeyValueCodingUtilities.freeze(aComponent, defaultEditingContext(), aComponent, true);
+ // System.out.println( "WOSession.savePageInPermanentCache: "
+ // + currentContextID + " : " + data.length );
+
+ permanentPages.setObjectForKey(data, currentContextID);
+ permanentPageStack.addObject(currentContextID);
+ if (permanentPageStack.count() > context().application().pageCacheSize()) {
+ String id = permanentPageStack.remove(0).toString(); // removeObjectAtIndex
+ permanentPages.removeObjectForKey(id);
+ }
+ }
+ }
+
+ /**
+ * Writes a message to the standard error stream.
+ */
+ public static void logString(String aString) {
+ System.err.println(aString);
+ }
+
+ /**
+ * Writes a message to the standard error stream if debugging is activated.
+ */
+ public static void debugString(String aString) {
+ // TODO: Check to see if debugging is enabled.
+ System.err.println(aString);
+ }
+
+ /**
+ * Returns the default editing context used by this session. Defaults to null.
+ */
+ public EOEditingContext defaultEditingContext() {
+ return defaultEditingContext;
+ }
+
+ /**
+ * Sets the default editing context used by this session.
+ */
+ public void setDefaultEditingContext(EOEditingContext aContext) {
+ defaultEditingContext = aContext;
+ }
+
+ // interface NSKeyValueCodingAdditions
+
+ public Object valueForKeyPath(String aPath) {
+ // currently key value coding support also handles keypaths
+ return valueForKey(aPath);
+ }
+
+ public void takeValueForKeyPath(Object aValue, String aPath) {
+ // currently key value coding support also handles keypaths
+ takeValueForKey(aValue, aPath);
+ }
+
+ public NSDictionary valuesForKeys(List aKeyList) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public void takeValuesFromDictionary(Map aValueMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public Object valueForKey(String aKey) { // System.out.println( "valueForKey: " + aKey + "->" + this );
+ Object result = objectForKey(aKey);
+ if (result == null)
+ result = NSKeyValueCodingSupport.valueForKey(this, aKey);
+ return result;
+ }
+
+ public void takeValueForKey(Object aValue, String aKey) { // System.out.println( "takeValueForKey: " + aKey + " : "
+ // + aValue + "->" + this );
+ setObjectForKey(aValue, aKey);
+ }
+
+ public Object storedValueForKey(String aKey) {
+ Object result = objectForKey(aKey);
+ if (result == null)
+ NSKeyValueCodingSupport.storedValueForKey(this, aKey);
+ return result;
+ }
+
+ public void takeStoredValueForKey(Object aValue, String aKey) {
+ setObjectForKey(aValue, aKey);
+ }
+
+ public Object handleQueryWithUnboundKey(String aKey) {
+ return NSKeyValueCodingSupport.handleQueryWithUnboundKey(this, aKey);
+ }
+
+ public void handleTakeValueForUnboundKey(Object aValue, String aKey) {
+ NSKeyValueCodingSupport.handleTakeValueForUnboundKey(this, aValue, aKey);
+ }
+
+ public void unableToSetNullForKey(String aKey) {
+ NSKeyValueCodingSupport.unableToSetNullForKey(this, aKey);
+ }
+
+ public Object validateTakeValueForKeyPath(Object aValue, String aKey) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSessionStore.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSessionStore.java
index f91a433..3008f21 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSessionStore.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSessionStore.java
@@ -19,75 +19,67 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web;
/**
-* An abstract class defining the requirements for persisting
-* session state across user transactions. Used by WOApplication
-* to persist sessions between requests.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public abstract class WOSessionStore
-{
- private static WOSessionStore serverSessionStore = null;
-
- /**
- * Returns the default session store used by WOApplication.
- */
- public static WOSessionStore serverSessionStore()
- {
- if ( serverSessionStore == null )
- {
- serverSessionStore = new WOServletSessionStore();
- }
- return serverSessionStore;
- }
+ * An abstract class defining the requirements for persisting session state
+ * across user transactions. Used by WOApplication to persist sessions between
+ * requests.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public abstract class WOSessionStore {
+ private static WOSessionStore serverSessionStore = null;
+
+ /**
+ * Returns the default session store used by WOApplication.
+ */
+ public static WOSessionStore serverSessionStore() {
+ if (serverSessionStore == null) {
+ serverSessionStore = new WOServletSessionStore();
+ }
+ return serverSessionStore;
+ }
- /**
- * Called by WOApplication after the request-response cycle has ended.
- * The context's session will again be available for subsequent requests.
- */
- public final void checkInSessionForContext(WOContext aContext)
- {
- saveSessionForContext( aContext );
- }
-
- /**
- * Returns the session with the specified id for the specified request,
- * or null if none exist. Subsequent calls for the same id will return
- * null until the session is checked in again.
- * Called by WOApplication before the request-response cycle starts.
- */
- public final WOSession checkOutSessionWithID(String sessionID, WORequest aRequest)
- {
- return restoreSessionWithID( sessionID, aRequest );
- }
+ /**
+ * Called by WOApplication after the request-response cycle has ended. The
+ * context's session will again be available for subsequent requests.
+ */
+ public final void checkInSessionForContext(WOContext aContext) {
+ saveSessionForContext(aContext);
+ }
- /**
- * Removes the WOSession for the specified ID from the store and returns it.
- */
- public abstract WOSession removeSessionWithID(String sessionID);
-
- /**
- * Returns the WOSession for the specified ID from the store.
- */
- public abstract WOSession restoreSessionWithID(String sessionID,
- WORequest aRequest);
-
- /**
- * Places the context's session into the store.
- */
- public abstract void saveSessionForContext(WOContext context);
+ /**
+ * Returns the session with the specified id for the specified request, or null
+ * if none exist. Subsequent calls for the same id will return null until the
+ * session is checked in again. Called by WOApplication before the
+ * request-response cycle starts.
+ */
+ public final WOSession checkOutSessionWithID(String sessionID, WORequest aRequest) {
+ return restoreSessionWithID(sessionID, aRequest);
+ }
+
+ /**
+ * Removes the WOSession for the specified ID from the store and returns it.
+ */
+ public abstract WOSession removeSessionWithID(String sessionID);
+
+ /**
+ * Returns the WOSession for the specified ID from the store.
+ */
+ public abstract WOSession restoreSessionWithID(String sessionID, WORequest aRequest);
+
+ /**
+ * Places the context's session into the store.
+ */
+ public abstract void saveSessionForContext(WOContext context);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/01/07 20:48:29 mpowers
- * Implemented WOSessionStore and WOServletSessionStore.
+ * Revision 1.1 2003/01/07 20:48:29 mpowers Implemented WOSessionStore and
+ * WOServletSessionStore.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOStaticElement.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOStaticElement.java
index 308cd20..29a06c4 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOStaticElement.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOStaticElement.java
@@ -19,52 +19,44 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web;
/**
-* This class represents a static portion of a web page.
-* Package access only, as it is not in the specification.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-class WOStaticElement extends WOElement
-{
+ * This class represents a static portion of a web page. Package access only, as
+ * it is not in the specification.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+class WOStaticElement extends WOElement {
String content;
/**
- * Default constructor.
- */
- public WOStaticElement()
- {
+ * Default constructor.
+ */
+ public WOStaticElement() {
content = null;
}
-
+
/**
- * Returns a static element representing the specified content.
- */
- public WOStaticElement( String aContentString )
- {
+ * Returns a static element representing the specified content.
+ */
+ public WOStaticElement(String aContentString) {
this();
content = aContentString;
}
- /**
- * Overridden to append the content string..
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- aResponse.appendContentString( content );
- }
-
-
- public WOResponse generateResponse()
- {
- WOResponse r = new WOResponse();
- if (content != null)
- {
- r.appendContentString(content);
- }
- return r;
- }
-
-
+ /**
+ * Overridden to append the content string..
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ aResponse.appendContentString(content);
+ }
+
+ public WOResponse generateResponse() {
+ WOResponse r = new WOResponse();
+ if (content != null) {
+ r.appendContentString(content);
+ }
+ return r;
+ }
+
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOString.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOString.java
index ef5b771..0c471d7 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOString.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOString.java
@@ -25,112 +25,87 @@ import net.wotonomy.foundation.NSNumberFormatter;
import net.wotonomy.foundation.NSTimestampFormatter;
/**
-* WOString renders a dynamically generated string in the output.
-* Bindings are:
-* <ul>
-* <li>value: a property returning a value which will be rendered as the
-* output. If a formatter is not used, then the value must be convertable
-* to a String with toString().</li>
-* <li>escapeHTML: a property returning a value convertable to a Boolean
-* indicating whether the any html characters in the output should be
-* escaped so they are shown as html characters rather than interpreted
-* as html.</li>
-* <li>formatter: a property returning a Format object that will be
-* used to format the value into a String.</li>
-* <li>dateformat: a property returning a DateFormat object that will be
-* used to format the value into a String.</li>
-* <li>numberformat: a property returning a NumberFormat object that will be
-* used to format the value into a String. Not yet implemented.</li>
-* <li>valueWhenEmpty: a property returning a String that will be used
-* in place of an empty or null value. Not yet implemented.</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOString extends WODynamicElement
-{
+ * WOString renders a dynamically generated string in the output. Bindings are:
+ * <ul>
+ * <li>value: a property returning a value which will be rendered as the output.
+ * If a formatter is not used, then the value must be convertable to a String
+ * with toString().</li>
+ * <li>escapeHTML: a property returning a value convertable to a Boolean
+ * indicating whether the any html characters in the output should be escaped so
+ * they are shown as html characters rather than interpreted as html.</li>
+ * <li>formatter: a property returning a Format object that will be used to
+ * format the value into a String.</li>
+ * <li>dateformat: a property returning a DateFormat object that will be used to
+ * format the value into a String.</li>
+ * <li>numberformat: a property returning a NumberFormat object that will be
+ * used to format the value into a String. Not yet implemented.</li>
+ * <li>valueWhenEmpty: a property returning a String that will be used in place
+ * of an empty or null value. Not yet implemented.</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOString extends WODynamicElement {
protected Object value;
protected boolean escapeHTML;
protected Format formatter;
protected String dateformat;
protected String numberformat;
- protected Object valueWhenEmpty;
+ protected Object valueWhenEmpty;
/**
- * The default constructor.
- */
- protected WOString ()
- {
- }
-
- public WOString (
- String aName, NSDictionary anAssociationMap, WOElement aRootElement)
- {
- super( aName, anAssociationMap, aRootElement );
- escapeHTML = true;
- }
+ * The default constructor.
+ */
+ protected WOString() {
+ }
+
+ public WOString(String aName, NSDictionary anAssociationMap, WOElement aRootElement) {
+ super(aName, anAssociationMap, aRootElement);
+ escapeHTML = true;
+ }
+
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ WOComponent c = aContext.component();
+ numberformat = stringForProperty("numberformat", c);
+ dateformat = stringForProperty("dateformat", c);
+ formatter = (Format) valueForProperty("formatter", c);
+ escapeHTML = booleanForProperty("escapeHTML", c);
+ value = valueForProperty("value", c);
+ valueWhenEmpty = valueForProperty("valueWhenEmpty", c);
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- WOComponent c = aContext.component();
- numberformat = stringForProperty("numberformat", c );
- dateformat = stringForProperty("dateformat", c );
- formatter = (Format) valueForProperty("formatter", c );
- escapeHTML = booleanForProperty("escapeHTML", c );
- value = valueForProperty("value", c );
- valueWhenEmpty = valueForProperty("valueWhenEmpty", c );
-
- Object result = value;
- if ( result != null )
- {
- if ( formatter != null )
- {
- try
- {
- result = formatter.format( result );
- }
- catch ( IllegalArgumentException exc )
- {
- }
- }
- if ( dateformat != null )
- {
- try
- {
- result = new NSTimestampFormatter( dateformat ).format( result );
- }
- catch ( IllegalArgumentException exc )
- {
- }
- }
- if ( numberformat != null )
- {
- try
- {
- result = new NSNumberFormatter( numberformat ).format( result );
- }
- catch ( IllegalArgumentException exc )
- {
- }
- }
- }
- if ( result == null )
- {
- result = valueWhenEmpty;
- if ( result == null )
- {
- result = "nil";
- }
- }
- if ( escapeHTML )
- {
- aResponse.appendContentHTMLString( result.toString() );
- }
- else
- {
- aResponse.appendContentString( result.toString() );
+ Object result = value;
+ if (result != null) {
+ if (formatter != null) {
+ try {
+ result = formatter.format(result);
+ } catch (IllegalArgumentException exc) {
+ }
+ }
+ if (dateformat != null) {
+ try {
+ result = new NSTimestampFormatter(dateformat).format(result);
+ } catch (IllegalArgumentException exc) {
+ }
+ }
+ if (numberformat != null) {
+ try {
+ result = new NSNumberFormatter(numberformat).format(result);
+ } catch (IllegalArgumentException exc) {
+ }
+ }
+ }
+ if (result == null) {
+ result = valueWhenEmpty;
+ if (result == null) {
+ result = "nil";
+ }
+ }
+ if (escapeHTML) {
+ aResponse.appendContentHTMLString(result.toString());
+ } else {
+ aResponse.appendContentString(result.toString());
}
- }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSubmitButton.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSubmitButton.java
index 05824f3..a1ef303 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSubmitButton.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSubmitButton.java
@@ -22,49 +22,52 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableArray;
/**
-* Implements a submit button with dynamic bindings.
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+ * Implements a submit button with dynamic bindings.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOSubmitButton extends WOInput {
- public WOSubmitButton() {
- super();
- }
+ public WOSubmitButton() {
+ super();
+ }
- public WOSubmitButton(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOSubmitButton(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- protected String inputType() {
- return "SUBMIT";
- }
+ protected String inputType() {
+ return "SUBMIT";
+ }
- protected Object value(WOContext c) {
- Object v = valueForProperty("value", c.component());
- if (v == null) {
- return "Submit";
- }
- return v;
- }
+ protected Object value(WOContext c) {
+ Object v = valueForProperty("value", c.component());
+ if (v == null) {
+ return "Submit";
+ }
+ return v;
+ }
- protected NSMutableArray additionalAttributes() {
- NSMutableArray a = super.additionalAttributes();
- a.add("action");
- return a;
- }
+ protected NSMutableArray additionalAttributes() {
+ NSMutableArray a = super.additionalAttributes();
+ a.add("action");
+ return a;
+ }
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- if (disabled(c))
- return null;
- //It's useless to check the senderID here because it's going to be for the form always.
- //So we check if the formValues contain the button's name (which means it was pressed)
- if (r.formValueForKey(inputName(c)) != null) {
- if (associations.objectForKey("action") != null)
- return (WOActionResults)valueForProperty("action", c.component());
- }
- return null;
- }
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ if (disabled(c))
+ return null;
+ // It's useless to check the senderID here because it's going to be for the form
+ // always.
+ // So we check if the formValues contain the button's name (which means it was
+ // pressed)
+ if (r.formValueForKey(inputName(c)) != null) {
+ if (associations.objectForKey("action") != null)
+ return (WOActionResults) valueForProperty("action", c.component());
+ }
+ return null;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSwitchComponent.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSwitchComponent.java
index d2e373a..6f42199 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSwitchComponent.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSwitchComponent.java
@@ -23,90 +23,78 @@ import net.wotonomy.foundation.NSMutableDictionary;
public class WOSwitchComponent extends WODynamicElement {
- private NSMutableDictionary elements;
- private String currentName;
- private WOElement currentElement;
-
- protected WOSwitchComponent()
- {
- super();
- elements = new NSMutableDictionary();
- }
-
- public WOSwitchComponent(String aName, NSDictionary aMap, WOElement template)
- {
- super(aName, aMap, template);
- elements = new NSMutableDictionary();
- }
-
- private WOElement getCurrentElement( WOContext c )
- {
- String name = stringForProperty( "WOComponentName", c.component() );
- if ( name == null ) return null;
-
- if ( currentElement != null && name.equals( currentName ) ) return currentElement;
-
- currentName = name;
- currentElement = (WOElement) elements.objectForKey( name );
- if ( currentElement == null )
- {
- currentElement = WOApplication.application().pageWithName( name, c );
- if ( currentElement != null )
- {
- currentElement.associations = associations;
- elements.setObjectForKey( currentElement, name );
- }
- }
-
- return currentElement;
- }
-
- void ensureAwakeInContext (WOContext aContext)
- {
- if ( aContext != null )
- {
- WOElement element = getCurrentElement( aContext );
- if ( element != null )
- {
- aContext.pushElement( element );
- element.ensureAwakeInContext( aContext );
- aContext.popElement();
- }
- }
- }
-
- public void takeValuesFromRequest(WORequest r, WOContext c)
- {
- WOElement element = getCurrentElement( c );
- if ( element != null )
- {
- c.pushElement( element );
- element.takeValuesFromRequest( r, c );
- c.popElement();
- }
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c)
- {
- WOActionResults result = null;
- WOElement element = getCurrentElement( c );
- if ( element != null )
- {
- c.pushElement( element );
- result = element.invokeAction( r, c );
- c.popElement();
- }
- return result;
- }
-
- public void appendToResponse(WOResponse r, WOContext c)
- {
- WOElement element = getCurrentElement( c );
- if ( element != null )
- {
- c.pushElement( element );
- element.appendToResponse( r, c );
- c.popElement();
- }
- }
+ private NSMutableDictionary elements;
+ private String currentName;
+ private WOElement currentElement;
+
+ protected WOSwitchComponent() {
+ super();
+ elements = new NSMutableDictionary();
+ }
+
+ public WOSwitchComponent(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ elements = new NSMutableDictionary();
+ }
+
+ private WOElement getCurrentElement(WOContext c) {
+ String name = stringForProperty("WOComponentName", c.component());
+ if (name == null)
+ return null;
+
+ if (currentElement != null && name.equals(currentName))
+ return currentElement;
+
+ currentName = name;
+ currentElement = (WOElement) elements.objectForKey(name);
+ if (currentElement == null) {
+ currentElement = WOApplication.application().pageWithName(name, c);
+ if (currentElement != null) {
+ currentElement.associations = associations;
+ elements.setObjectForKey(currentElement, name);
+ }
+ }
+
+ return currentElement;
+ }
+
+ void ensureAwakeInContext(WOContext aContext) {
+ if (aContext != null) {
+ WOElement element = getCurrentElement(aContext);
+ if (element != null) {
+ aContext.pushElement(element);
+ element.ensureAwakeInContext(aContext);
+ aContext.popElement();
+ }
+ }
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ WOElement element = getCurrentElement(c);
+ if (element != null) {
+ c.pushElement(element);
+ element.takeValuesFromRequest(r, c);
+ c.popElement();
+ }
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ WOActionResults result = null;
+ WOElement element = getCurrentElement(c);
+ if (element != null) {
+ c.pushElement(element);
+ result = element.invokeAction(r, c);
+ c.popElement();
+ }
+ return result;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ WOElement element = getCurrentElement(c);
+ if (element != null) {
+ c.pushElement(element);
+ element.appendToResponse(r, c);
+ c.popElement();
+ }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOText.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOText.java
index 008fda8..3b5dd1d 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOText.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOText.java
@@ -22,20 +22,21 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
/**
-* Implements a TEXTAREA element, with dynamic bindings.
+ * Implements a TEXTAREA element, with dynamic bindings.
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOText extends WOInput {
- public WOText() {
- super();
- }
+ public WOText() {
+ super();
+ }
- public WOText(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOText(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
protected String inputType() {
return "TEXTAREA";
@@ -49,24 +50,23 @@ public class WOText extends WOInput {
return formattedValue(fieldValue, c.component());
}
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- Object val = r.formValueForKey(inputName(c));
- if ( val != null )
- setValueForProperty("value", formattedValue(val, c.component()), c.component());
- }
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ Object val = r.formValueForKey(inputName(c));
+ if (val != null)
+ setValueForProperty("value", formattedValue(val, c.component()), c.component());
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString("<TEXTAREA NAME=\"");
- r.appendContentString(inputName(c));
- r.appendContentString("\"");
- String moreFields = additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "name", "value" }));
- if (moreFields != null && moreFields.length() > 0)
- r.appendContentString(moreFields);
- r.appendContentString(">");
- moreFields = value(c).toString();
- if (moreFields != null && moreFields.length() > 0)
- r.appendContentString(moreFields);
- r.appendContentString("</TEXTAREA>");
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<TEXTAREA NAME=\"");
+ r.appendContentString(inputName(c));
+ r.appendContentString("\"");
+ String moreFields = additionalHTMLProperties(c.component(), new NSArray(new Object[] { "name", "value" }));
+ if (moreFields != null && moreFields.length() > 0)
+ r.appendContentString(moreFields);
+ r.appendContentString(">");
+ moreFields = value(c).toString();
+ if (moreFields != null && moreFields.length() > 0)
+ r.appendContentString(moreFields);
+ r.appendContentString("</TEXTAREA>");
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOTextField.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOTextField.java
index 4233ad4..82f591a 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOTextField.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOTextField.java
@@ -22,38 +22,39 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableArray;
/**
-* Implements an INPUT tag of type TEXT, with dynamic bindings.
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+ * Implements an INPUT tag of type TEXT, with dynamic bindings.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOTextField extends WOInput {
- public WOTextField() {
- super();
- }
-
- public WOTextField(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
-
- protected String inputType() {
- return "TEXT";
- }
-
- protected Object value(WOContext c) {
- Object fieldValue = valueForProperty("value", c.component());
- if (fieldValue == null) {
- fieldValue = "";
- }
- return formattedValue(fieldValue, c.component());
- }
-
- protected NSMutableArray additionalAttributes() {
- NSMutableArray a = super.additionalAttributes();
- a.addObject("dateformat");
- a.addObject("numberformat");
- return a;
- }
+ public WOTextField() {
+ super();
+ }
+
+ public WOTextField(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
+
+ protected String inputType() {
+ return "TEXT";
+ }
+
+ protected Object value(WOContext c) {
+ Object fieldValue = valueForProperty("value", c.component());
+ if (fieldValue == null) {
+ fieldValue = "";
+ }
+ return formattedValue(fieldValue, c.component());
+ }
+
+ protected NSMutableArray additionalAttributes() {
+ NSMutableArray a = super.additionalAttributes();
+ a.addObject("dateformat");
+ a.addObject("numberformat");
+ return a;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/util/BrowserLauncher.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/util/BrowserLauncher.java
index 777d4a1..7a6a946 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/util/BrowserLauncher.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/util/BrowserLauncher.java
@@ -10,656 +10,644 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-/** <p> BrowserLauncher is a class that provides one static method,
- * openURL, which opens the default web browser for the current user
- * of the system to the given URL. It may support other protocols
- * depending on the system -- mailto, ftp, etc. -- but that has not
- * been rigorously tested and is not guaranteed to work. </p>
+/**
+ * <p>
+ * BrowserLauncher is a class that provides one static method, openURL, which
+ * opens the default web browser for the current user of the system to the given
+ * URL. It may support other protocols depending on the system -- mailto, ftp,
+ * etc. -- but that has not been rigorously tested and is not guaranteed to
+ * work.
+ * </p>
*
- * <p> Yes, this is platform-specific code, and yes, it may rely on
- * classes on certain platforms that are not part of the standard JDK.
- * What we're trying to do, though, is to take something that's
- * frequently desirable but inherently platform-specific -- opening a
- * default browser -- and allow programmers (you, for example) to do
- * so without worrying about dropping into native code or doing
- * anything else similarly evil. </p>
+ * <p>
+ * Yes, this is platform-specific code, and yes, it may rely on classes on
+ * certain platforms that are not part of the standard JDK. What we're trying to
+ * do, though, is to take something that's frequently desirable but inherently
+ * platform-specific -- opening a default browser -- and allow programmers (you,
+ * for example) to do so without worrying about dropping into native code or
+ * doing anything else similarly evil.
+ * </p>
*
- * <p> Anyway, this code is completely in Java and will run on all JDK
- * 1.1-compliant systems without modification or a need for additional
- * libraries. All classes that are required on certain platforms to
- * allow this to run are dynamically loaded at runtime via reflection
- * and, if not found, will not cause this to do anything other than
- * returning an error when opening the browser. </p>
+ * <p>
+ * Anyway, this code is completely in Java and will run on all JDK 1.1-compliant
+ * systems without modification or a need for additional libraries. All classes
+ * that are required on certain platforms to allow this to run are dynamically
+ * loaded at runtime via reflection and, if not found, will not cause this to do
+ * anything other than returning an error when opening the browser.
+ * </p>
*
- * <p> There are certain system requirements for this class, as it's
- * running through Runtime.exec(), which is Java's way of making a
- * native system call. Currently, this requires that a Macintosh have
- * a Finder which supports the GURL event, which is true for Mac OS
- * 8.0 and 8.1 systems that have the Internet Scripting AppleScript
- * dictionary installed in the Scripting Additions folder in the
- * Extensions folder (which is installed by default as far as I know
- * under Mac OS 8.0 and 8.1), and for all Mac OS 8.5 and later
- * systems. On Windows, it only runs under Win32 systems (Windows 95,
- * 98, and NT 4.0, as well as later versions of all). On other
- * systems, this drops back from the inherently platform-sensitive
- * concept of a default browser and simply attempts to launch Netscape
- * via a shell command. </p>
+ * <p>
+ * There are certain system requirements for this class, as it's running through
+ * Runtime.exec(), which is Java's way of making a native system call.
+ * Currently, this requires that a Macintosh have a Finder which supports the
+ * GURL event, which is true for Mac OS 8.0 and 8.1 systems that have the
+ * Internet Scripting AppleScript dictionary installed in the Scripting
+ * Additions folder in the Extensions folder (which is installed by default as
+ * far as I know under Mac OS 8.0 and 8.1), and for all Mac OS 8.5 and later
+ * systems. On Windows, it only runs under Win32 systems (Windows 95, 98, and NT
+ * 4.0, as well as later versions of all). On other systems, this drops back
+ * from the inherently platform-sensitive concept of a default browser and
+ * simply attempts to launch Netscape via a shell command.
+ * </p>
*
- * <p> This code is Copyright 1999-2001 by Eric Albert
- * (ejalbert@cs.stanford.edu) and may be redistributed or modified in
- * any form without restrictions as long as the portion of this
- * comment from this paragraph through the end of the comment is not
- * removed. The author requests that he be notified of any
- * application, applet, or other binary that makes use of this code,
- * but that's more out of curiosity than anything and is not required.
- * This software includes no warranty. The author is not repsonsible
- * for any loss of data or functionality or any adverse or unexpected
- * effects of using this software. </p>
+ * <p>
+ * This code is Copyright 1999-2001 by Eric Albert (ejalbert@cs.stanford.edu)
+ * and may be redistributed or modified in any form without restrictions as long
+ * as the portion of this comment from this paragraph through the end of the
+ * comment is not removed. The author requests that he be notified of any
+ * application, applet, or other binary that makes use of this code, but that's
+ * more out of curiosity than anything and is not required. This software
+ * includes no warranty. The author is not repsonsible for any loss of data or
+ * functionality or any adverse or unexpected effects of using this software.
+ * </p>
*
- * Credits: <br> Steven Spencer, JavaWorld magazine (<a
- * href="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java
- * Tip 66</a>) <br> Thanks also to Ron B. Yeh, Eric Shapiro, Ben
- * Engber, Paul Teitlebaum, Andrea Cantatore, Larry Barowski, Trevor
- * Bedzek, Frank Miedrich, and Ron Rabakukk
+ * Credits: <br>
+ * Steven Spencer, JavaWorld magazine
+ * (<a href="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java
+ * Tip 66</a>) <br>
+ * Thanks also to Ron B. Yeh, Eric Shapiro, Ben Engber, Paul Teitlebaum, Andrea
+ * Cantatore, Larry Barowski, Trevor Bedzek, Frank Miedrich, and Ron Rabakukk
*
*
- * original author Eric Albert (<a
- * href="mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu</a>)
+ * original author Eric Albert
+ * (<a href="mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu</a>)
* author's version 1.4b1 (Released June 20, 2001)
+ *
* @author Copyright 2001, Intersect Software Corporation
- * @version $Revision: 905 $ $Date: 2006-02-18 20:44:03 -0500 (Sat, 18 Feb 2006) $
+ * @version $Revision: 905 $ $Date: 2006-02-18 20:44:03 -0500 (Sat, 18 Feb 2006)
+ * $
*/
public class BrowserLauncher {
- /** The Java virtual machine that we are running on. Actually, in
- * most cases we only care about the operating system, but some
- * operating systems require us to switch on the VM. */
- private static int jvm;
+ /**
+ * The Java virtual machine that we are running on. Actually, in most cases we
+ * only care about the operating system, but some operating systems require us
+ * to switch on the VM.
+ */
+ private static int jvm;
- /** The browser for the system */
- private static Object browser;
+ /** The browser for the system */
+ private static Object browser;
- /** Caches whether any classes, methods, and fields that are not
- * part of the JDK and need to be dynamically loaded at runtime
- * loaded successfully. <p> Note that if this is
- * <code>false</code>, <code>openURL()</code> will always return
- * an IOException. */
- private static boolean loadedWithoutErrors;
+ /**
+ * Caches whether any classes, methods, and fields that are not part of the JDK
+ * and need to be dynamically loaded at runtime loaded successfully.
+ * <p>
+ * Note that if this is <code>false</code>, <code>openURL()</code> will always
+ * return an IOException.
+ */
+ private static boolean loadedWithoutErrors;
- /** The com.apple.mrj.MRJFileUtils class */
- private static Class mrjFileUtilsClass;
+ /** The com.apple.mrj.MRJFileUtils class */
+ private static Class mrjFileUtilsClass;
- /** The com.apple.mrj.MRJOSType class */
- private static Class mrjOSTypeClass;
+ /** The com.apple.mrj.MRJOSType class */
+ private static Class mrjOSTypeClass;
- /** The com.apple.MacOS.AEDesc class */
- private static Class aeDescClass;
+ /** The com.apple.MacOS.AEDesc class */
+ private static Class aeDescClass;
- /** The <init>(int) method of com.apple.MacOS.AETarget */
- private static Constructor aeTargetConstructor;
+ /** The <init>(int) method of com.apple.MacOS.AETarget */
+ private static Constructor aeTargetConstructor;
- /** The <init>(int, int, int) method of com.apple.MacOS.AppleEvent */
- private static Constructor appleEventConstructor;
+ /** The <init>(int, int, int) method of com.apple.MacOS.AppleEvent */
+ private static Constructor appleEventConstructor;
- /** The <init>(String) method of com.apple.MacOS.AEDesc */
- private static Constructor aeDescConstructor;
+ /** The <init>(String) method of com.apple.MacOS.AEDesc */
+ private static Constructor aeDescConstructor;
- /** The findFolder method of com.apple.mrj.MRJFileUtils */
- private static Method findFolder;
+ /** The findFolder method of com.apple.mrj.MRJFileUtils */
+ private static Method findFolder;
- /** The getFileCreator method of com.apple.mrj.MRJFileUtils */
- private static Method getFileCreator;
+ /** The getFileCreator method of com.apple.mrj.MRJFileUtils */
+ private static Method getFileCreator;
- /** The getFileType method of com.apple.mrj.MRJFileUtils */
- private static Method getFileType;
+ /** The getFileType method of com.apple.mrj.MRJFileUtils */
+ private static Method getFileType;
- /** The openURL method of com.apple.mrj.MRJFileUtils */
- private static Method openURL;
+ /** The openURL method of com.apple.mrj.MRJFileUtils */
+ private static Method openURL;
- /** The makeOSType method of com.apple.MacOS.OSUtils */
- private static Method makeOSType;
-
- /** The putParameter method of com.apple.MacOS.AppleEvent */
- private static Method putParameter;
-
- /** The sendNoReply method of com.apple.MacOS.AppleEvent */
- private static Method sendNoReply;
-
- /** Actually an MRJOSType pointing to the System Folder on a Macintosh */
- private static Object kSystemFolderType;
-
- /** The keyDirectObject AppleEvent parameter type */
- private static Integer keyDirectObject;
-
- /** The kAutoGenerateReturnID AppleEvent code */
- private static Integer kAutoGenerateReturnID;
-
- /** The kAnyTransactionID AppleEvent code */
- private static Integer kAnyTransactionID;
-
- /** The linkage object required for JDirect 3 on Mac OS X. */
- private static Object linkage;
-
- /** The framework to reference on Mac OS X */
- private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
-
- /** JVM constant for MRJ 2.0 */
- private static final int MRJ_2_0 = 0;
-
- /** JVM constant for MRJ 2.1 or later */
- private static final int MRJ_2_1 = 1;
-
- /** JVM constant for Java on Mac OS X 10.0 (MRJ 3.0) */
- private static final int MRJ_3_0 = 3;
-
- /** JVM constant for MRJ 3.1 */
- private static final int MRJ_3_1 = 4;
-
- /** JVM constant for any Windows NT JVM */
- private static final int WINDOWS_NT = 5;
-
- /** JVM constant for any Windows 9x JVM */
- private static final int WINDOWS_9x = 6;
-
- /** JVM constant for any other platform */
- private static final int OTHER = -1;
-
- /** The file type of the Finder on a Macintosh. Hardcoding
- * "Finder" would keep non-U.S. English systems from working
- * properly. */
- private static final String FINDER_TYPE = "FNDR";
-
- /** The creator code of the Finder on a Macintosh, which is needed
- * to send AppleEvents to the application. */
- private static final String FINDER_CREATOR = "MACS";
-
- /** The name for the AppleEvent type corresponding to a GetURL event. */
- private static final String GURL_EVENT = "GURL";
-
- /** The first parameter that needs to be passed into
- * Runtime.exec() to open the default web browser on Windows. */
- private static final String FIRST_WINDOWS_PARAMETER = "/c";
-
- /** The second parameter for Runtime.exec() on Windows. */
- private static final String SECOND_WINDOWS_PARAMETER = "start";
-
- /** The third parameter for Runtime.exec() on Windows. This is a
- * "title" parameter that the command line expects. Setting this
- * parameter allows URLs containing spaces to work. */
- private static final String THIRD_WINDOWS_PARAMETER = "\"\"";
-
- /** The shell parameters for Netscape that opens a given URL in an
- * already-open copy of Netscape on many command-line systems. */
- private static final String NETSCAPE_REMOTE_PARAMETER = "-remote";
- //private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
- //private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
- private static final String NETSCAPE_OPEN_PARAMETER_START = "openURL(";
- private static final String NETSCAPE_OPEN_PARAMETER_END = ")";
-
- /** The message from any exception thrown throughout the
- * initialization process. */
- private static String errorMessage;
-
- /** An initialization block that determines the operating system
- * and loads the necessary runtime data. */
- static {
- loadedWithoutErrors = true;
- String osName = System.getProperty("os.name");
- if (osName.startsWith("Mac OS")) {
- String mrjVersion = System.getProperty("mrj.version");
- String majorMRJVersion = mrjVersion.substring(0, 3);
- try {
- double version = Double.valueOf(majorMRJVersion).doubleValue();
- if (version == 2) {
- jvm = MRJ_2_0;
- } else if (version >= 2.1 && version < 3) {
- // Assume that all 2.x versions of MRJ work the
- // same. MRJ 2.1 actually works via
- // Runtime.exec() and 2.2 supports that but has an
- // openURL() method as well that we currently
- // ignore.
- jvm = MRJ_2_1;
- } else if (version == 3.0) {
- jvm = MRJ_3_0;
- } else if (version >= 3.1) {
- // Assume that all 3.1 and later versions of MRJ
- // work the same.
- jvm = MRJ_3_1;
- } else {
- loadedWithoutErrors = false;
- errorMessage = "Unsupported MRJ version: " + version;
- }
- } catch (NumberFormatException nfe) {
- loadedWithoutErrors = false;
- errorMessage = "Invalid MRJ version: " + mrjVersion;
- }
- } else if (osName.startsWith("Windows")) {
- if (osName.indexOf("9") != -1) {
- jvm = WINDOWS_9x;
- } else {
- jvm = WINDOWS_NT;
- }
- } else {
- jvm = OTHER;
- }
-
- if (loadedWithoutErrors) { // if we haven't hit any errors yet
- loadedWithoutErrors = loadClasses();
- }
- }
-
- /** This class should be never be instantiated; this just ensures so. */
- private BrowserLauncher() { }
-
- /** Called by a static initializer to load any classes, fields,
- * and methods required at runtime to locate the user's web
- * browser.
- * @return <code>true</code> if all intialization succeeded
- * <code>false</code> if any portion of the initialization failed */
- private static boolean loadClasses() {
- switch (jvm) {
- case MRJ_2_0:
- try {
- Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
- Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
- Class appleEventClass = Class.forName
- ("com.apple.MacOS.AppleEvent");
- Class aeClass = Class.forName("com.apple.MacOS.ae");
- aeDescClass = Class.forName("com.apple.MacOS.AEDesc");
-
- aeTargetConstructor = aeTargetClass.getDeclaredConstructor
- (new Class [] { int.class });
- appleEventConstructor = appleEventClass.getDeclaredConstructor
- (new Class[] { int.class, int.class, aeTargetClass,
- int.class, int.class });
- aeDescConstructor = aeDescClass.getDeclaredConstructor
- (new Class[] { String.class });
-
- makeOSType = osUtilsClass.getDeclaredMethod
- ("makeOSType", new Class [] { String.class });
- putParameter = appleEventClass.getDeclaredMethod
- ("putParameter", new Class[] { int.class, aeDescClass });
- sendNoReply = appleEventClass.getDeclaredMethod
- ("sendNoReply", new Class[] { });
-
- Field keyDirectObjectField = aeClass.getDeclaredField
- ("keyDirectObject");
- keyDirectObject = (Integer) keyDirectObjectField.get(null);
- Field autoGenerateReturnIDField = appleEventClass
- .getDeclaredField("kAutoGenerateReturnID");
- kAutoGenerateReturnID = (Integer) autoGenerateReturnIDField
- .get(null);
- Field anyTransactionIDField = appleEventClass.getDeclaredField
- ("kAnyTransactionID");
- kAnyTransactionID = (Integer) anyTransactionIDField.get(null);
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- } catch (NoSuchFieldException nsfe) {
- errorMessage = nsfe.getMessage();
- return false;
- } catch (IllegalAccessException iae) {
- errorMessage = iae.getMessage();
- return false;
- }
- break;
- case MRJ_2_1:
- try {
- mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
- mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType");
- Field systemFolderField = mrjFileUtilsClass.getDeclaredField
- ("kSystemFolderType");
- kSystemFolderType = systemFolderField.get(null);
- findFolder = mrjFileUtilsClass.getDeclaredMethod
- ("findFolder", new Class[] { mrjOSTypeClass });
- getFileCreator = mrjFileUtilsClass.getDeclaredMethod
- ("getFileCreator", new Class[] { File.class });
- getFileType = mrjFileUtilsClass.getDeclaredMethod
- ("getFileType", new Class[] { File.class });
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchFieldException nsfe) {
- errorMessage = nsfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- } catch (SecurityException se) {
- errorMessage = se.getMessage();
- return false;
- } catch (IllegalAccessException iae) {
- errorMessage = iae.getMessage();
- return false;
- }
- break;
- case MRJ_3_0:
- try {
- Class linker = Class.forName("com.apple.mrj.jdirect.Linker");
- Constructor constructor = linker.getConstructor
- (new Class[]{ Class.class });
- linkage = constructor.newInstance(new Object[]
- { BrowserLauncher.class });
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- } catch (InvocationTargetException ite) {
- errorMessage = ite.getMessage();
- return false;
- } catch (InstantiationException ie) {
- errorMessage = ie.getMessage();
- return false;
- } catch (IllegalAccessException iae) {
- errorMessage = iae.getMessage();
- return false;
- }
- break;
- case MRJ_3_1:
- try {
- mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
- openURL = mrjFileUtilsClass.getDeclaredMethod
- ("openURL", new Class[] { String.class });
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- }
- break;
- default:
- break;
- }
- return true;
- }
-
- /** Attempts to locate the default web browser on the local
- * system. Caches results so it only locates the browser once *
- * for each use of this class per JVM instance.
- * @return The browser for the system. Note that this may not be
- * what you would consider to be a standard web browser; instead,
- * it's the application that gets called to open the default web
- * browser. In some cases, this will be a non-String object that
- * provides the means of calling the default browser. */
- private static Object locateBrowser() {
- if (browser != null) {
- return browser;
- }
- switch (jvm) {
- case MRJ_2_0:
- try {
- Integer finderCreatorCode = (Integer) makeOSType.invoke
- (null, new Object[] { FINDER_CREATOR });
- Object aeTarget = aeTargetConstructor.newInstance
- (new Object[] { finderCreatorCode });
- Integer gurlType = (Integer) makeOSType.invoke
- (null, new Object[] { GURL_EVENT });
- Object appleEvent = appleEventConstructor.newInstance
- (new Object[] { gurlType, gurlType, aeTarget,
- kAutoGenerateReturnID, kAnyTransactionID });
- // Don't set browser = appleEvent because then the
- // next time we call locateBrowser(), we'll get the
- // same AppleEvent, to which we'll already have added
- // the relevant parameter. Instead, regenerate the
- // AppleEvent every time. There's probably a way to
- // do this better; if any has any ideas, please let me
- // know.
- return appleEvent;
- } catch (IllegalAccessException iae) {
- browser = null;
- errorMessage = iae.getMessage();
- return browser;
- } catch (InstantiationException ie) {
- browser = null;
- errorMessage = ie.getMessage();
- return browser;
- } catch (InvocationTargetException ite) {
- browser = null;
- errorMessage = ite.getMessage();
- return browser;
- }
- case MRJ_2_1:
- File systemFolder;
- try {
- systemFolder = (File) findFolder.invoke(null, new Object[]
- { kSystemFolderType });
- } catch (IllegalArgumentException iare) {
- browser = null;
- errorMessage = iare.getMessage();
- return browser;
- } catch (IllegalAccessException iae) {
- browser = null;
- errorMessage = iae.getMessage();
- return browser;
- } catch (InvocationTargetException ite) {
- browser = null;
- errorMessage = ite.getTargetException().getClass() + ": " +
- ite.getTargetException().getMessage();
- return browser;
- }
- String[] systemFolderFiles = systemFolder.list();
- // Avoid a FilenameFilter because that can't be stopped mid-list
- for(int i = 0; i < systemFolderFiles.length; i++) {
- try {
- File file = new File(systemFolder, systemFolderFiles[i]);
- if (!file.isFile()) {
- continue;
- }
- // We're looking for a file with a creator code of
- // 'MACS' and a type of 'FNDR'. Only requiring
- // the type results in non-Finder applications
- // being picked up on certain Mac OS 9 systems,
- // especially German ones, and sending a GURL
- // event to those applications results in a logout
- // under Multiple Users.
- Object fileType = getFileType.invoke
- (null, new Object[] { file });
- if (FINDER_TYPE.equals(fileType.toString())) {
- Object fileCreator = getFileCreator.invoke
- (null, new Object[] { file });
- if (FINDER_CREATOR.equals(fileCreator.toString())) {
- browser = file.toString(); // Actually the
- // Finder, but that's OK
- return browser;
- }
- }
- } catch (IllegalArgumentException iare) {
- //WTF? browser = browser;
- errorMessage = iare.getMessage();
- return null;
- } catch (IllegalAccessException iae) {
- browser = null;
- errorMessage = iae.getMessage();
- return browser;
- } catch (InvocationTargetException ite) {
- browser = null;
- errorMessage = ite.getTargetException().getClass() + ": "
- + ite.getTargetException().getMessage();
- return browser;
- }
- }
- browser = null;
- break;
- case MRJ_3_0:
- case MRJ_3_1:
- browser = ""; // Return something non-null
- break;
- case WINDOWS_NT:
- browser = "cmd.exe";
- break;
- case WINDOWS_9x:
- browser = "command.com";
- break;
- case OTHER:
- default:
- browser = "netscape";
- break;
- }
- return browser;
- }
-
- /** Attempts to open the default web browser to the given URL.
- * @param url The URL to open
- * @throws IOException If the web browser could not be located or
- * does not run */
- public static void openURL(String url) throws IOException {
- if (!loadedWithoutErrors) {
- throw new IOException("Exception in finding browser: "
- + errorMessage);
- }
- Object browser = locateBrowser();
- if (browser == null) {
- throw new IOException("Unable to locate browser: " + errorMessage);
- }
-
- switch (jvm) {
- case MRJ_2_0:
- Object aeDesc = null;
- try {
- aeDesc = aeDescConstructor.newInstance(new Object[] { url });
- putParameter.invoke(browser, new Object[]
- { keyDirectObject, aeDesc });
- sendNoReply.invoke(browser, new Object[] { });
- } catch (InvocationTargetException ite) {
- throw new IOException("InvocationTargetException while creating"
- +" AEDesc: " + ite.getMessage());
- } catch (IllegalAccessException iae) {
- throw new IOException("IllegalAccessException while building "
- + "AppleEvent: " + iae.getMessage());
- } catch (InstantiationException ie) {
- throw new IOException("InstantiationException while creating "
- + "AEDesc: " + ie.getMessage());
- } finally {
- aeDesc = null; // Encourage it to get disposed if it
- // was created
- browser = null; // Ditto
- }
- break;
- case MRJ_2_1:
- Runtime.getRuntime().exec(new String[] { (String) browser, url } );
- break;
- case MRJ_3_0:
- int[] instance = new int[1];
- int result = ICStart(instance, 0);
- if (result == 0) {
- int[] selectionStart = new int[] { 0 };
- byte[] urlBytes = url.getBytes();
- int[] selectionEnd = new int[] { urlBytes.length };
- result = ICLaunchURL(instance[0], new byte[] { 0 }, urlBytes,
- urlBytes.length, selectionStart,
- selectionEnd);
- if (result == 0) {
- // Ignore the return value; the URL was launched
- // successfully regardless of what happens here.
- ICStop(instance);
- } else {
- throw new IOException("Unable to launch URL: " + result);
- }
- } else {
- throw new IOException("Unable to create an Internet Config "
- + "instance: " + result);
- }
- break;
- case MRJ_3_1:
- try {
- openURL.invoke(null, new Object[] { url });
- } catch (InvocationTargetException ite) {
- throw new IOException("InvocationTargetException while calling "
- + "openURL: " + ite.getMessage());
- } catch (IllegalAccessException iae) {
- throw new IOException("IllegalAccessException while calling "
- + "openURL: " + iae.getMessage());
- }
- break;
- case WINDOWS_NT:
- // Add quotes around the URL to allow ampersands and other special
- // characters to work.
- Process process = Runtime.getRuntime().exec(new String[]
- { (String) browser, FIRST_WINDOWS_PARAMETER,
- SECOND_WINDOWS_PARAMETER, THIRD_WINDOWS_PARAMETER,
- '"' + url + '"' });
- // This avoids a memory leak on some versions of Java on
- // Windows. That's hinted at in
- // <http://developer.java.sun.com/developer/qow/archive/68/>.
- try {
- process.waitFor();
- process.exitValue();
- } catch (InterruptedException ie) {
- throw new IOException("InterruptedException while launching "
- + "browser: " + ie.getMessage());
- }
- break;
- case WINDOWS_9x:
- // Add quotes around the URL to allow ampersands and other special
- // characters to work.
- // Note: windows 98 doesn't expect the THIRD_WINDOWS_PARAMETER for
- // its title.
- process = Runtime.getRuntime().exec(new String[]
- { (String) browser, FIRST_WINDOWS_PARAMETER,
- SECOND_WINDOWS_PARAMETER, '"' + url + '"' });
- // This avoids a memory leak on some versions of Java on
- // Windows. That's hinted at in
- // <http://developer.java.sun.com/developer/qow/archive/68/>.
- try {
- process.waitFor();
- process.exitValue();
- } catch (InterruptedException ie) {
- throw new IOException("InterruptedException while launching "
- + "browser: " + ie.getMessage());
- }
- break;
- case OTHER:
- // Assume that we're on Unix and that Netscape is installed
-
- // First, attempt to open the URL in a currently running
- // session of Netscape
- process = Runtime.getRuntime().exec(new String[]
- {(String)browser, NETSCAPE_REMOTE_PARAMETER,
- NETSCAPE_OPEN_PARAMETER_START + url +
- NETSCAPE_OPEN_PARAMETER_END });
- try {
- int exitCode = process.waitFor();
- if (exitCode != 0) { // if the command had an error
- Runtime.getRuntime().exec(new String[]
- { (String) browser, url } );
- } else if(process.getErrorStream() != null) {
- // Netscape may not be open, so the command may not have an
- // error, it just wouldn't have a process to attach to...
- BufferedReader reader = new BufferedReader
- (new InputStreamReader(process.getErrorStream()));
- String errorStr = reader.readLine();
-
- if ( errorStr != null ) {
- // Command failed, start up the browser
- process = Runtime.getRuntime().exec(new String[] {
- (String) browser, url });
- }
- }
- } catch (InterruptedException ie) {
- throw new IOException("InterruptedException while launching "
- + "browser: " + ie.getMessage());
- }
- break;
- default:
- // This should never occur, but if it does, we'll try the
- // simplest thing possible
- Runtime.getRuntime().exec(new String[] { (String) browser, url });
- break;
- }
- }
-
- /** Methods required for Mac OS X. The presence of native methods
- * does not cause any problems on other platforms. */
- private native static int ICStart(int[] instance, int signature);
- private native static int ICStop(int[] instance);
- private native static int ICLaunchURL
- (int instance, byte[] hint, byte[] data, int len, int[] selectionStart,
- int[] selectionEnd);
+ /** The makeOSType method of com.apple.MacOS.OSUtils */
+ private static Method makeOSType;
+
+ /** The putParameter method of com.apple.MacOS.AppleEvent */
+ private static Method putParameter;
+
+ /** The sendNoReply method of com.apple.MacOS.AppleEvent */
+ private static Method sendNoReply;
+
+ /** Actually an MRJOSType pointing to the System Folder on a Macintosh */
+ private static Object kSystemFolderType;
+
+ /** The keyDirectObject AppleEvent parameter type */
+ private static Integer keyDirectObject;
+
+ /** The kAutoGenerateReturnID AppleEvent code */
+ private static Integer kAutoGenerateReturnID;
+
+ /** The kAnyTransactionID AppleEvent code */
+ private static Integer kAnyTransactionID;
+
+ /** The linkage object required for JDirect 3 on Mac OS X. */
+ private static Object linkage;
+
+ /** The framework to reference on Mac OS X */
+ private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
+
+ /** JVM constant for MRJ 2.0 */
+ private static final int MRJ_2_0 = 0;
+
+ /** JVM constant for MRJ 2.1 or later */
+ private static final int MRJ_2_1 = 1;
+
+ /** JVM constant for Java on Mac OS X 10.0 (MRJ 3.0) */
+ private static final int MRJ_3_0 = 3;
+
+ /** JVM constant for MRJ 3.1 */
+ private static final int MRJ_3_1 = 4;
+
+ /** JVM constant for any Windows NT JVM */
+ private static final int WINDOWS_NT = 5;
+
+ /** JVM constant for any Windows 9x JVM */
+ private static final int WINDOWS_9x = 6;
+
+ /** JVM constant for any other platform */
+ private static final int OTHER = -1;
+
+ /**
+ * The file type of the Finder on a Macintosh. Hardcoding "Finder" would keep
+ * non-U.S. English systems from working properly.
+ */
+ private static final String FINDER_TYPE = "FNDR";
+
+ /**
+ * The creator code of the Finder on a Macintosh, which is needed to send
+ * AppleEvents to the application.
+ */
+ private static final String FINDER_CREATOR = "MACS";
+
+ /** The name for the AppleEvent type corresponding to a GetURL event. */
+ private static final String GURL_EVENT = "GURL";
+
+ /**
+ * The first parameter that needs to be passed into Runtime.exec() to open the
+ * default web browser on Windows.
+ */
+ private static final String FIRST_WINDOWS_PARAMETER = "/c";
+
+ /** The second parameter for Runtime.exec() on Windows. */
+ private static final String SECOND_WINDOWS_PARAMETER = "start";
+
+ /**
+ * The third parameter for Runtime.exec() on Windows. This is a "title"
+ * parameter that the command line expects. Setting this parameter allows URLs
+ * containing spaces to work.
+ */
+ private static final String THIRD_WINDOWS_PARAMETER = "\"\"";
+
+ /**
+ * The shell parameters for Netscape that opens a given URL in an already-open
+ * copy of Netscape on many command-line systems.
+ */
+ private static final String NETSCAPE_REMOTE_PARAMETER = "-remote";
+ // private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
+ // private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
+ private static final String NETSCAPE_OPEN_PARAMETER_START = "openURL(";
+ private static final String NETSCAPE_OPEN_PARAMETER_END = ")";
+
+ /**
+ * The message from any exception thrown throughout the initialization process.
+ */
+ private static String errorMessage;
+
+ /**
+ * An initialization block that determines the operating system and loads the
+ * necessary runtime data.
+ */
+ static {
+ loadedWithoutErrors = true;
+ String osName = System.getProperty("os.name");
+ if (osName.startsWith("Mac OS")) {
+ String mrjVersion = System.getProperty("mrj.version");
+ String majorMRJVersion = mrjVersion.substring(0, 3);
+ try {
+ double version = Double.valueOf(majorMRJVersion).doubleValue();
+ if (version == 2) {
+ jvm = MRJ_2_0;
+ } else if (version >= 2.1 && version < 3) {
+ // Assume that all 2.x versions of MRJ work the
+ // same. MRJ 2.1 actually works via
+ // Runtime.exec() and 2.2 supports that but has an
+ // openURL() method as well that we currently
+ // ignore.
+ jvm = MRJ_2_1;
+ } else if (version == 3.0) {
+ jvm = MRJ_3_0;
+ } else if (version >= 3.1) {
+ // Assume that all 3.1 and later versions of MRJ
+ // work the same.
+ jvm = MRJ_3_1;
+ } else {
+ loadedWithoutErrors = false;
+ errorMessage = "Unsupported MRJ version: " + version;
+ }
+ } catch (NumberFormatException nfe) {
+ loadedWithoutErrors = false;
+ errorMessage = "Invalid MRJ version: " + mrjVersion;
+ }
+ } else if (osName.startsWith("Windows")) {
+ if (osName.indexOf("9") != -1) {
+ jvm = WINDOWS_9x;
+ } else {
+ jvm = WINDOWS_NT;
+ }
+ } else {
+ jvm = OTHER;
+ }
+
+ if (loadedWithoutErrors) { // if we haven't hit any errors yet
+ loadedWithoutErrors = loadClasses();
+ }
+ }
+
+ /** This class should be never be instantiated; this just ensures so. */
+ private BrowserLauncher() {
+ }
+
+ /**
+ * Called by a static initializer to load any classes, fields, and methods
+ * required at runtime to locate the user's web browser.
+ *
+ * @return <code>true</code> if all intialization succeeded <code>false</code>
+ * if any portion of the initialization failed
+ */
+ private static boolean loadClasses() {
+ switch (jvm) {
+ case MRJ_2_0:
+ try {
+ Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
+ Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
+ Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent");
+ Class aeClass = Class.forName("com.apple.MacOS.ae");
+ aeDescClass = Class.forName("com.apple.MacOS.AEDesc");
+
+ aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class[] { int.class });
+ appleEventConstructor = appleEventClass.getDeclaredConstructor(
+ new Class[] { int.class, int.class, aeTargetClass, int.class, int.class });
+ aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class[] { String.class });
+
+ makeOSType = osUtilsClass.getDeclaredMethod("makeOSType", new Class[] { String.class });
+ putParameter = appleEventClass.getDeclaredMethod("putParameter",
+ new Class[] { int.class, aeDescClass });
+ sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply", new Class[] {});
+
+ Field keyDirectObjectField = aeClass.getDeclaredField("keyDirectObject");
+ keyDirectObject = (Integer) keyDirectObjectField.get(null);
+ Field autoGenerateReturnIDField = appleEventClass.getDeclaredField("kAutoGenerateReturnID");
+ kAutoGenerateReturnID = (Integer) autoGenerateReturnIDField.get(null);
+ Field anyTransactionIDField = appleEventClass.getDeclaredField("kAnyTransactionID");
+ kAnyTransactionID = (Integer) anyTransactionIDField.get(null);
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ } catch (NoSuchFieldException nsfe) {
+ errorMessage = nsfe.getMessage();
+ return false;
+ } catch (IllegalAccessException iae) {
+ errorMessage = iae.getMessage();
+ return false;
+ }
+ break;
+ case MRJ_2_1:
+ try {
+ mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
+ mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType");
+ Field systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType");
+ kSystemFolderType = systemFolderField.get(null);
+ findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class[] { mrjOSTypeClass });
+ getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class[] { File.class });
+ getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class[] { File.class });
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchFieldException nsfe) {
+ errorMessage = nsfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ } catch (SecurityException se) {
+ errorMessage = se.getMessage();
+ return false;
+ } catch (IllegalAccessException iae) {
+ errorMessage = iae.getMessage();
+ return false;
+ }
+ break;
+ case MRJ_3_0:
+ try {
+ Class linker = Class.forName("com.apple.mrj.jdirect.Linker");
+ Constructor constructor = linker.getConstructor(new Class[] { Class.class });
+ linkage = constructor.newInstance(new Object[] { BrowserLauncher.class });
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ } catch (InvocationTargetException ite) {
+ errorMessage = ite.getMessage();
+ return false;
+ } catch (InstantiationException ie) {
+ errorMessage = ie.getMessage();
+ return false;
+ } catch (IllegalAccessException iae) {
+ errorMessage = iae.getMessage();
+ return false;
+ }
+ break;
+ case MRJ_3_1:
+ try {
+ mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
+ openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class[] { String.class });
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Attempts to locate the default web browser on the local system. Caches
+ * results so it only locates the browser once * for each use of this class per
+ * JVM instance.
+ *
+ * @return The browser for the system. Note that this may not be what you would
+ * consider to be a standard web browser; instead, it's the application
+ * that gets called to open the default web browser. In some cases, this
+ * will be a non-String object that provides the means of calling the
+ * default browser.
+ */
+ private static Object locateBrowser() {
+ if (browser != null) {
+ return browser;
+ }
+ switch (jvm) {
+ case MRJ_2_0:
+ try {
+ Integer finderCreatorCode = (Integer) makeOSType.invoke(null, new Object[] { FINDER_CREATOR });
+ Object aeTarget = aeTargetConstructor.newInstance(new Object[] { finderCreatorCode });
+ Integer gurlType = (Integer) makeOSType.invoke(null, new Object[] { GURL_EVENT });
+ Object appleEvent = appleEventConstructor.newInstance(
+ new Object[] { gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID });
+ // Don't set browser = appleEvent because then the
+ // next time we call locateBrowser(), we'll get the
+ // same AppleEvent, to which we'll already have added
+ // the relevant parameter. Instead, regenerate the
+ // AppleEvent every time. There's probably a way to
+ // do this better; if any has any ideas, please let me
+ // know.
+ return appleEvent;
+ } catch (IllegalAccessException iae) {
+ browser = null;
+ errorMessage = iae.getMessage();
+ return browser;
+ } catch (InstantiationException ie) {
+ browser = null;
+ errorMessage = ie.getMessage();
+ return browser;
+ } catch (InvocationTargetException ite) {
+ browser = null;
+ errorMessage = ite.getMessage();
+ return browser;
+ }
+ case MRJ_2_1:
+ File systemFolder;
+ try {
+ systemFolder = (File) findFolder.invoke(null, new Object[] { kSystemFolderType });
+ } catch (IllegalArgumentException iare) {
+ browser = null;
+ errorMessage = iare.getMessage();
+ return browser;
+ } catch (IllegalAccessException iae) {
+ browser = null;
+ errorMessage = iae.getMessage();
+ return browser;
+ } catch (InvocationTargetException ite) {
+ browser = null;
+ errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
+ return browser;
+ }
+ String[] systemFolderFiles = systemFolder.list();
+ // Avoid a FilenameFilter because that can't be stopped mid-list
+ for (int i = 0; i < systemFolderFiles.length; i++) {
+ try {
+ File file = new File(systemFolder, systemFolderFiles[i]);
+ if (!file.isFile()) {
+ continue;
+ }
+ // We're looking for a file with a creator code of
+ // 'MACS' and a type of 'FNDR'. Only requiring
+ // the type results in non-Finder applications
+ // being picked up on certain Mac OS 9 systems,
+ // especially German ones, and sending a GURL
+ // event to those applications results in a logout
+ // under Multiple Users.
+ Object fileType = getFileType.invoke(null, new Object[] { file });
+ if (FINDER_TYPE.equals(fileType.toString())) {
+ Object fileCreator = getFileCreator.invoke(null, new Object[] { file });
+ if (FINDER_CREATOR.equals(fileCreator.toString())) {
+ browser = file.toString(); // Actually the
+ // Finder, but that's OK
+ return browser;
+ }
+ }
+ } catch (IllegalArgumentException iare) {
+ // WTF? browser = browser;
+ errorMessage = iare.getMessage();
+ return null;
+ } catch (IllegalAccessException iae) {
+ browser = null;
+ errorMessage = iae.getMessage();
+ return browser;
+ } catch (InvocationTargetException ite) {
+ browser = null;
+ errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
+ return browser;
+ }
+ }
+ browser = null;
+ break;
+ case MRJ_3_0:
+ case MRJ_3_1:
+ browser = ""; // Return something non-null
+ break;
+ case WINDOWS_NT:
+ browser = "cmd.exe";
+ break;
+ case WINDOWS_9x:
+ browser = "command.com";
+ break;
+ case OTHER:
+ default:
+ browser = "netscape";
+ break;
+ }
+ return browser;
+ }
+
+ /**
+ * Attempts to open the default web browser to the given URL.
+ *
+ * @param url The URL to open
+ * @throws IOException If the web browser could not be located or does not run
+ */
+ public static void openURL(String url) throws IOException {
+ if (!loadedWithoutErrors) {
+ throw new IOException("Exception in finding browser: " + errorMessage);
+ }
+ Object browser = locateBrowser();
+ if (browser == null) {
+ throw new IOException("Unable to locate browser: " + errorMessage);
+ }
+
+ switch (jvm) {
+ case MRJ_2_0:
+ Object aeDesc = null;
+ try {
+ aeDesc = aeDescConstructor.newInstance(new Object[] { url });
+ putParameter.invoke(browser, new Object[] { keyDirectObject, aeDesc });
+ sendNoReply.invoke(browser, new Object[] {});
+ } catch (InvocationTargetException ite) {
+ throw new IOException("InvocationTargetException while creating" + " AEDesc: " + ite.getMessage());
+ } catch (IllegalAccessException iae) {
+ throw new IOException("IllegalAccessException while building " + "AppleEvent: " + iae.getMessage());
+ } catch (InstantiationException ie) {
+ throw new IOException("InstantiationException while creating " + "AEDesc: " + ie.getMessage());
+ } finally {
+ aeDesc = null; // Encourage it to get disposed if it
+ // was created
+ browser = null; // Ditto
+ }
+ break;
+ case MRJ_2_1:
+ Runtime.getRuntime().exec(new String[] { (String) browser, url });
+ break;
+ case MRJ_3_0:
+ int[] instance = new int[1];
+ int result = ICStart(instance, 0);
+ if (result == 0) {
+ int[] selectionStart = new int[] { 0 };
+ byte[] urlBytes = url.getBytes();
+ int[] selectionEnd = new int[] { urlBytes.length };
+ result = ICLaunchURL(instance[0], new byte[] { 0 }, urlBytes, urlBytes.length, selectionStart,
+ selectionEnd);
+ if (result == 0) {
+ // Ignore the return value; the URL was launched
+ // successfully regardless of what happens here.
+ ICStop(instance);
+ } else {
+ throw new IOException("Unable to launch URL: " + result);
+ }
+ } else {
+ throw new IOException("Unable to create an Internet Config " + "instance: " + result);
+ }
+ break;
+ case MRJ_3_1:
+ try {
+ openURL.invoke(null, new Object[] { url });
+ } catch (InvocationTargetException ite) {
+ throw new IOException("InvocationTargetException while calling " + "openURL: " + ite.getMessage());
+ } catch (IllegalAccessException iae) {
+ throw new IOException("IllegalAccessException while calling " + "openURL: " + iae.getMessage());
+ }
+ break;
+ case WINDOWS_NT:
+ // Add quotes around the URL to allow ampersands and other special
+ // characters to work.
+ Process process = Runtime.getRuntime().exec(new String[] { (String) browser, FIRST_WINDOWS_PARAMETER,
+ SECOND_WINDOWS_PARAMETER, THIRD_WINDOWS_PARAMETER, '"' + url + '"' });
+ // This avoids a memory leak on some versions of Java on
+ // Windows. That's hinted at in
+ // <http://developer.java.sun.com/developer/qow/archive/68/>.
+ try {
+ process.waitFor();
+ process.exitValue();
+ } catch (InterruptedException ie) {
+ throw new IOException("InterruptedException while launching " + "browser: " + ie.getMessage());
+ }
+ break;
+ case WINDOWS_9x:
+ // Add quotes around the URL to allow ampersands and other special
+ // characters to work.
+ // Note: windows 98 doesn't expect the THIRD_WINDOWS_PARAMETER for
+ // its title.
+ process = Runtime.getRuntime().exec(new String[] { (String) browser, FIRST_WINDOWS_PARAMETER,
+ SECOND_WINDOWS_PARAMETER, '"' + url + '"' });
+ // This avoids a memory leak on some versions of Java on
+ // Windows. That's hinted at in
+ // <http://developer.java.sun.com/developer/qow/archive/68/>.
+ try {
+ process.waitFor();
+ process.exitValue();
+ } catch (InterruptedException ie) {
+ throw new IOException("InterruptedException while launching " + "browser: " + ie.getMessage());
+ }
+ break;
+ case OTHER:
+ // Assume that we're on Unix and that Netscape is installed
+
+ // First, attempt to open the URL in a currently running
+ // session of Netscape
+ process = Runtime.getRuntime().exec(new String[] { (String) browser, NETSCAPE_REMOTE_PARAMETER,
+ NETSCAPE_OPEN_PARAMETER_START + url + NETSCAPE_OPEN_PARAMETER_END });
+ try {
+ int exitCode = process.waitFor();
+ if (exitCode != 0) { // if the command had an error
+ Runtime.getRuntime().exec(new String[] { (String) browser, url });
+ } else if (process.getErrorStream() != null) {
+ // Netscape may not be open, so the command may not have an
+ // error, it just wouldn't have a process to attach to...
+ BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+ String errorStr = reader.readLine();
+
+ if (errorStr != null) {
+ // Command failed, start up the browser
+ process = Runtime.getRuntime().exec(new String[] { (String) browser, url });
+ }
+ }
+ } catch (InterruptedException ie) {
+ throw new IOException("InterruptedException while launching " + "browser: " + ie.getMessage());
+ }
+ break;
+ default:
+ // This should never occur, but if it does, we'll try the
+ // simplest thing possible
+ Runtime.getRuntime().exec(new String[] { (String) browser, url });
+ break;
+ }
+ }
+
+ /**
+ * Methods required for Mac OS X. The presence of native methods does not cause
+ * any problems on other platforms.
+ */
+ private native static int ICStart(int[] instance, int signature);
+
+ private native static int ICStop(int[] instance);
+
+ private native static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len, int[] selectionStart,
+ int[] selectionEnd);
}
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoder.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoder.java
index 8da71fe..54658c0 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoder.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoder.java
@@ -32,83 +32,73 @@ import net.wotonomy.foundation.xml.XMLDecoder;
import org.xml.sax.SAXException;
/**
-* An implementation of XMLDecoder that reads objects from
-* XMLRPC format.
-* This implementation is not thread-safe, so a new instances
-* should be created to accomodate multiple threads.
-*/
-public class XMLRPCDecoder implements XMLDecoder
-{
- XMLRPCDecoderHelper helper = new XMLRPCDecoderHelper();
-
- /**
- * Decodes an object in XML-RPC format from the specified input stream.
- * @param anInputStream The input stream from which to read.
- * The stream will be read fully.
- * @param aDescription A description to accompany error messages
- * for the stream, typically a file name.
- * @param aURL A URL against which relative references within the
- * XML will be resolved.
- * @return The object that was constructed from the XML content,
- * or null if no object could be constructed.
- */
- public Object decode(
- InputStream anInputStream, String aDescription, URL aURL )
- {
- Object result = null;
-
- try {
- SAXParser sparser = SAXParserFactory.newInstance().newSAXParser();
- sparser.parse(anInputStream,helper,aURL.toExternalForm());
- result = helper.getResult();
- } catch (ParserConfigurationException e) {
- throw new WotonomyException("Problem in parser configuration", e );
- } catch (IOException e) {
- throw new WotonomyException("IOException thrown while parsing", e );
- } catch (SAXException e) {
- throw new WotonomyException("SAXException thrown while parsing", e );
- }
- helper.reset();
- return result;
- }
+ * An implementation of XMLDecoder that reads objects from XMLRPC format. This
+ * implementation is not thread-safe, so a new instances should be created to
+ * accomodate multiple threads.
+ */
+public class XMLRPCDecoder implements XMLDecoder {
+ XMLRPCDecoderHelper helper = new XMLRPCDecoderHelper();
+
+ /**
+ * Decodes an object in XML-RPC format from the specified input stream.
+ *
+ * @param anInputStream The input stream from which to read. The stream will be
+ * read fully.
+ * @param aDescription A description to accompany error messages for the
+ * stream, typically a file name.
+ * @param aURL A URL against which relative references within the XML
+ * will be resolved.
+ * @return The object that was constructed from the XML content, or null if no
+ * object could be constructed.
+ */
+ public Object decode(InputStream anInputStream, String aDescription, URL aURL) {
+ Object result = null;
+
+ try {
+ SAXParser sparser = SAXParserFactory.newInstance().newSAXParser();
+ sparser.parse(anInputStream, helper, aURL.toExternalForm());
+ result = helper.getResult();
+ } catch (ParserConfigurationException e) {
+ throw new WotonomyException("Problem in parser configuration", e);
+ } catch (IOException e) {
+ throw new WotonomyException("IOException thrown while parsing", e);
+ } catch (SAXException e) {
+ throw new WotonomyException("SAXException thrown while parsing", e);
+ }
+ helper.reset();
+ return result;
+ }
+
+ /**
+ * Decodes an XML-RPC message from the specified input stream. Stand-alone
+ * values not wrapped in "methodCall" or "param" tags will be treated as a
+ * response.
+ *
+ * @param anInputStream The input stream from which to read. The stream will be
+ * read fully.
+ * @param aReceiver an XMLRPCReceiver that will be invoked with the
+ * appropriate method: request, response, or fault.
+ */
+ public void decode(InputStream anInputStream, XMLRPCReceiver aReceiver) {
+ try {
+ SAXParser sparser = SAXParserFactory.newInstance().newSAXParser();
+ sparser.parse(anInputStream, helper);
- /**
- * Decodes an XML-RPC message from the specified input stream.
- * Stand-alone values not wrapped in "methodCall" or "param"
- * tags will be treated as a response.
- * @param anInputStream The input stream from which to read.
- * The stream will be read fully.
- * @param aReceiver an XMLRPCReceiver that will be invoked with
- * the appropriate method: request, response, or fault.
- */
- public void decode(
- InputStream anInputStream, XMLRPCReceiver aReceiver )
- {
- try
- {
- SAXParser sparser = SAXParserFactory.newInstance().newSAXParser();
- sparser.parse(anInputStream,helper);
-
- if ( helper.isRequest() )
- {
- aReceiver.request( helper.getMethodName(), helper.getParameters() );
- }
- else
- if ( helper.isFault() )
- {
- aReceiver.fault( helper.getFaultCode(), helper.getFaultString() );
- }
- else // all else is considered a response
- {
- aReceiver.response( helper.getResult() );
- }
- } catch (ParserConfigurationException e) {
- throw new WotonomyException("Problem in parser configuration", e );
- } catch (IOException e) {
- throw new WotonomyException("IOException thrown while parsing", e );
- } catch (SAXException e) {
- throw new WotonomyException("SAXException thrown while parsing", e );
- }
- helper.reset();
- }
+ if (helper.isRequest()) {
+ aReceiver.request(helper.getMethodName(), helper.getParameters());
+ } else if (helper.isFault()) {
+ aReceiver.fault(helper.getFaultCode(), helper.getFaultString());
+ } else // all else is considered a response
+ {
+ aReceiver.response(helper.getResult());
+ }
+ } catch (ParserConfigurationException e) {
+ throw new WotonomyException("Problem in parser configuration", e);
+ } catch (IOException e) {
+ throw new WotonomyException("IOException thrown while parsing", e);
+ } catch (SAXException e) {
+ throw new WotonomyException("SAXException thrown while parsing", e);
+ }
+ helper.reset();
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java
index 2368672..0806d88 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java
@@ -38,77 +38,64 @@ import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
/**
-* Used by XMLDecoder to implement the necessary interfaces
-* required by the jclark xp parser.
-* This class is not thread safe.
-*/
-class XMLRPCDecoderHelper extends DefaultHandler
-{
- protected final Object nilMarker = new Object();
- protected Stack valueStack;
- protected String methodName;
- protected int faultCode;
- protected String faultString;
- protected List parameters;
- protected StringBuffer cdataBuffer;
-
-
-
- public XMLRPCDecoderHelper()
- {
- valueStack = new Stack();
- parameters = new LinkedList();
- cdataBuffer = new StringBuffer();
- reset();
- }
-
- public void reset()
- {
- valueStack.clear();
- parameters.clear();
- cdataBuffer.setLength( 0 );
- methodName = null;
- faultCode = 0;
- faultString = null;
- }
-
- public boolean isRequest()
- {
- return ( methodName != null );
- }
-
- public boolean isResponse()
- {
- return ( methodName == null );
- }
-
- public boolean isFault()
- {
- // faults are responses
- return ( isResponse() ) && ( faultString != null );
- }
-
- public int getFaultCode()
- {
- return faultCode;
- }
-
- public String getFaultString()
- {
- return faultString;
- }
-
- public String getMethodName()
- {
- return methodName;
- }
-
- public Object[] getParameters()
- {
- return parameters.toArray();
- }
-
- public void endDocument() throws SAXException {
+ * Used by XMLDecoder to implement the necessary interfaces required by the
+ * jclark xp parser. This class is not thread safe.
+ */
+class XMLRPCDecoderHelper extends DefaultHandler {
+ protected final Object nilMarker = new Object();
+ protected Stack valueStack;
+ protected String methodName;
+ protected int faultCode;
+ protected String faultString;
+ protected List parameters;
+ protected StringBuffer cdataBuffer;
+
+ public XMLRPCDecoderHelper() {
+ valueStack = new Stack();
+ parameters = new LinkedList();
+ cdataBuffer = new StringBuffer();
+ reset();
+ }
+
+ public void reset() {
+ valueStack.clear();
+ parameters.clear();
+ cdataBuffer.setLength(0);
+ methodName = null;
+ faultCode = 0;
+ faultString = null;
+ }
+
+ public boolean isRequest() {
+ return (methodName != null);
+ }
+
+ public boolean isResponse() {
+ return (methodName == null);
+ }
+
+ public boolean isFault() {
+ // faults are responses
+ return (isResponse()) && (faultString != null);
+ }
+
+ public int getFaultCode() {
+ return faultCode;
+ }
+
+ public String getFaultString() {
+ return faultString;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ public Object[] getParameters() {
+ return parameters.toArray();
+ }
+
+ public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
}
@@ -118,47 +105,40 @@ class XMLRPCDecoderHelper extends DefaultHandler
super.startDocument();
reset();
}
-
- public Object getResult()
- {
- if ( valueStack.empty() ) return null;
- Object result = valueStack.peek();
- if ( result == nilMarker ) result = null;
- return result;
- }
-
-
+
+ public Object getResult() {
+ if (valueStack.empty())
+ return null;
+ Object result = valueStack.peek();
+ if (result == nilMarker)
+ result = null;
+ return result;
+ }
+
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
- if ( XMLRPCEncoder.VALUE.equals( localName ) )
- {
- ValueMarker marker = new ValueMarker();
- String classname = attributes.getValue( uri, XMLRPCEncoder.CLASS );
- if ( classname != null )
- {
- try
- {
- Class c = Class.forName( classname );
- if ( c != null )
- {
- marker.setMarkerClass( c );
- }
- }
- catch ( Exception exc )
- {
- System.out.println( "XMLRPCDecoderHelper.startElement: " +
- "Can't find class: " + classname );
- }
- }
- valueStack.push( marker );
- }
+ if (XMLRPCEncoder.VALUE.equals(localName)) {
+ ValueMarker marker = new ValueMarker();
+ String classname = attributes.getValue(uri, XMLRPCEncoder.CLASS);
+ if (classname != null) {
+ try {
+ Class c = Class.forName(classname);
+ if (c != null) {
+ marker.setMarkerClass(c);
+ }
+ } catch (Exception exc) {
+ System.out.println("XMLRPCDecoderHelper.startElement: " + "Can't find class: " + classname);
+ }
+ }
+ valueStack.push(marker);
+ }
}
-
- public void characters(char[] ch, int start, int length) throws SAXException {
+
+ public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
- char[] someChars = new char[((start+length)<=ch.length) ? length : ch.length-start];
- for (int i = 0; i < someChars.length; i++ ) {
- someChars[i] = ch[start+i];
+ char[] someChars = new char[((start + length) <= ch.length) ? length : ch.length - start];
+ for (int i = 0; i < someChars.length; i++) {
+ someChars[i] = ch[start + i];
}
cdataBuffer.append(someChars);
}
@@ -166,231 +146,140 @@ class XMLRPCDecoderHelper extends DefaultHandler
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
- // if any cdata is buffered or if string value
- if ( ( XMLRPCEncoder.STRING.equals( localName ) )
- || ( cdataBuffer.length() > 0 ) )
- {
- // push value on the stack
- valueStack.push( cdataBuffer.toString() );
- cdataBuffer.setLength( 0 );
- }
-
- if ( XMLRPCEncoder.VALUE.equals( localName ) )
- {
- Object value = valueStack.pop();
- try
- {
+ // if any cdata is buffered or if string value
+ if ((XMLRPCEncoder.STRING.equals(localName)) || (cdataBuffer.length() > 0)) {
+ // push value on the stack
+ valueStack.push(cdataBuffer.toString());
+ cdataBuffer.setLength(0);
+ }
+
+ if (XMLRPCEncoder.VALUE.equals(localName)) {
+ Object value = valueStack.pop();
+ try {
// ValueMarker marker = (ValueMarker) valueStack.pop();
- ValueMarker marker = null;
- Object markerValue = valueStack.pop();
- if ( markerValue instanceof ValueMarker )
- {
- marker = (ValueMarker) markerValue;
- }
- else
- {
- throw new WotonomyException( "Expected value marker, found"
- + markerValue.getClass() + " : " + markerValue );
- }
-
+ ValueMarker marker = null;
+ Object markerValue = valueStack.pop();
+ if (markerValue instanceof ValueMarker) {
+ marker = (ValueMarker) markerValue;
+ } else {
+ throw new WotonomyException(
+ "Expected value marker, found" + markerValue.getClass() + " : " + markerValue);
+ }
+
//System.out.println( "getMarkerClass: " + marker.getMarkerClass() + " : " + value );
//System.out.println( valueStack );
- if ( marker.getMarkerClass() != null )
- {
- // apply introspection
- if ( value instanceof Map )
- {
- Map map = (Map)value;
- Map.Entry entry;
- value = marker.getMarkerClass().newInstance();
- Iterator it = map.entrySet().iterator();
- Object entryValue;
- while( it.hasNext() )
- {
- entry = (Map.Entry) it.next();
- entryValue = entry.getValue();
- if ( entryValue == nilMarker ) entryValue = null;
- Introspector.set(
- value, entry.getKey().toString(), entryValue );
- }
- }
- if ( ! ( value.getClass().equals( marker.getMarkerClass() ) ) )
- {
- Object converted =
- ValueConverter.convertObjectToClass(
- value, marker.getMarkerClass() );
- if ( converted != null )
- {
- value = converted;
- }
- }
- }
- }
- catch ( Exception exc )
- {
- // fall back on unconverted value
- }
-
- valueStack.push( value );
+ if (marker.getMarkerClass() != null) {
+ // apply introspection
+ if (value instanceof Map) {
+ Map map = (Map) value;
+ Map.Entry entry;
+ value = marker.getMarkerClass().newInstance();
+ Iterator it = map.entrySet().iterator();
+ Object entryValue;
+ while (it.hasNext()) {
+ entry = (Map.Entry) it.next();
+ entryValue = entry.getValue();
+ if (entryValue == nilMarker)
+ entryValue = null;
+ Introspector.set(value, entry.getKey().toString(), entryValue);
+ }
+ }
+ if (!(value.getClass().equals(marker.getMarkerClass()))) {
+ Object converted = ValueConverter.convertObjectToClass(value, marker.getMarkerClass());
+ if (converted != null) {
+ value = converted;
+ }
+ }
+ }
+ } catch (Exception exc) {
+ // fall back on unconverted value
+ }
+
+ valueStack.push(value);
// System.out.println( "convertedValue: " + value + "("+ value.getClass() +")" );
- }
- else
- if ( XMLRPCEncoder.MEMBER.equals( localName ) ) // Map.Entry
- {
- // leave key and value to be handled by struct
- }
- else
- if ( XMLRPCEncoder.STRUCT.equals( localName ) ) // write Entries to map or object
- {
- // write values to array (reverse the order)
- Object value;
- Map map = new HashMap();
- while ( ( ! valueStack.empty() )
- && ( ! ( valueStack.peek() instanceof ValueMarker ) ) )
- {
- value = valueStack.pop();
- map.put( valueStack.pop(), value );
- }
- // push the list on the stack
- valueStack.push( map );
- }
- else
- if ( XMLRPCEncoder.ARRAY.equals( localName ) )
- {
+ } else if (XMLRPCEncoder.MEMBER.equals(localName)) // Map.Entry
+ {
+ // leave key and value to be handled by struct
+ } else if (XMLRPCEncoder.STRUCT.equals(localName)) // write Entries to map or object
+ {
+ // write values to array (reverse the order)
+ Object value;
+ Map map = new HashMap();
+ while ((!valueStack.empty()) && (!(valueStack.peek() instanceof ValueMarker))) {
+ value = valueStack.pop();
+ map.put(valueStack.pop(), value);
+ }
+ // push the list on the stack
+ valueStack.push(map);
+ } else if (XMLRPCEncoder.ARRAY.equals(localName)) {
//System.out.println( "ended ARRAY: " + valueStack.size() );
- // write values to array (reverse the order)
- Object value;
- LinkedList list = new LinkedList();
- while ( ( ! valueStack.empty() )
- && ( ! ( valueStack.peek() instanceof ValueMarker ) ) )
- {
- value = valueStack.pop();
- if ( value == nilMarker ) value = null;
- list.addFirst( value );
- }
- // push the list on the stack
- valueStack.push( list );
- }
- else
- if ( XMLRPCEncoder.INT.equals( localName ) )
- {
- Object value = valueStack.pop();
- try
- {
- valueStack.push(
- new Integer( value.toString() ) );
- }
- catch ( NumberFormatException exc )
- {
- throw new WotonomyException(
- "Invalid double format: " + value.toString() );
- }
- }
- else
- if ( XMLRPCEncoder.I4.equals( localName ) )
- {
- Object value = valueStack.pop();
- try
- {
- valueStack.push(
- new Integer( value.toString() ) );
- }
- catch ( NumberFormatException exc )
- {
- throw new WotonomyException(
- "Invalid double format: " + value.toString() );
- }
- }
- else
- if ( XMLRPCEncoder.NIL.equals( localName ) )
- {
- valueStack.push( nilMarker );
- }
- else
- if ( XMLRPCEncoder.DOUBLE.equals( localName ) )
- {
- Object value = valueStack.pop();
- try
- {
- valueStack.push(
- new Double( value.toString() ) );
- }
- catch ( NumberFormatException exc )
- {
- throw new WotonomyException(
- "Invalid double format: " + value.toString() );
- }
- }
- else
- if ( XMLRPCEncoder.DATE.equals( localName ) )
- {
- Object value = valueStack.pop();
- try
- {
- valueStack.push(
- XMLRPCEncoder.DATEFORMAT8601.parseObject(
- value.toString() ) );
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Invalid date format: " + value );
- }
- }
- else
- if ( XMLRPCEncoder.BOOLEAN.equals( localName ) )
- {
- Object value = valueStack.pop();
- if ( XMLRPCEncoder.TRUE.equals( value ) )
- {
- valueStack.push( Boolean.TRUE );
- }
- else
- if ( XMLRPCEncoder.FALSE.equals( value ) )
- {
- valueStack.push( Boolean.FALSE );
- }
- else
- {
- throw new WotonomyException(
- "Invalid boolean format: " + value );
- }
- }
- else
- if ( XMLRPCEncoder.BASE64.equals( localName ) )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
- else
- if ( XMLRPCEncoder.FAULT.equals( localName ) )
- {
- Map faultMap = (Map) valueStack.pop();
- try
- {
- faultCode = ((Integer)
- faultMap.get( XMLRPCEncoder.FAULTCODE )).intValue();
- faultString = (String) faultMap.get( XMLRPCEncoder.FAULTSTRING );
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Invalid fault format: " + faultMap );
- }
- }
- else
- if ( XMLRPCEncoder.METHODNAME.equals( localName ) )
- {
- methodName = (String) valueStack.pop();
- }
- else
- if ( XMLRPCEncoder.PARAM.equals( localName ) )
- {
- //NOTE: this leaves the parameter on the stack
- parameters.add( getResult() );
- }
- }
-
-
+ // write values to array (reverse the order)
+ Object value;
+ LinkedList list = new LinkedList();
+ while ((!valueStack.empty()) && (!(valueStack.peek() instanceof ValueMarker))) {
+ value = valueStack.pop();
+ if (value == nilMarker)
+ value = null;
+ list.addFirst(value);
+ }
+ // push the list on the stack
+ valueStack.push(list);
+ } else if (XMLRPCEncoder.INT.equals(localName)) {
+ Object value = valueStack.pop();
+ try {
+ valueStack.push(new Integer(value.toString()));
+ } catch (NumberFormatException exc) {
+ throw new WotonomyException("Invalid double format: " + value.toString());
+ }
+ } else if (XMLRPCEncoder.I4.equals(localName)) {
+ Object value = valueStack.pop();
+ try {
+ valueStack.push(new Integer(value.toString()));
+ } catch (NumberFormatException exc) {
+ throw new WotonomyException("Invalid double format: " + value.toString());
+ }
+ } else if (XMLRPCEncoder.NIL.equals(localName)) {
+ valueStack.push(nilMarker);
+ } else if (XMLRPCEncoder.DOUBLE.equals(localName)) {
+ Object value = valueStack.pop();
+ try {
+ valueStack.push(new Double(value.toString()));
+ } catch (NumberFormatException exc) {
+ throw new WotonomyException("Invalid double format: " + value.toString());
+ }
+ } else if (XMLRPCEncoder.DATE.equals(localName)) {
+ Object value = valueStack.pop();
+ try {
+ valueStack.push(XMLRPCEncoder.DATEFORMAT8601.parseObject(value.toString()));
+ } catch (Exception exc) {
+ throw new WotonomyException("Invalid date format: " + value);
+ }
+ } else if (XMLRPCEncoder.BOOLEAN.equals(localName)) {
+ Object value = valueStack.pop();
+ if (XMLRPCEncoder.TRUE.equals(value)) {
+ valueStack.push(Boolean.TRUE);
+ } else if (XMLRPCEncoder.FALSE.equals(value)) {
+ valueStack.push(Boolean.FALSE);
+ } else {
+ throw new WotonomyException("Invalid boolean format: " + value);
+ }
+ } else if (XMLRPCEncoder.BASE64.equals(localName)) {
+ throw new WotonomyException("Not implemented yet.");
+ } else if (XMLRPCEncoder.FAULT.equals(localName)) {
+ Map faultMap = (Map) valueStack.pop();
+ try {
+ faultCode = ((Integer) faultMap.get(XMLRPCEncoder.FAULTCODE)).intValue();
+ faultString = (String) faultMap.get(XMLRPCEncoder.FAULTSTRING);
+ } catch (Exception exc) {
+ throw new WotonomyException("Invalid fault format: " + faultMap);
+ }
+ } else if (XMLRPCEncoder.METHODNAME.equals(localName)) {
+ methodName = (String) valueStack.pop();
+ } else if (XMLRPCEncoder.PARAM.equals(localName)) {
+ // NOTE: this leaves the parameter on the stack
+ parameters.add(getResult());
+ }
+ }
public void endPrefixMapping(String prefix) throws SAXException {
// TODO Auto-generated method stub
@@ -423,12 +312,14 @@ class XMLRPCDecoderHelper extends DefaultHandler
}
public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
- // NOTE: Sun accepted an incompatible api difference. The (false) should be tossed by hotspot
+ // NOTE: Sun accepted an incompatible api difference. The (false) should be
+ // tossed by hotspot
try {
- if (false) throw new IOException("Fake exception to make it compile in both 1.4 and 1.5");
- return super.resolveEntity(publicId, systemId);
+ if (false)
+ throw new IOException("Fake exception to make it compile in both 1.4 and 1.5");
+ return super.resolveEntity(publicId, systemId);
} catch (IOException e) {
- throw new SAXException(e.getClass().getName() + " thrown while resolving entity.",e);
+ throw new SAXException(e.getClass().getName() + " thrown while resolving entity.", e);
}
}
@@ -442,14 +333,13 @@ class XMLRPCDecoderHelper extends DefaultHandler
super.skippedEntity(name);
}
-
-
public void startPrefixMapping(String prefix, String uri) throws SAXException {
// TODO Auto-generated method stub
super.startPrefixMapping(prefix, uri);
}
- public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException {
+ public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName)
+ throws SAXException {
// TODO Auto-generated method stub
super.unparsedEntityDecl(name, publicId, systemId, notationName);
}
@@ -459,76 +349,65 @@ class XMLRPCDecoderHelper extends DefaultHandler
super.warning(e);
}
-
- // marker class
-
- private class ValueMarker
- {
- private Class theClass;
-
- public ValueMarker()
- {
- theClass = null;
- }
-
- public void setMarkerClass( Class aClass )
- {
- theClass = aClass;
- }
-
- public Class getMarkerClass()
- {
- return theClass;
- }
-
- public String toString()
- {
- return "[ValueMarker: " + theClass + "]";
- }
- }
-
+ // marker class
+
+ private class ValueMarker {
+ private Class theClass;
+
+ public ValueMarker() {
+ theClass = null;
+ }
+
+ public void setMarkerClass(Class aClass) {
+ theClass = aClass;
+ }
+
+ public Class getMarkerClass() {
+ return theClass;
+ }
+
+ public String toString() {
+ return "[ValueMarker: " + theClass + "]";
+ }
+ }
+
}
/*
- * $Log$
- * Revision 1.1 2006/02/19 01:44:03 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.1 2006/02/19 01:44:03 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.7 2003/08/06 23:07:53 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.7 2003/08/06 23:07:53 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.6 2001/03/03 15:16:35 mpowers
- * Fixed bug in decoding empty strings: string handler did nothing and
- * empty cdatas were ignored, so no value was placed on the stack.
+ * Revision 1.6 2001/03/03 15:16:35 mpowers Fixed bug in decoding empty strings:
+ * string handler did nothing and empty cdatas were ignored, so no value was
+ * placed on the stack.
*
- * Revision 1.5 2001/02/17 16:52:06 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.5 2001/02/17 16:52:06 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.4 2001/02/09 15:51:39 mpowers
- * Fixed a pernicious bug: I was using the character event entirely
- * incorrectly, but the problem only exhibited itself with large data
- * and even then only randomly. Now using a string buffer.
+ * Revision 1.4 2001/02/09 15:51:39 mpowers Fixed a pernicious bug: I was using
+ * the character event entirely incorrectly, but the problem only exhibited
+ * itself with large data and even then only randomly. Now using a string
+ * buffer.
*
- * Revision 1.3 2001/02/07 19:24:28 mpowers
- * Moved XML classes to separate package.
+ * Revision 1.3 2001/02/07 19:24:28 mpowers Moved XML classes to separate
+ * package.
*
- * Revision 1.2 2001/02/06 14:34:23 mpowers
- * Forgot to rename the package declarations.
+ * Revision 1.2 2001/02/06 14:34:23 mpowers Forgot to rename the package
+ * declarations.
*
- * Revision 1.1 2001/02/06 14:31:19 mpowers
- * Moving XML utilities from util to xml package.
+ * Revision 1.1 2001/02/06 14:31:19 mpowers Moving XML utilities from util to
+ * xml package.
*
- * Revision 1.1.1.1 2000/12/21 15:52:39 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:39 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:48 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:48 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCEncoder.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCEncoder.java
index 3a63d45..d84f164 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCEncoder.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCEncoder.java
@@ -43,484 +43,398 @@ import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
-* An implementation of XMLEncoder that serializes objects
-* into XMLRPC format, which is found at http://xmlrpc.com/spec.
-* We extend that standard only in that we add a "class"
-* attribute to the "value" tag, so that a java-based decoder
-* can more closely reconstruct the original java data structure.
-* The class attribute can be safely ignored by clients.
-* This implementation is not thread-safe, so a new instances
-* should be created to accomodate multiple threads.
-*/
-public class XMLRPCEncoder implements XMLEncoder
-{
- public static final String METHODCALL = "methodCall";
- public static final String METHODNAME = "methodName";
- public static final String METHODRESPONSE = "methodResponse";
- public static final String PARAMS = "params";
- public static final String PARAM = "param";
- public static final String FAULT = "fault";
- public static final String FAULTCODE = "faultCode";
- public static final String FAULTSTRING = "faultString";
-
- public static final String VALUE = "value";
- public static final String CLASS = "class";
-
- public static final String STRUCT = "struct";
- public static final String MEMBER = "member";
- public static final String NAME = "name";
-
- public static final String ARRAY = "array";
- public static final String DATA = "data";
-
- public static final String NIL = "nil";
- public static final String INT = "int";
- public static final String I4 = "i4";
- public static final String BOOLEAN = "boolean";
- public static final String STRING = "string";
- public static final String DOUBLE = "double";
- public static final String DATE = "dateTime.iso8601";
- public static final String BASE64 = "base64";
-
- public static final String TRUE = "1";
- public static final String FALSE = "0";
-
- public static final Format DATEFORMAT8601 =
- new SimpleDateFormat( "yyyyMMdd'T'HHmmss" );
-
- /**
- * Encodes an object to the specified output stream as XML.
- * @param anObject The object to be serialized to XML format.
- * @param anOutputStream The output stream to which the object
- * will be written.
- */
- public void encode( Object anObject, OutputStream anOutputStream )
- {
- try
- {
-
- //XMLWriter writer = new UTF8XMLWriter( anOutputStream );
- RPCXMLWriter writer = new RPCXMLWriter(anOutputStream,OutputFormat.createCompactFormat());
- writeValueToXMLWriter( anObject, writer );
- writer.flush();
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
- }
-
- /**
- * Encodes a method request in XML-RPC format in a "methodCall" tag,
- * and writes the XML to the specified output stream.
- * This method only writes XML: the caller is responsible for
- * generating the appropriate header, if any, which should set
- * the content type as "text/xml" and the content length as appropriate.
- * The caller is also responsible for writing the xml version tag.
- * @param aMethodName The method name to appear in the "methodName" tag.
- * @param aParameterArray An array of objects, each of which will be
- * encoded as values enclosed in a "param" tag, all of which will be
- * enclosed in a "params" tag.
- * @param anOutputStream The stream to which the XML will be written.
- */
- public void encodeRequest(
- String aMethodName, Object[] aParameterArray,
- OutputStream anOutputStream )
- {
- try
- {
- RPCXMLWriter writer = new RPCXMLWriter( anOutputStream, OutputFormat.createCompactFormat());
- writer.processingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" );
- writer.startElement( METHODCALL );
- writer.startElement( METHODNAME );
- writer.write( aMethodName );
- writer.endElement( METHODNAME );
- writer.startElement( PARAMS );
- for ( int i = 0; i < aParameterArray.length; i++ )
- {
- writer.startElement( PARAM );
- writeValueToXMLWriter( aParameterArray[i], writer );
- writer.endElement( PARAM );
- }
- writer.endElement( PARAMS );
- writer.endElement( METHODCALL );
- writer.flush();
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
-
- //TODO: should this return the content-length?
- }
-
- /**
- * Encodes a method response in XML-RPC format in a "methodResponse" tag,
- * and writes the XML to the specified output stream.
- * This method only writes XML: the caller is responsible for
- * generating the appropriate header, if any, which should set
- * the content type as "text/xml" and the content length as appropriate.
- * The caller is also responsible for writing the xml version tag.
- * @param aResult A object which will be
- * encoded as values enclosed in a "param" tag, all of which will be
- * enclosed in a "params" tag.
- * @param anOutputStream The stream to which the XML will be written.
- */
- public void encodeResponse(
- Object aResult, OutputStream anOutputStream )
- {
- try
- {
- RPCXMLWriter writer = new RPCXMLWriter( anOutputStream, OutputFormat.createCompactFormat() );
- writer.processingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" );
- writer.startElement( METHODRESPONSE );
- writer.startElement( PARAMS );
- writer.startElement( PARAM );
- writeValueToXMLWriter( aResult, writer );
- writer.endElement( PARAM );
- writer.endElement( PARAMS );
- writer.endElement( METHODRESPONSE );
- writer.flush();
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
-
- //TODO: should this return the content-length?
- }
-
- /**
- * Encodes a fault response in XML-RPC format in a "methodResponse" tag,
- * and writes the XML to the specified output stream.
- * This method only writes XML: the caller is responsible for first
- * generating the appropriate header, if any, which should set
- * the content type as "text/xml" and the content length as appropriate.
- * The caller is also responsible for writing the xml version tag.
- * @param aFaultCode An application-defined error code.
- * @param aFaultString A human-readable error description.
- * @param anOutputStream The stream to which the XML will be written.
- */
- public void encodeFault(
- int aFaultCode, String aFaultString, OutputStream anOutputStream )
- {
- try
- {
- RPCXMLWriter writer = new RPCXMLWriter( anOutputStream, OutputFormat.createCompactFormat() );
- writer.processingInstruction( "xml", "version=\"1.0\"" );
- writer.startElement( METHODRESPONSE );
- writer.startElement( FAULT );
- writer.startElement( VALUE );
- writer.startElement( STRUCT );
-
- writer.startElement( MEMBER );
- writer.startElement( NAME );
- writer.write( FAULTCODE );
- writer.endElement( NAME );
- writer.startElement( VALUE );
- writer.startElement( INT );
- writer.write( new Integer( aFaultCode ).toString() );
- writer.endElement( INT );
- writer.endElement( VALUE );
- writer.endElement( MEMBER );
-
- writer.startElement( MEMBER );
- writer.startElement( NAME );
- writer.write( FAULTSTRING );
- writer.endElement( NAME );
- writer.startElement( VALUE );
- writer.startElement( STRING );
- writer.write( aFaultString );
- writer.endElement( STRING );
- writer.endElement( VALUE );
- writer.endElement( MEMBER );
-
- writer.endElement( STRUCT );
- writer.endElement( VALUE );
- writer.endElement( FAULT );
- writer.endElement( METHODRESPONSE );
- writer.flush();
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
-
- //TODO: should this return the content-length?
- }
-
- /**
- * Performs the actual writing of the file to XML.
- */
- private void writeValueToXMLWriter(
- Object anObject, RPCXMLWriter writer )
- {
- try
- {
-
-
- if ( anObject == null )
- {
- writer.startElement( VALUE );
- // write nil for null
- Element nill = new NonLazyElement(NIL);
- writer.write(nill);
- }
- else
- if ( anObject instanceof Collection )
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- // write items in the order we get them from the iterator
-
- writer.startElement( ARRAY );
- writer.startElement( DATA );
- Iterator it = ((Collection)anObject).iterator();
- while ( it.hasNext() )
- {
- writeValueToXMLWriter( it.next(), writer );
- }
- writer.endElement( DATA );
- writer.endElement( ARRAY );
-
- }
- else
- if ( anObject instanceof Map )
- {
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- // write items in the order we get them from the iterator
- //FIXME: The method-based properties are being ignored!
-
- Map.Entry entry;
- writer.startElement( STRUCT );
- writer.startElement( MEMBER );
- Iterator it = ((Map)anObject).entrySet().iterator();
- while ( it.hasNext() )
- {
- entry = (Map.Entry) it.next();
- writer.startElement( NAME );
- writeValueToXMLWriter( entry.getKey(), writer );
- writer.endElement( NAME );
- writeValueToXMLWriter( entry.getValue(), writer );
- }
- writer.endElement( MEMBER );
- writer.endElement( STRUCT );
- }
- else // not a collection
- {
- // check for primitive types
- if ( anObject instanceof String )
- {
- writer.startElement( VALUE );
-
- writer.startElement( STRING );
- writer.write( anObject.toString() );
- writer.endElement( STRING );
- }
- else
- if ( anObject instanceof StringBuffer )
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- writer.startElement( STRING );
- writer.write( anObject.toString() );
- writer.endElement( STRING );
- }
- else
- if ( anObject instanceof Number )
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- if ( ( anObject instanceof Double )
- || ( anObject instanceof Float ) )
- {
- writer.startElement( DOUBLE );
- writer.write( anObject.toString() );
- writer.endElement( DOUBLE );
- }
- else
- {
- writer.startElement( INT );
- writer.write( anObject.toString() );
- writer.endElement( INT );
- }
- }
- else
- if ( anObject instanceof Date )
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- writer.startElement( DATE );
- writer.write( DATEFORMAT8601.format( anObject ) );
- writer.endElement( DATE );
- }
- else
- if ( anObject instanceof Boolean )
- {
- writer.startElement( BOOLEAN );
- if ( ((Boolean)anObject).booleanValue() )
- {
- writer.write( "1" );
- }
- else
- {
- writer.write( "0" );
- }
- writer.endElement( BOOLEAN );
- }
- else
- if ( anObject.getClass().isArray() )
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- writer.startElement( ARRAY );
- writer.startElement( DATA );
-
- int length = Array.getLength( anObject );
- for ( int i = 0; i < length; i++ )
- {
- writeValueToXMLWriter( Array.get( anObject, i ), writer );
- }
-
- writer.endElement( DATA );
- writer.endElement( ARRAY );
- }
- else // not primitive or collection, treat as struct
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- List readProperties = new ArrayList();
- String[] read = Introspector.getReadPropertiesForObject( anObject );
- for ( int i = 0; i < read.length; i++ )
- {
- readProperties.add( read[i] );
- }
-
- List properties = new ArrayList();
- String[] write = Introspector.getWritePropertiesForObject( anObject );
- for ( int i = 0; i < write.length; i++ )
- {
- properties.add( write[i] );
- }
-
- // only use readable properties
- properties.retainAll( readProperties );
-
+ * An implementation of XMLEncoder that serializes objects into XMLRPC format,
+ * which is found at http://xmlrpc.com/spec. We extend that standard only in
+ * that we add a "class" attribute to the "value" tag, so that a java-based
+ * decoder can more closely reconstruct the original java data structure. The
+ * class attribute can be safely ignored by clients. This implementation is not
+ * thread-safe, so a new instances should be created to accomodate multiple
+ * threads.
+ */
+public class XMLRPCEncoder implements XMLEncoder {
+ public static final String METHODCALL = "methodCall";
+ public static final String METHODNAME = "methodName";
+ public static final String METHODRESPONSE = "methodResponse";
+ public static final String PARAMS = "params";
+ public static final String PARAM = "param";
+ public static final String FAULT = "fault";
+ public static final String FAULTCODE = "faultCode";
+ public static final String FAULTSTRING = "faultString";
+
+ public static final String VALUE = "value";
+ public static final String CLASS = "class";
+
+ public static final String STRUCT = "struct";
+ public static final String MEMBER = "member";
+ public static final String NAME = "name";
+
+ public static final String ARRAY = "array";
+ public static final String DATA = "data";
+
+ public static final String NIL = "nil";
+ public static final String INT = "int";
+ public static final String I4 = "i4";
+ public static final String BOOLEAN = "boolean";
+ public static final String STRING = "string";
+ public static final String DOUBLE = "double";
+ public static final String DATE = "dateTime.iso8601";
+ public static final String BASE64 = "base64";
+
+ public static final String TRUE = "1";
+ public static final String FALSE = "0";
+
+ public static final Format DATEFORMAT8601 = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
+
+ /**
+ * Encodes an object to the specified output stream as XML.
+ *
+ * @param anObject The object to be serialized to XML format.
+ * @param anOutputStream The output stream to which the object will be written.
+ */
+ public void encode(Object anObject, OutputStream anOutputStream) {
+ try {
+
+ // XMLWriter writer = new UTF8XMLWriter( anOutputStream );
+ RPCXMLWriter writer = new RPCXMLWriter(anOutputStream, OutputFormat.createCompactFormat());
+ writeValueToXMLWriter(anObject, writer);
+ writer.flush();
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+ }
+
+ /**
+ * Encodes a method request in XML-RPC format in a "methodCall" tag, and writes
+ * the XML to the specified output stream. This method only writes XML: the
+ * caller is responsible for generating the appropriate header, if any, which
+ * should set the content type as "text/xml" and the content length as
+ * appropriate. The caller is also responsible for writing the xml version tag.
+ *
+ * @param aMethodName The method name to appear in the "methodName" tag.
+ * @param aParameterArray An array of objects, each of which will be encoded as
+ * values enclosed in a "param" tag, all of which will be
+ * enclosed in a "params" tag.
+ * @param anOutputStream The stream to which the XML will be written.
+ */
+ public void encodeRequest(String aMethodName, Object[] aParameterArray, OutputStream anOutputStream) {
+ try {
+ RPCXMLWriter writer = new RPCXMLWriter(anOutputStream, OutputFormat.createCompactFormat());
+ writer.processingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
+ writer.startElement(METHODCALL);
+ writer.startElement(METHODNAME);
+ writer.write(aMethodName);
+ writer.endElement(METHODNAME);
+ writer.startElement(PARAMS);
+ for (int i = 0; i < aParameterArray.length; i++) {
+ writer.startElement(PARAM);
+ writeValueToXMLWriter(aParameterArray[i], writer);
+ writer.endElement(PARAM);
+ }
+ writer.endElement(PARAMS);
+ writer.endElement(METHODCALL);
+ writer.flush();
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+
+ // TODO: should this return the content-length?
+ }
+
+ /**
+ * Encodes a method response in XML-RPC format in a "methodResponse" tag, and
+ * writes the XML to the specified output stream. This method only writes XML:
+ * the caller is responsible for generating the appropriate header, if any,
+ * which should set the content type as "text/xml" and the content length as
+ * appropriate. The caller is also responsible for writing the xml version tag.
+ *
+ * @param aResult A object which will be encoded as values enclosed in a
+ * "param" tag, all of which will be enclosed in a
+ * "params" tag.
+ * @param anOutputStream The stream to which the XML will be written.
+ */
+ public void encodeResponse(Object aResult, OutputStream anOutputStream) {
+ try {
+ RPCXMLWriter writer = new RPCXMLWriter(anOutputStream, OutputFormat.createCompactFormat());
+ writer.processingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
+ writer.startElement(METHODRESPONSE);
+ writer.startElement(PARAMS);
+ writer.startElement(PARAM);
+ writeValueToXMLWriter(aResult, writer);
+ writer.endElement(PARAM);
+ writer.endElement(PARAMS);
+ writer.endElement(METHODRESPONSE);
+ writer.flush();
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+
+ // TODO: should this return the content-length?
+ }
+
+ /**
+ * Encodes a fault response in XML-RPC format in a "methodResponse" tag, and
+ * writes the XML to the specified output stream. This method only writes XML:
+ * the caller is responsible for first generating the appropriate header, if
+ * any, which should set the content type as "text/xml" and the content length
+ * as appropriate. The caller is also responsible for writing the xml version
+ * tag.
+ *
+ * @param aFaultCode An application-defined error code.
+ * @param aFaultString A human-readable error description.
+ * @param anOutputStream The stream to which the XML will be written.
+ */
+ public void encodeFault(int aFaultCode, String aFaultString, OutputStream anOutputStream) {
+ try {
+ RPCXMLWriter writer = new RPCXMLWriter(anOutputStream, OutputFormat.createCompactFormat());
+ writer.processingInstruction("xml", "version=\"1.0\"");
+ writer.startElement(METHODRESPONSE);
+ writer.startElement(FAULT);
+ writer.startElement(VALUE);
+ writer.startElement(STRUCT);
+
+ writer.startElement(MEMBER);
+ writer.startElement(NAME);
+ writer.write(FAULTCODE);
+ writer.endElement(NAME);
+ writer.startElement(VALUE);
+ writer.startElement(INT);
+ writer.write(new Integer(aFaultCode).toString());
+ writer.endElement(INT);
+ writer.endElement(VALUE);
+ writer.endElement(MEMBER);
+
+ writer.startElement(MEMBER);
+ writer.startElement(NAME);
+ writer.write(FAULTSTRING);
+ writer.endElement(NAME);
+ writer.startElement(VALUE);
+ writer.startElement(STRING);
+ writer.write(aFaultString);
+ writer.endElement(STRING);
+ writer.endElement(VALUE);
+ writer.endElement(MEMBER);
+
+ writer.endElement(STRUCT);
+ writer.endElement(VALUE);
+ writer.endElement(FAULT);
+ writer.endElement(METHODRESPONSE);
+ writer.flush();
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+
+ // TODO: should this return the content-length?
+ }
+
+ /**
+ * Performs the actual writing of the file to XML.
+ */
+ private void writeValueToXMLWriter(Object anObject, RPCXMLWriter writer) {
+ try {
+
+ if (anObject == null) {
+ writer.startElement(VALUE);
+ // write nil for null
+ Element nill = new NonLazyElement(NIL);
+ writer.write(nill);
+ } else if (anObject instanceof Collection) {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ // write items in the order we get them from the iterator
+
+ writer.startElement(ARRAY);
+ writer.startElement(DATA);
+ Iterator it = ((Collection) anObject).iterator();
+ while (it.hasNext()) {
+ writeValueToXMLWriter(it.next(), writer);
+ }
+ writer.endElement(DATA);
+ writer.endElement(ARRAY);
+
+ } else if (anObject instanceof Map) {
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ // write items in the order we get them from the iterator
+ // FIXME: The method-based properties are being ignored!
+
+ Map.Entry entry;
+ writer.startElement(STRUCT);
+ writer.startElement(MEMBER);
+ Iterator it = ((Map) anObject).entrySet().iterator();
+ while (it.hasNext()) {
+ entry = (Map.Entry) it.next();
+ writer.startElement(NAME);
+ writeValueToXMLWriter(entry.getKey(), writer);
+ writer.endElement(NAME);
+ writeValueToXMLWriter(entry.getValue(), writer);
+ }
+ writer.endElement(MEMBER);
+ writer.endElement(STRUCT);
+ } else // not a collection
+ {
+ // check for primitive types
+ if (anObject instanceof String) {
+ writer.startElement(VALUE);
+
+ writer.startElement(STRING);
+ writer.write(anObject.toString());
+ writer.endElement(STRING);
+ } else if (anObject instanceof StringBuffer) {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ writer.startElement(STRING);
+ writer.write(anObject.toString());
+ writer.endElement(STRING);
+ } else if (anObject instanceof Number) {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ if ((anObject instanceof Double) || (anObject instanceof Float)) {
+ writer.startElement(DOUBLE);
+ writer.write(anObject.toString());
+ writer.endElement(DOUBLE);
+ } else {
+ writer.startElement(INT);
+ writer.write(anObject.toString());
+ writer.endElement(INT);
+ }
+ } else if (anObject instanceof Date) {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ writer.startElement(DATE);
+ writer.write(DATEFORMAT8601.format(anObject));
+ writer.endElement(DATE);
+ } else if (anObject instanceof Boolean) {
+ writer.startElement(BOOLEAN);
+ if (((Boolean) anObject).booleanValue()) {
+ writer.write("1");
+ } else {
+ writer.write("0");
+ }
+ writer.endElement(BOOLEAN);
+ } else if (anObject.getClass().isArray()) {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ writer.startElement(ARRAY);
+ writer.startElement(DATA);
+
+ int length = Array.getLength(anObject);
+ for (int i = 0; i < length; i++) {
+ writeValueToXMLWriter(Array.get(anObject, i), writer);
+ }
+
+ writer.endElement(DATA);
+ writer.endElement(ARRAY);
+ } else // not primitive or collection, treat as struct
+ {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ List readProperties = new ArrayList();
+ String[] read = Introspector.getReadPropertiesForObject(anObject);
+ for (int i = 0; i < read.length; i++) {
+ readProperties.add(read[i]);
+ }
+
+ List properties = new ArrayList();
+ String[] write = Introspector.getWritePropertiesForObject(anObject);
+ for (int i = 0; i < write.length; i++) {
+ properties.add(write[i]);
+ }
+
+ // only use readable properties
+ properties.retainAll(readProperties);
+
// if ( properties.size() > 0 )
// {
- String key;
- Object value;
- Iterator it = properties.iterator();
- writer.startElement( STRUCT );
- while ( it.hasNext() )
- {
- key = (String) it.next();
- value = Introspector.get( anObject, key );
-
- writer.startElement( MEMBER );
- writer.startElement( NAME );
- writer.write( key );
- writer.endElement( NAME );
- writeValueToXMLWriter( value, writer );
- writer.endElement( MEMBER );
- }
- writer.endElement( STRUCT );
-/*
- }
- else // no properties - write a converted string
- {
- writer.startElement( STRING );
- Object converted =
- ValueConverter.convertObjectToClass( anObject, String.class );
- if ( converted != null )
- {
- writer.write( converted.toString() );
- }
- else
- {
- writer.write( anObject.toString() );
- }
- writer.endElement( STRING );
- }
-*/
- }
- }
-
- writer.endElement( VALUE );
- }
- catch ( Exception exc )
- {
- System.err.println( "XMLFileSoup.writeValueToXMLWriter: " + exc );
- exc.printStackTrace();
- }
-
- }
-/*
- public static void main( String[] argv )
- {
- System.out.println( "<test>" );
- XMLRPCEncoder encoder = new XMLRPCEncoder();
- encoder.encodeRequest( "systemObject.test", new Object[] {
- new net.wotonomy.test.TestObject(),
- new net.wotonomy.test.TestObject(),
- new net.wotonomy.test.TestObject() }, System.out );
- System.out.println();
- System.out.println();
- encoder.encodeResponse( new net.wotonomy.test.TestObject(), System.out );
- System.out.println();
- System.out.println();
- encoder.encodeFault( -1, "This is a fault.", System.out );
- System.out.println();
- System.out.println();
- System.out.println( "</test>" );
- }
-*/
-
- private class RPCXMLWriter extends XMLWriter {
+ String key;
+ Object value;
+ Iterator it = properties.iterator();
+ writer.startElement(STRUCT);
+ while (it.hasNext()) {
+ key = (String) it.next();
+ value = Introspector.get(anObject, key);
+
+ writer.startElement(MEMBER);
+ writer.startElement(NAME);
+ writer.write(key);
+ writer.endElement(NAME);
+ writeValueToXMLWriter(value, writer);
+ writer.endElement(MEMBER);
+ }
+ writer.endElement(STRUCT);
+ /*
+ * } else // no properties - write a converted string { writer.startElement(
+ * STRING ); Object converted = ValueConverter.convertObjectToClass( anObject,
+ * String.class ); if ( converted != null ) { writer.write( converted.toString()
+ * ); } else { writer.write( anObject.toString() ); } writer.endElement( STRING
+ * ); }
+ */
+ }
+ }
+
+ writer.endElement(VALUE);
+ } catch (Exception exc) {
+ System.err.println("XMLFileSoup.writeValueToXMLWriter: " + exc);
+ exc.printStackTrace();
+ }
+
+ }
+ /*
+ * public static void main( String[] argv ) { System.out.println( "<test>" );
+ * XMLRPCEncoder encoder = new XMLRPCEncoder(); encoder.encodeRequest(
+ * "systemObject.test", new Object[] { new net.wotonomy.test.TestObject(), new
+ * net.wotonomy.test.TestObject(), new net.wotonomy.test.TestObject() },
+ * System.out ); System.out.println(); System.out.println();
+ * encoder.encodeResponse( new net.wotonomy.test.TestObject(), System.out );
+ * System.out.println(); System.out.println(); encoder.encodeFault( -1,
+ * "This is a fault.", System.out ); System.out.println(); System.out.println();
+ * System.out.println( "</test>" ); }
+ */
+
+ private class RPCXMLWriter extends XMLWriter {
public RPCXMLWriter(OutputStream arg0, OutputFormat arg1) throws UnsupportedEncodingException {
super(arg0, arg1);
}
- public void endElement(String localname) throws SAXException {
+ public void endElement(String localname) throws SAXException {
super.endElement(null, localname, null);
}
public void startElement(String localname) throws SAXException {
this.startElement(localname, null);
}
+
public void startElement(String localname, Attributes attributes) throws SAXException {
this.startElement(null, localname, null, attributes);
}
- }
-
+ }
+
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCReceiver.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCReceiver.java
index 48c9e41..5848cd0 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCReceiver.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCReceiver.java
@@ -19,54 +19,51 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web.xml;
/**
-* A call-back interface that receives an XML-RPC transaction message.
-* Used by XMLRPCDecoder to return values from a message.
-*/
-public interface XMLRPCReceiver
-{
- /**
- * Receives an XML-RPC request.
- * @param aMethodName The method name of the request.
- * @param aParameterArray The objects contained in the request, in order.
- */
- void request( String aMethodName, Object[] aParameterArray );
-
- /**
- * Receives an XML-RPC response.
- * @param aResult The object contained in the response.
- */
- void response( Object aResult );
-
- /**
- * Receives an XML-RPC fault response.
- * @param aFaultCode The fault code contained in the response.
- * @param aFaultString The fault string contained in the response.
- */
- void fault( int aFaultCode, String aFaultString );
+ * A call-back interface that receives an XML-RPC transaction message. Used by
+ * XMLRPCDecoder to return values from a message.
+ */
+public interface XMLRPCReceiver {
+ /**
+ * Receives an XML-RPC request.
+ *
+ * @param aMethodName The method name of the request.
+ * @param aParameterArray The objects contained in the request, in order.
+ */
+ void request(String aMethodName, Object[] aParameterArray);
+
+ /**
+ * Receives an XML-RPC response.
+ *
+ * @param aResult The object contained in the response.
+ */
+ void response(Object aResult);
+
+ /**
+ * Receives an XML-RPC fault response.
+ *
+ * @param aFaultCode The fault code contained in the response.
+ * @param aFaultString The fault string contained in the response.
+ */
+ void fault(int aFaultCode, String aFaultString);
}
/*
- * $Log$
- * Revision 1.1 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.1 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2001/02/06 14:34:23 mpowers
- * Forgot to rename the package declarations.
+ * Revision 1.2 2001/02/06 14:34:23 mpowers Forgot to rename the package
+ * declarations.
*
- * Revision 1.1 2001/02/06 14:31:19 mpowers
- * Moving XML utilities from util to xml package.
+ * Revision 1.1 2001/02/06 14:31:19 mpowers Moving XML utilities from util to
+ * xml package.
*
- * Revision 1.1.1.1 2000/12/21 15:52:44 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:44 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCSelector.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCSelector.java
index 7c1f104..599481f 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCSelector.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCSelector.java
@@ -32,207 +32,155 @@ import net.wotonomy.foundation.NSSelector;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* An NSSelector customized to invoke methods with XMLRPC
-* when a URL is passed in as the object to the invoke() method.
-* The method name and parameters will be marshalled and sent
-* as an XMLRPC request to the host specified by the URL. <br><br>
-*
-* To use this class simply as an XMLRPC client, just call
-* invoke() with a URL referencing the XMLRPC server and an
-* optional array of parameters.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class XMLRPCSelector extends NSSelector
-{
- private boolean copyStream = false;
-
- /**
- * Constructor specifying a method name.
- */
- public XMLRPCSelector (String aMethodName)
- {
- super( aMethodName, EMPTY_CLASS_ARRAY );
- }
-
- /**
- * Constructor specifying a method name and an array of parameter types.
- * When accessing XMLRPC servers, invoke() does require that the
- * specified objects match the types in the parameter type array.
- */
- public XMLRPCSelector (String aMethodName, Class[] aParameterTypeArray)
- {
- super( aMethodName, aParameterTypeArray );
- }
-
- /**
- * Invokes this selector's method on the specified object
- * using the specified parameters.
- */
- public Object invoke (Object anObject, Object[] parameters)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- if ( anObject instanceof URL )
- {
- Receiver receiver = new Receiver();
- byte[] copyOfResponse = null;
- try
- {
- URLConnection cn = ((URL)anObject).openConnection();
-
- // set properties
- cn.setDoOutput(true);
- cn.setDoInput(true);
- cn.setRequestProperty(
- "content-type","text/xml");
-
- // send parameters
- OutputStream out = cn.getOutputStream();
- new XMLRPCEncoder().encodeRequest(
- name(), parameters, out );
- out.flush();
- out.close();
-
- // get response: getInputStream initiates the request
- InputStream input =
- new BufferedInputStream( cn.getInputStream() );
- if ( copyStream )
- {
- ByteArrayOutputStream byteArray =
- new ByteArrayOutputStream();
- int b;
- while ( ( b = input.read() ) != -1 )
- {
- byteArray.write( b );
- }
- copyOfResponse = byteArray.toByteArray();
- input = new ByteArrayInputStream( copyOfResponse );
- }
- new XMLRPCDecoder().decode( input, receiver );
- }
- catch ( FileNotFoundException exc )
- {
- throw new WotonomyException( "Server did not return a response." );
- }
- catch ( Exception exc )
- {
- if ( copyOfResponse != null )
- {
- System.out.println( new String( copyOfResponse ) );
- exc.printStackTrace();
- }
- throw new InvocationTargetException( exc );
- }
-
- if ( receiver.faultString == null )
- {
- return receiver.result;
- }
- else
- {
- throw new InvocationTargetException(
- new WotonomyException(
- receiver.faultCode + ": " + receiver.faultString ) );
- }
- }
-
- // else: not a URL
- return super.invoke( anObject, parameters );
+ * An NSSelector customized to invoke methods with XMLRPC when a URL is passed
+ * in as the object to the invoke() method. The method name and parameters will
+ * be marshalled and sent as an XMLRPC request to the host specified by the URL.
+ * <br>
+ * <br>
+ *
+ * To use this class simply as an XMLRPC client, just call invoke() with a URL
+ * referencing the XMLRPC server and an optional array of parameters.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class XMLRPCSelector extends NSSelector {
+ private boolean copyStream = false;
+
+ /**
+ * Constructor specifying a method name.
+ */
+ public XMLRPCSelector(String aMethodName) {
+ super(aMethodName, EMPTY_CLASS_ARRAY);
+ }
+
+ /**
+ * Constructor specifying a method name and an array of parameter types. When
+ * accessing XMLRPC servers, invoke() does require that the specified objects
+ * match the types in the parameter type array.
+ */
+ public XMLRPCSelector(String aMethodName, Class[] aParameterTypeArray) {
+ super(aMethodName, aParameterTypeArray);
}
- public static Object invoke
- (String methodName, Class[] parameterTypes, Object anObject, Object[] parameters)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return new XMLRPCSelector( methodName, parameterTypes ).invoke( anObject, parameters );
+ /**
+ * Invokes this selector's method on the specified object using the specified
+ * parameters.
+ */
+ public Object invoke(Object anObject, Object[] parameters)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ if (anObject instanceof URL) {
+ Receiver receiver = new Receiver();
+ byte[] copyOfResponse = null;
+ try {
+ URLConnection cn = ((URL) anObject).openConnection();
+
+ // set properties
+ cn.setDoOutput(true);
+ cn.setDoInput(true);
+ cn.setRequestProperty("content-type", "text/xml");
+
+ // send parameters
+ OutputStream out = cn.getOutputStream();
+ new XMLRPCEncoder().encodeRequest(name(), parameters, out);
+ out.flush();
+ out.close();
+
+ // get response: getInputStream initiates the request
+ InputStream input = new BufferedInputStream(cn.getInputStream());
+ if (copyStream) {
+ ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
+ int b;
+ while ((b = input.read()) != -1) {
+ byteArray.write(b);
+ }
+ copyOfResponse = byteArray.toByteArray();
+ input = new ByteArrayInputStream(copyOfResponse);
+ }
+ new XMLRPCDecoder().decode(input, receiver);
+ } catch (FileNotFoundException exc) {
+ throw new WotonomyException("Server did not return a response.");
+ } catch (Exception exc) {
+ if (copyOfResponse != null) {
+ System.out.println(new String(copyOfResponse));
+ exc.printStackTrace();
+ }
+ throw new InvocationTargetException(exc);
+ }
+
+ if (receiver.faultString == null) {
+ return receiver.result;
+ } else {
+ throw new InvocationTargetException(
+ new WotonomyException(receiver.faultCode + ": " + receiver.faultString));
+ }
+ }
+
+ // else: not a URL
+ return super.invoke(anObject, parameters);
}
- public static Object invoke
- (String methodName, Object anObject)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return XMLRPCSelector.invoke(
- methodName, EMPTY_CLASS_ARRAY, anObject, EMPTY_OBJECT_ARRAY );
+ public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object[] parameters)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return new XMLRPCSelector(methodName, parameterTypes).invoke(anObject, parameters);
}
- public static Object invoke
- (String methodName, Class[] parameterTypes,
- Object anObject, Object aParameter)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return XMLRPCSelector.invoke(
- methodName, parameterTypes, anObject, new Object[] { aParameter } );
+ public static Object invoke(String methodName, Object anObject)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return XMLRPCSelector.invoke(methodName, EMPTY_CLASS_ARRAY, anObject, EMPTY_OBJECT_ARRAY);
}
- public static Object invoke
- (String methodName, Class[] parameterTypes,
- Object anObject, Object p1, Object p2)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return XMLRPCSelector.invoke(
- methodName, parameterTypes, anObject, new Object[] { p1, p2 } );
+ public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object aParameter)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return XMLRPCSelector.invoke(methodName, parameterTypes, anObject, new Object[] { aParameter });
+ }
+
+ public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object p1, Object p2)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return XMLRPCSelector.invoke(methodName, parameterTypes, anObject, new Object[] { p1, p2 });
+ }
+
+ private class Receiver implements XMLRPCReceiver {
+ public Object result;
+ public int faultCode;
+ public String faultString;
+
+ public Receiver() {
+ result = null;
+ faultCode = -1;
+ faultString = null;
+ }
+
+ public void request(String aMethodName, Object[] aParameterArray) {
+ throw new WotonomyException("Invalid response: Expected response but received request.");
+ }
+
+ public void response(Object aResult) {
+ result = aResult;
+ faultCode = -1;
+ faultString = null;
+ }
+
+ public void fault(int aFaultCode, String aFaultString) {
+ result = null;
+ faultCode = aFaultCode;
+ faultString = aFaultString;
+ }
}
-
- private class Receiver implements XMLRPCReceiver
- {
- public Object result;
- public int faultCode;
- public String faultString;
-
- public Receiver()
- {
- result = null;
- faultCode = -1;
- faultString = null;
- }
-
- public void request(
- String aMethodName, Object[] aParameterArray )
- {
- throw new WotonomyException(
- "Invalid response: Expected response but received request." );
- }
-
- public void response(
- Object aResult )
- {
- result = aResult;
- faultCode = -1;
- faultString = null;
- }
-
- public void fault(
- int aFaultCode, String aFaultString)
- {
- result = null;
- faultCode = aFaultCode;
- faultString = aFaultString;
- }
- }
-
}
/*
- * $Log$
- * Revision 1.1 2006/02/19 01:44:03 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.1 2006/02/19 01:44:03 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2001/02/07 19:24:28 mpowers
- * Moved XML classes to separate package.
+ * Revision 1.1 2001/02/07 19:24:28 mpowers Moved XML classes to separate
+ * package.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java
index a9981a4..94b5680 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java
@@ -34,250 +34,195 @@ import net.wotonomy.foundation.NSSelector;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* A servlet that can make any java object into an XML-RPC server.
-* Simply pass in the object to the constructor and XML-RPC requests
-* to this servlet will call the appropriate methods and convert
-* the results to an XML-RPC response. <br><br>
-*
-* Depending on your servlet container, it may be necessary to
-* create a simple subclass that creates your handler object
-* in its constructor and then calls setHandler(). <br><br>
-*
-* Responses are in the specification's standard response format.<br><br>
-*
-* Faults are returned if any exception is thrown in the method,
-* or if the specified method is not found on the object.
-* The fault string is the toString value of the exception,
-* and the fault code is the hasCode value of the exception. <br><br>
-*
-* Remember that this servlet only responds to POSTs,
-* per the XML-RPC spec.
-*/
-public class XMLRPCServlet extends HttpServlet
-{
- protected Object handler;
- protected boolean synchronizing;
- private Hashtable selectorCache = new Hashtable(); // thread safe
- private boolean copyStream = false;
-
- /**
- * Default constructor initializes internal state.
- */
- public XMLRPCServlet()
- {
- handler = null;
- synchronizing = false;
- }
-
- /**
- * Constructor takes any java object and allows its methods
- * to be invoked via XMLRPC requests to this servlet.
- * Simply calls setHandler().
- */
- public XMLRPCServlet( Object aHandler )
- {
- this();
- setHandler( aHandler );
- }
-
- /**
- * Gets the object whose methods will be invoked to
- * handle incoming requests.
- */
- public Object getHandler()
- {
- return handler;
- }
-
- /**
- * Sets the object whose methods will be invoked to
- * handle incoming requests.
- */
- public void setHandler( Object aHandler )
- {
- handler = aHandler;
- }
-
- /**
- * Gets whether the servlet should synchonize on the
- * object before invoking methods on it.
- * Defaults to false.
- */
- public boolean isSynchronizing()
- {
- return synchronizing;
- }
-
- /**
- * Sets whether the servlet should synchonize on the
- * object before invoking methods on it.
- * Defaults to false.
- */
- public void setSynchronizing( boolean willSynchronize )
- {
- synchronizing = willSynchronize;
- }
-
- /**
- * Overridden to service the request.
- */
- protected void doPost(
- HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException
- {
- if ( getHandler() != null )
- {
- InputStream input = req.getInputStream();
- byte[] copyOfRequest = null;
+ * A servlet that can make any java object into an XML-RPC server. Simply pass
+ * in the object to the constructor and XML-RPC requests to this servlet will
+ * call the appropriate methods and convert the results to an XML-RPC response.
+ * <br>
+ * <br>
+ *
+ * Depending on your servlet container, it may be necessary to create a simple
+ * subclass that creates your handler object in its constructor and then calls
+ * setHandler(). <br>
+ * <br>
+ *
+ * Responses are in the specification's standard response format.<br>
+ * <br>
+ *
+ * Faults are returned if any exception is thrown in the method, or if the
+ * specified method is not found on the object. The fault string is the toString
+ * value of the exception, and the fault code is the hasCode value of the
+ * exception. <br>
+ * <br>
+ *
+ * Remember that this servlet only responds to POSTs, per the XML-RPC spec.
+ */
+public class XMLRPCServlet extends HttpServlet {
+ protected Object handler;
+ protected boolean synchronizing;
+ private Hashtable selectorCache = new Hashtable(); // thread safe
+ private boolean copyStream = false;
+
+ /**
+ * Default constructor initializes internal state.
+ */
+ public XMLRPCServlet() {
+ handler = null;
+ synchronizing = false;
+ }
+
+ /**
+ * Constructor takes any java object and allows its methods to be invoked via
+ * XMLRPC requests to this servlet. Simply calls setHandler().
+ */
+ public XMLRPCServlet(Object aHandler) {
+ this();
+ setHandler(aHandler);
+ }
+
+ /**
+ * Gets the object whose methods will be invoked to handle incoming requests.
+ */
+ public Object getHandler() {
+ return handler;
+ }
+
+ /**
+ * Sets the object whose methods will be invoked to handle incoming requests.
+ */
+ public void setHandler(Object aHandler) {
+ handler = aHandler;
+ }
+
+ /**
+ * Gets whether the servlet should synchonize on the object before invoking
+ * methods on it. Defaults to false.
+ */
+ public boolean isSynchronizing() {
+ return synchronizing;
+ }
+
+ /**
+ * Sets whether the servlet should synchonize on the object before invoking
+ * methods on it. Defaults to false.
+ */
+ public void setSynchronizing(boolean willSynchronize) {
+ synchronizing = willSynchronize;
+ }
+
+ /**
+ * Overridden to service the request.
+ */
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ if (getHandler() != null) {
+ InputStream input = req.getInputStream();
+ byte[] copyOfRequest = null;
- if ( copyStream )
- {
- ByteArrayOutputStream byteArray =
- new ByteArrayOutputStream();
- int b;
- while ( ( b = input.read() ) != -1 )
- {
- byteArray.write( b );
- }
- copyOfRequest = byteArray.toByteArray();
- input = new ByteArrayInputStream( copyOfRequest );
- }
-
- try
- {
- new XMLRPCDecoder().decode( input,
- new Receiver( this, resp ) );
- }
- catch ( WotonomyException exc )
- {
- if ( copyOfRequest != null )
- {
- System.out.println( new String( copyOfRequest ) );
- exc.printStackTrace();
- }
- // catches io exceptions thrown in handleRequest.
- Throwable t = exc.getWrappedThrowable();
- if ( t instanceof IOException )
- {
- throw (IOException)t;
- }
- throw exc;
- }
- }
- }
-
- /**
- * Called by doPost after parsing an incoming request,
- * and is responsible for invoking the specified method
- * with the specified parameters on the handler object.
- * (This implementation calls getOutputStream() on the response.)
- * Override to customize the handling of the request.
- */
- protected void handleRequest( String aMethodName,
- Object[] aParameterArray, HttpServletResponse aResponse )
- {
- OutputStream output = null;
-
- try
- {
- output = aResponse.getOutputStream();
- aResponse.setStatus( HttpServletResponse.SC_OK ); // always 200
- aResponse.setContentType( "text/xml" );
- }
- catch ( IOException exc )
- {
- // caught in doPost
- throw new WotonomyException( exc );
- }
-
- // get the array of types
- XMLRPCEncoder encoder = new XMLRPCEncoder();
- Class[] types = new Class[ aParameterArray.length ];
- for ( int i = 0; i < aParameterArray.length; i++ )
- {
- types[i] = aParameterArray[i].getClass();
- }
-
- //TODO: selectors should be cached if possible
-
- Object handler = getHandler();
- if ( isSynchronizing() )
- {
- synchronized ( handler )
- {
- execute( encoder, handler, output,
- new NSSelector( aMethodName, types ), aParameterArray );
- }
- }
- else
- {
- execute( encoder, handler, output,
- new NSSelector( aMethodName, types ), aParameterArray );
- }
- }
-
- private void execute( XMLRPCEncoder anEncoder, Object aHandler,
- OutputStream output, NSSelector aSelector, Object[] aParameterArray )
- {
- try
- {
- Object result =
- aSelector.invoke( aHandler, aParameterArray );
- anEncoder.encodeResponse( result, output );
- }
- catch ( Exception exc )
- {
- anEncoder.encodeFault(
- exc.hashCode(), exc.toString(), output );
- }
- }
-
- private class Receiver implements XMLRPCReceiver
- {
- XMLRPCServlet controller;
- HttpServletResponse response;
-
- public Receiver(
- XMLRPCServlet aController,
- HttpServletResponse aResponse )
- {
- controller = aController;
- response = aResponse;
- }
-
- public void request(
- String aMethodName, Object[] aParameterArray )
- {
- controller.handleRequest(
- aMethodName, aParameterArray, response );
- }
-
- public void response(
- Object aResult )
- {
- // does nothing
- }
-
- public void fault(
- int aFaultCode, String aFaultString)
- {
- // does nothing
- }
- }
+ if (copyStream) {
+ ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
+ int b;
+ while ((b = input.read()) != -1) {
+ byteArray.write(b);
+ }
+ copyOfRequest = byteArray.toByteArray();
+ input = new ByteArrayInputStream(copyOfRequest);
+ }
+
+ try {
+ new XMLRPCDecoder().decode(input, new Receiver(this, resp));
+ } catch (WotonomyException exc) {
+ if (copyOfRequest != null) {
+ System.out.println(new String(copyOfRequest));
+ exc.printStackTrace();
+ }
+ // catches io exceptions thrown in handleRequest.
+ Throwable t = exc.getWrappedThrowable();
+ if (t instanceof IOException) {
+ throw (IOException) t;
+ }
+ throw exc;
+ }
+ }
+ }
+
+ /**
+ * Called by doPost after parsing an incoming request, and is responsible for
+ * invoking the specified method with the specified parameters on the handler
+ * object. (This implementation calls getOutputStream() on the response.)
+ * Override to customize the handling of the request.
+ */
+ protected void handleRequest(String aMethodName, Object[] aParameterArray, HttpServletResponse aResponse) {
+ OutputStream output = null;
+
+ try {
+ output = aResponse.getOutputStream();
+ aResponse.setStatus(HttpServletResponse.SC_OK); // always 200
+ aResponse.setContentType("text/xml");
+ } catch (IOException exc) {
+ // caught in doPost
+ throw new WotonomyException(exc);
+ }
+
+ // get the array of types
+ XMLRPCEncoder encoder = new XMLRPCEncoder();
+ Class[] types = new Class[aParameterArray.length];
+ for (int i = 0; i < aParameterArray.length; i++) {
+ types[i] = aParameterArray[i].getClass();
+ }
+
+ // TODO: selectors should be cached if possible
+
+ Object handler = getHandler();
+ if (isSynchronizing()) {
+ synchronized (handler) {
+ execute(encoder, handler, output, new NSSelector(aMethodName, types), aParameterArray);
+ }
+ } else {
+ execute(encoder, handler, output, new NSSelector(aMethodName, types), aParameterArray);
+ }
+ }
+
+ private void execute(XMLRPCEncoder anEncoder, Object aHandler, OutputStream output, NSSelector aSelector,
+ Object[] aParameterArray) {
+ try {
+ Object result = aSelector.invoke(aHandler, aParameterArray);
+ anEncoder.encodeResponse(result, output);
+ } catch (Exception exc) {
+ anEncoder.encodeFault(exc.hashCode(), exc.toString(), output);
+ }
+ }
+
+ private class Receiver implements XMLRPCReceiver {
+ XMLRPCServlet controller;
+ HttpServletResponse response;
+
+ public Receiver(XMLRPCServlet aController, HttpServletResponse aResponse) {
+ controller = aController;
+ response = aResponse;
+ }
+
+ public void request(String aMethodName, Object[] aParameterArray) {
+ controller.handleRequest(aMethodName, aParameterArray, response);
+ }
+
+ public void response(Object aResult) {
+ // does nothing
+ }
+
+ public void fault(int aFaultCode, String aFaultString) {
+ // does nothing
+ }
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.1 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2001/02/07 19:24:28 mpowers
- * Moved XML classes to separate package.
+ * Revision 1.1 2001/02/07 19:24:28 mpowers Moved XML classes to separate
+ * package.
*
*/
-