Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: er/extensions/ERXDirectActionHyperlink.java


1   /*
2    * Copyright(C) NetStruxr, Inc. All rights reserved.
3    *
4    * This software is published under the terms of the NetStruxr
5    * Public Software License version 0.5, a copy of which has been
6    * included with this distribution in the LICENSE.NPL file.  */
7   package er.extensions;
8   
9   import com.webobjects.foundation.*;
10  import com.webobjects.eocontrol.*;
11  import com.webobjects.eoaccess.*;
12  import com.webobjects.appserver.*;
13  import java.util.*;
14  
15  /**
16   * This component can be used for two things:<br/>
17   * 1) Generating direct action urls for use in
18   * components that are being e-mailed to people.
19   * 2) Support for encoding enterprise objects in
20   * the form values of generated urls.
21   * At the moment this component still contains some
22   * custy code that needs to be cleaned up before it
23   * can really be used, like adding the .wo and .api files ;0.<br/>
24   * <br/>
25   * Synopsis:<br/>
26   * [actionClass=<i>anActionClass</i>];directActionName=<i>aDirectActionName</i>;[entityNameSeparator=<i>aSeparator</i>;]
27   * [relative=<i>aBoolean</i>;][shouldEncryptObjectFormValues=<i>aBoolean</i>;][objectsForFormValues=<i>anArray</i>;]
28   * [bindingDictionary=<i>aDictionary</i>;][unencryptedBindingDictionary=<i>aDictionary</i>;]
29   *
30   * @binding actionClass direct action class to be used
31   * @binding directActionName direct action name
32   * @binding entityNameSeparator separator used when constructiong urls with encoded enterprise objects
33   * @binding relative generates relative or absolute url
34   * @binding shouldEncryptObjectFormValues boolean flag that tells if the primary keys
35   *    of the enterprise objects should be encrypted using blowfish
36   * @binding objectForFormValue an enterprise object to be encoded in the url
37   * @binding objectsForFormValues array of enterprise objects to be encoded in the url
38   * @binding bindingDictionary adds the key-value pairs to generated url as
39   *     form values, encrypting the values with blowfish.
40   * @binding unencryptedBindingDictionary adds the key-value pairs to generated url as
41   *     form values
42   */
43  public class ERXDirectActionHyperlink extends ERXStatelessComponent {
44  
45      // Class instances -------------------------------------------------
46  
47      /** Key used to denote an adaptor prefix for a generated url string */
48      // MOVEME: ERXWOUtilities
49      public final static String ADAPTOR_PREFIX_MARKER="**ADAPTOR_PREFIX**";
50      /** Key used to denote a suffix for a generated url string */ 
51      // MOVEME: ERXWOUtilities
52      public final static String SUFFIX_MARKER="**SUFFIX**";
53  
54      /** logging support */
55      public static final ERXLogger log = ERXLogger.getERXLogger(ERXDirectActionHyperlink.class);
56  
57    
58      // Constructor -------------------------------------------------
59      /**
60       * Public constructor
61       * @param aContext a context
62       */
63      public ERXDirectActionHyperlink(WOContext aContext) {
64          super(aContext);
65      }
66  
67    
68      // Component methods -------------------------------------------------
69  
70      /**
71       * Cover method to return the binding: <b>entityNameSeparator</b>
72       * The entity name separator is used when constructing URLs with enterprise objects encoded in the url.
73       * This value default to the value defined in the system property <i>er.extensions.ERXDirectActionHyperlink.EntityNameSeparator</i> which defaults as well to the character '<pre>_</pre>'.
74       * @return returns the value for binding: <b>entityNameSeparator</b>
75       */
76      public String entityNameSeparator() {
77          String separator = (String)this.valueForBinding("entityNameSeparator");
78          if (separator == null)
79              separator = ERXEOEncodingUtilities.EntityNameSeparator;
80          return separator;
81      }
82  
83      /**
84       * Cover method to return the boolean value
85       * of the binding: <b>relative</b>
86       * Defaults to <code>true</code>.
87       * @return returns if the generated url should be relative or not(absolute).
88       */
89      public boolean relative() {
90          return valueForBooleanBinding("relative", true);
91      }
92  
93      /**
94       * Cover method to return the boolean value
95       * of the binding: <b>shouldEncryptObjectFormValues</b>
96       * Defaults to <code>false</code>. 
97       * @return returns if the encoded objects' primary keys
98       *    should be encrypted or not.
99       */
100     public boolean shouldEncryptObjectFormValues() {
101         return valueForBooleanBinding("shouldEncryptObjectFormValues");
102     }
103     /**
104      * Cover method to return the binding: <b>objectsForFormValues</b>
105      * This is an array of objects to be encoded as form values.
106      * @return returns bound array of objects to be encoded
107      */
108     public NSArray objectsForFormValues() {
109         return(NSArray)valueForBinding("objectsForFormValues");
110     }
111     /**
112      * Cover method to return the binding: <b>objectsForFormValue</b>
113      * This is an enterprise object to be encoded as form values.
114      * @return returns bound enterprise object to be encoded
115      */
116     public EOEnterpriseObject objectForFormValue() {
117         return(EOEnterpriseObject)valueForBinding("objectForFormValue");
118     }
119 
120     /**
121      * Returns all of the objects to be encoded
122      * in the form values. Collects those bound
123      * to both 'objectsForFormValues' and
124      * 'objectForFormValue' into a single array.
125      * @return complete collection of objects to
126      *     be encoded in form values.
127      */
128     public NSArray allObjectsForFormValues() {
129         NSMutableArray objects = null;
130         if(hasBinding("objectsForFormValues") || hasBinding("objectForFormValue")) {
131             objects = new NSMutableArray();
132             if(objectsForFormValues() != null)
133                 objects.addObjectsFromArray(objectsForFormValues());
134             if(objectForFormValue() != null)
135                 objects.addObject(objectForFormValue());
136         }
137         return objects != null ? objects : NSArray.EmptyArray;
138     }
139 
140     /**
141      * Retrives a given binding and if it is not null
142      * then returns <code>toString</code> called on the
143      * bound object.
144      * @param binding to be resolved
145      * @return resolved binding in string format
146      */
147     // MOVEME: Should move to ERXStatelessComponent and have this component subclass that
148     // FIXME: Should be renamed stringValueForBinding
149     public String stringForBinding(String binding) {
150         Object v=valueForBinding(binding);
151         return v!=null ? v.toString() : null;
152     }
153 
154     /**
155      * Generates an href for the given direct action based
156      * on all of the bindings. Currently it generates an
157      * absolute url starting with the key: ADAPTOR_PREFIX_MARKER.
158      * Before this href can be really useful it needs to
159      * be cleaned up.
160      * @return href containing all of the specification from
161      *    the bindings.
162      */
163     // FIXME: Lots of stuff to be fixed here.
164     public String href() {
165         String directActionName = null;
166         NSDictionary encryptedBindingDict   = null;
167         NSDictionary unencryptedBindingDict = null;
168         NSArray formValuesObjects = null;
169 
170         // Compose the direct action name from the bindings
171         // Typically, something like "DirectActionClass/actionMethod".
172         // Keep consistency with directActionName semantics as it is defined in directActionHref static method
173         if(this.hasBinding("actionClass")) {
174             StringBuffer daBuffer = new StringBuffer();
175             daBuffer.append(this.valueForBinding("actionClass"));
176             daBuffer.append('/');
177             daBuffer.append(this.valueForBinding("directActionName"));
178             directActionName = daBuffer.toString();
179         } else {
180             directActionName = (String)this.valueForBinding("directActionName");
181         }
182 
183         if((directActionName == null) || (directActionName.length() == 0))
184             throw new IllegalArgumentException("ERXDirectActionHyperlink: directActionName must be specified.");
185 
186         // Get the binding dictionaries
187         // FIXME: Rename binding to encryptedBindingDictionary
188         if(hasBinding("bindingDictionary"))
189             encryptedBindingDict = (NSDictionary)valueForBinding("bindingDictionary");
190 
191         if(hasBinding("unencryptedBindingDictionary"))
192             unencryptedBindingDict = (NSDictionary)valueForBinding("unencryptedBindingDictionary");
193 
194         // Get the objects to encode
195         if(allObjectsForFormValues().count() > 0)
196             formValuesObjects = allObjectsForFormValues();
197 
198         // Compose and return the final url
199         return directActionHyperlink(this.context(),
200                 this.shouldEncryptObjectFormValues(), formValuesObjects, entityNameSeparator(),
201     encryptedBindingDict, unencryptedBindingDict,
202                 this.application().name(), directActionName,
203                 this.relative(), null);
204     }
205   
206     // Class methods -------------------------------------------------
207 
208     /** Holds the application host url */
209     // MOVEME: This stuff might be better served if it was off of ERXApplication
210     private static String _applicationHostUrl;
211     /**
212      * This returns the value stored in the system properties:
213      * <b>ERApplicationHostURL</b> if this isn't set then a
214      * runtime exception is thrown. This property should be of
215      * the form: http://mymachine.com
216      * @return the application host url that should be used when
217      *    complete urls are generated.
218      */
219     // MOVEME: This stuff might be better served if it was off of ERXApplication
220     public static String applicationHostUrl() {
221         if(_applicationHostUrl ==null) {
222             // FIXME: Should be: er.extensions.ERXApplicationHostURL
223             _applicationHostUrl = System.getProperty("ERApplicationHostURL");
224             if(_applicationHostUrl==null || _applicationHostUrl.length()==0)
225                 throw new RuntimeException("The ERApplicationHostURL default was empty -- please set it for the machine running the target application: it should look like http://mymachine.com");
226         }
227         return _applicationHostUrl;
228     }
229 
230     public static String directActionHyperlink(WOContext context,
231                 boolean encryptEos, NSArray eos, String entityNameSeparator,
232                 NSDictionary encryptedDict, NSDictionary unencryptedDict,
233                 String appName, String daName,
234                 boolean relative, String suffix) {
235         StringBuffer result = new StringBuffer(ADAPTOR_PREFIX_MARKER);
236         result.append(".woa/wa/");
237         result.append(daName);
238         result.append('?');
239 
240         if(encryptedDict != null) {
241             NSArray allKeys = encryptedDict.allKeys();
242             for(Enumeration e = allKeys.objectEnumerator(); e.hasMoreElements();) {
243                 String key =(String)e.nextElement();
244                 String value = encryptedDict.objectForKey(key).toString();
245                 ERXStringUtilities.appendSeparatorIfLastNot('&', '?', result);
246                 result.append(key);
247                 result.append("=");
248                 result.append(ERXCrypto.blowfishEncode(value));
249             }
250         }
251 
252         if(unencryptedDict != null) {
253             NSArray allKeys = unencryptedDict.allKeys();
254             for(Enumeration e = allKeys.objectEnumerator(); e.hasMoreElements();) {
255                 String key =(String)e.nextElement();
256                 String value = unencryptedDict.objectForKey(key).toString();
257                 ERXStringUtilities.appendSeparatorIfLastNot('&', '?', result);
258                 result.append(key);
259                 result.append("=");
260                 result.append(value);
261             }
262         }
263 
264         if((eos != null) &&(eos.count() > 0)) {
265             ERXStringUtilities.appendSeparatorIfLastNot('&', '?', result);
266             result.append(ERXEOEncodingUtilities.encodeEnterpriseObjectsPrimaryKeyForUrl(eos, entityNameSeparator, encryptEos));
267         }
268 
269         if(suffix != null)
270             result.append(SUFFIX_MARKER);
271 
272         return completeURLFromString(result.toString(), context, appName, relative, suffix);
273     }
274   
275     /**
276      * This method is useful for completing urls that are being generated
277      * in components that are going to be e-mailed to users. This method
278      * has the ability to substitute different application names which
279      * can be helpful if one application is generating the component, but
280      * the action of the url points to a different application on the
281      * same host.
282      * @param s href string to be completed
283      * @param c current context
284      * @param applicationName to be substituted if ADAPTOR_PREFIX_MARKER
285      *    is present
286      * @param relative flag to indicate if the generated url should be
287      *    relative or absolute in which case the applicationHostUrl
288      *     will be used
289      * @param suffix string to be substitued if the SUFFIX_MARKER string
290      *    is present
291      * @return complete url after substitutions have been made
292      */
293     // MOVEME: ERXWOUtilities
294     public static String completeURLFromString(String s,
295                                                WOContext c,
296                                                String applicationName,
297                                                boolean relative,
298                                                String suffix) {
299         if(s!=null && s.indexOf(ADAPTOR_PREFIX_MARKER)!=-1) {
300             if(applicationName==null || applicationName.length()==0)
301                 throw new RuntimeException("completeURLFromString: found ADAPTOR_PREFIX_MARKER and no application name to replace it - original text:"+s);
302             NSArray a=NSArray.componentsSeparatedByString(s, ADAPTOR_PREFIX_MARKER);
303             // BIG ASSUMPTION : the target application must have the same suffix as this application
304             String postFix=c.request().adaptorPrefix()+"/"+applicationName;
305             s= a.componentsJoinedByString(relative ? postFix : applicationHostUrl()+postFix);
306         }
307         if(s!=null && s.indexOf(SUFFIX_MARKER)!=-1) {
308             NSArray a=NSArray.componentsSeparatedByString(s, SUFFIX_MARKER);
309             // BIG ASSUMPTION : the target application must have the same suffix as this application
310             String postFix=suffix!=null ? suffix : "";
311             s= a.componentsJoinedByString(postFix);
312         }
313         return s;
314     }
315 }