001    // Copyright May 20, 2006 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    package org.apache.tapestry.event;
015    
016    import org.apache.hivemind.ApplicationRuntimeException;
017    import org.apache.hivemind.util.Defense;
018    import org.apache.tapestry.IRequestCycle;
019    import org.apache.tapestry.json.JSONArray;
020    
021    import java.text.ParseException;
022    import java.util.Arrays;
023    import java.util.HashMap;
024    import java.util.Map;
025    
026    
027    /**
028     * Represents a client side generated browser event.
029     */
030    public class BrowserEvent
031    {
032        public static final String NAME="beventname";
033        public static final String TYPE="beventtype";
034        public static final String KEYS="beventkeys";
035        public static final String CHAR_CODE="beventcharCode";
036        public static final String PAGE_X="beventpageX";
037        public static final String PAGE_Y="beventpageY";
038        public static final String LAYER_X="beventlayerX";
039        public static final String LAYER_Y="beventlayerY";
040    
041        public static final String TARGET="beventtarget";
042        public static final String TARGET_ATTR_ID="id";
043        public static final String COMPONENT_ID = "bcomponentid";
044    
045        public static final String METHOD_ARGUMENTS="methodArguments";
046    
047        private String _name;
048        private String _type;
049        private String[] _keys;
050        private String _charCode;
051        private String _pageX;
052        private String _pageY;
053        private String _layerX;
054        private String _layerY;
055        private EventTarget _target;
056        private String _componentId;
057        
058        private String _methodArguments;
059        private JSONArray _methodArgumentsArray;
060    
061        /**
062         * Creates a new browser event that will extract its own
063         * parameters.
064         *
065         * @param cycle
066         *          The request cycle to extract parameters from.
067         */
068        public BrowserEvent(IRequestCycle cycle)
069        {
070            Defense.notNull(cycle, "cycle");
071    
072            _name = cycle.getParameter(NAME);
073            _type = cycle.getParameter(TYPE);
074            _keys = cycle.getParameters(KEYS);
075            _charCode = cycle.getParameter(CHAR_CODE);
076            _pageX = cycle.getParameter(PAGE_X);
077            _pageY = cycle.getParameter(PAGE_Y);
078            _layerX = cycle.getParameter(LAYER_X);
079            _layerY = cycle.getParameter(LAYER_Y);
080            _componentId = cycle.getParameter(COMPONENT_ID);
081    
082            Map props = new HashMap();
083            _target = new EventTarget(props);
084    
085            String targetId = cycle.getParameter(TARGET + "." + TARGET_ATTR_ID);
086            if (targetId != null)
087            {
088                props.put(TARGET_ATTR_ID, targetId);
089            }
090    
091            _methodArguments = cycle.getParameter(METHOD_ARGUMENTS);
092        }
093    
094        /**
095         * Creates a new browser event with the specified
096         * name/target properties.
097         *
098         * @param name The name of the event, ie "onClick", "onBlur", etc..
099         * @param target The target of the client side event.
100         */
101        public BrowserEvent(String name, EventTarget target)
102        {
103            this(name, null, target);
104        }
105    
106        /**
107         * Creates a new browser event with the specified
108         * name/target properties.
109         *
110         * @param name The name of the event, ie "onClick", "onBlur", etc..
111         * @param componentId Component targeted.
112         * @param target The target of the client side event.
113         */
114        public BrowserEvent(String name, String componentId, EventTarget target)
115        {
116            _name = name;
117            _target = target;
118            _componentId = componentId;
119        }
120    
121        /**
122         * The name of the event that was generated. 
123         *
124         * <p>
125         * Examples would be <code>onClick,onSelect,onLoad,etc...</code>.
126         * </p>
127         * @return The event name.
128         */
129        public String getName()
130        {
131            return _name;
132        }
133    
134        /**
135         * Returns the target of the client side event.
136         *
137         * @return The target representation of the client side object event originally bound for.
138         */
139        public EventTarget getTarget()
140        {
141            return _target;
142        }
143    
144        /**
145         * Only when the event targeted a {@link org.apache.tapestry.IComponent} - will return the originating
146         * components id as returned from {@link org.apache.tapestry.IComponent#getId()}.  <em>Not</em> present
147         * on element events.
148         *
149         * @return The originating component id that generated the event.
150         */
151        public String getComponentId()
152        {
153            return _componentId;
154        }
155        
156        /**
157         * @return the charCode
158         */
159        public String getCharCode()
160        {
161            return _charCode;
162        }
163    
164        /**
165         * @return the keys
166         */
167        public String[] getKeys()
168        {
169            return _keys;
170        }
171    
172        /**
173         * @return the layerX
174         */
175        public String getLayerX()
176        {
177            return _layerX;
178        }
179    
180        /**
181         * @return the layerY
182         */
183        public String getLayerY()
184        {
185            return _layerY;
186        }
187    
188        /**
189         * @return the pageX
190         */
191        public String getPageX()
192        {
193            return _pageX;
194        }
195    
196        /**
197         * @return the pageY
198         */
199        public String getPageY()
200        {
201            return _pageY;
202        }
203    
204        /**
205         * @return the type
206         */
207        public String getType()
208        {
209            return _type;
210        }
211    
212    
213        /**
214         * @return the method arguments of an intercepted method-call, if any. If none
215         *         are available, return an empty JSONArray, never null.
216         *
217         * @throws ApplicationRuntimeException when the JSON-String could not be
218         *         parsed.
219         */
220        public JSONArray getMethodArguments()
221        {
222            if ( _methodArgumentsArray == null)
223            {
224                try
225                {
226                    _methodArgumentsArray = _methodArguments != null
227                                            ? new JSONArray( _methodArguments )
228                                            : new JSONArray();
229                }
230                catch (ParseException ex)
231                {
232                    throw new ApplicationRuntimeException(ex);
233                }
234            }
235            
236            return _methodArgumentsArray;
237        }
238    
239        /**
240         * Utility method to check if the current request contains
241         * a browser event.
242         *
243         * @param cycle
244         *          The associated request.
245         * @return True if the request contains browser event data.
246         */
247        public static boolean hasBrowserEvent(IRequestCycle cycle)
248        {
249            Defense.notNull(cycle, "cycle");
250    
251            return cycle.getParameter(NAME) != null;
252        }
253    
254        public String toString()
255        {
256            return "BrowserEvent[" +
257                   "_name='" + _name + '\'' +
258                   '\n' +
259                   ", _type='" + _type + '\'' +
260                   '\n' +
261                   ", _keys=" + (_keys == null ? null : Arrays.asList(_keys)) +
262                   '\n' +
263                   ", _charCode='" + _charCode + '\'' +
264                   '\n' +
265                   ", _pageX='" + _pageX + '\'' +
266                   '\n' +
267                   ", _pageY='" + _pageY + '\'' +
268                   '\n' +
269                   ", _layerX='" + _layerX + '\'' +
270                   '\n' +
271                   ", _layerY='" + _layerY + '\'' +
272                   '\n' +
273                   ", _target=" + _target +
274                   '\n' +
275                   ", _methodArguments='" + _methodArguments + '\'' +
276                   '\n' +
277                   ", _methodArgumentsArray=" + _methodArgumentsArray +
278                   '\n' +
279                   ']';
280        }
281    
282        public boolean equals(Object o)
283        {
284            if (this == o) return true;
285            if (o == null || getClass() != o.getClass()) return false;
286    
287            BrowserEvent event = (BrowserEvent) o;
288    
289            if (_charCode != null ? !_charCode.equals(event._charCode) : event._charCode != null) return false;
290            if (!Arrays.equals(_keys, event._keys)) return false;
291            if (_layerX != null ? !_layerX.equals(event._layerX) : event._layerX != null) return false;
292            if (_layerY != null ? !_layerY.equals(event._layerY) : event._layerY != null) return false;
293            if (_methodArguments != null ? !_methodArguments.equals(event._methodArguments) : event._methodArguments != null) return false;
294            if (_methodArgumentsArray != null ? !_methodArgumentsArray.equals(event._methodArgumentsArray) : event._methodArgumentsArray != null) return false;
295            if (_name != null ? !_name.equals(event._name) : event._name != null) return false;
296            if (_pageX != null ? !_pageX.equals(event._pageX) : event._pageX != null) return false;
297            if (_pageY != null ? !_pageY.equals(event._pageY) : event._pageY != null) return false;
298            if (_target != null ? !_target.equals(event._target) : event._target != null) return false;
299            if (_type != null ? !_type.equals(event._type) : event._type != null) return false;
300    
301            return true;
302        }
303    
304        public int hashCode()
305        {
306            int result;
307            result = (_name != null ? _name.hashCode() : 0);
308            result = 31 * result + (_type != null ? _type.hashCode() : 0);
309            result = 31 * result + (_keys != null ? Arrays.hashCode(_keys) : 0);
310            result = 31 * result + (_charCode != null ? _charCode.hashCode() : 0);
311            result = 31 * result + (_pageX != null ? _pageX.hashCode() : 0);
312            result = 31 * result + (_pageY != null ? _pageY.hashCode() : 0);
313            result = 31 * result + (_layerX != null ? _layerX.hashCode() : 0);
314            result = 31 * result + (_layerY != null ? _layerY.hashCode() : 0);
315            result = 31 * result + (_target != null ? _target.hashCode() : 0);
316            result = 31 * result + (_methodArguments != null ? _methodArguments.hashCode() : 0);
317            result = 31 * result + (_methodArgumentsArray != null ? _methodArgumentsArray.hashCode() : 0);
318            return result;
319        }
320    }