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        public static final String COMPONENT_ID_PATH = "bcomponentidpath";
045    
046        public static final String METHOD_ARGUMENTS = "methodArguments";
047    
048        private String _name;
049        private String _type;
050        private String[] _keys;
051        private String _charCode;
052        private String _pageX;
053        private String _pageY;
054        private String _layerX;
055        private String _layerY;
056        private EventTarget _target;
057        private String _componentId;
058        private String _componentIdPath;
059    
060        private String _methodArguments;
061        private JSONArray _methodArgumentsArray;
062    
063        /**
064         * Creates a new browser event that will extract its own
065         * parameters.
066         *
067         * @param cycle
068         *          The request cycle to extract parameters from.
069         */
070        public BrowserEvent(IRequestCycle cycle)
071        {
072            Defense.notNull(cycle, "cycle");
073    
074            _name = cycle.getParameter(NAME);
075            _type = cycle.getParameter(TYPE);
076            _keys = cycle.getParameters(KEYS);
077            _charCode = cycle.getParameter(CHAR_CODE);
078            _pageX = cycle.getParameter(PAGE_X);
079            _pageY = cycle.getParameter(PAGE_Y);
080            _layerX = cycle.getParameter(LAYER_X);
081            _layerY = cycle.getParameter(LAYER_Y);
082            _componentId = cycle.getParameter(COMPONENT_ID);
083            _componentIdPath = cycle.getParameter(COMPONENT_ID_PATH);
084    
085            Map props = new HashMap();
086            _target = new EventTarget(props);
087    
088            String targetId = cycle.getParameter(TARGET + "." + TARGET_ATTR_ID);
089            if (targetId != null)
090            {
091                props.put(TARGET_ATTR_ID, targetId);
092            }
093    
094            _methodArguments = cycle.getParameter(METHOD_ARGUMENTS);
095        }
096    
097        /**
098         * Creates a new browser event with the specified
099         * name/target properties.
100         *
101         * @param name The name of the event, ie "onClick", "onBlur", etc..
102         * @param target The target of the client side event.
103         */
104        public BrowserEvent(String name, EventTarget target)
105        {
106            this(name, null, null, target);
107        }
108    
109        /**
110         * Creates a new browser event with the specified
111         * name/target properties.
112         *
113         * <p>Currently used for testing only.</p>
114         *
115         * @param name The name of the event, ie "onClick", "onBlur", etc..
116         * @param componentId Component targeted.
117         * @param componentIdPath The id path of the component.
118         * @param target The target of the client side event.
119         */
120        public BrowserEvent(String name, String componentId, String componentIdPath, EventTarget target)
121        {
122            _name = name;
123            _target = target;
124            _componentId = componentId;
125            _componentIdPath = componentIdPath;
126        }
127    
128        /**
129         * The name of the event that was generated. 
130         *
131         * <p>
132         * Examples would be <code>onClick,onSelect,onLoad,etc...</code>.
133         * </p>
134         * @return The event name.
135         */
136        public String getName()
137        {
138            return _name;
139        }
140    
141        /**
142         * Returns the target of the client side event.
143         *
144         * @return The target representation of the client side object event originally bound for.
145         */
146        public EventTarget getTarget()
147        {
148            return _target;
149        }
150    
151        /**
152         * Only when the event targeted a {@link org.apache.tapestry.IComponent} - will return the originating
153         * components id as returned from {@link org.apache.tapestry.IComponent#getId()}.  <em>Not</em> present
154         * on element events.
155         *
156         * @return The originating component id that generated the event.
157         */
158        public String getComponentId()
159        {
160            return _componentId;
161        }
162    
163        /**
164         * If the event was generated for a {@link org.apache.tapestry.IComponent} - will be the
165         * value returned from {@link org.apache.tapestry.IComponent#getExtendedId()}.
166         *
167         * @return Component path id, or null if not present.
168         */
169        public String getComponentIdPath()
170        {
171            return _componentIdPath;
172        }
173    
174        /**
175         * @return the charCode
176         */
177        public String getCharCode()
178        {
179            return _charCode;
180        }
181    
182        /**
183         * @return the keys
184         */
185        public String[] getKeys()
186        {
187            return _keys;
188        }
189    
190        /**
191         * @return the layerX
192         */
193        public String getLayerX()
194        {
195            return _layerX;
196        }
197    
198        /**
199         * @return the layerY
200         */
201        public String getLayerY()
202        {
203            return _layerY;
204        }
205    
206        /**
207         * @return the pageX
208         */
209        public String getPageX()
210        {
211            return _pageX;
212        }
213    
214        /**
215         * @return the pageY
216         */
217        public String getPageY()
218        {
219            return _pageY;
220        }
221    
222        /**
223         * @return the type
224         */
225        public String getType()
226        {
227            return _type;
228        }
229    
230    
231        /**
232         * @return the method arguments of an intercepted method-call, if any. If none
233         *         are available, return an empty JSONArray, never null.
234         *
235         * @throws ApplicationRuntimeException when the JSON-String could not be
236         *         parsed.
237         */
238        public JSONArray getMethodArguments()
239        {
240            if ( _methodArgumentsArray == null)
241            {
242                try
243                {
244                    _methodArgumentsArray = _methodArguments != null
245                            ? new JSONArray( _methodArguments )
246                            : new JSONArray();
247                }
248                catch (ParseException ex)
249                {
250                    throw new ApplicationRuntimeException(ex);
251                }
252            }
253    
254            return _methodArgumentsArray;
255        }
256    
257        /**
258         * Utility method to check if the current request contains
259         * a browser event.
260         *
261         * @param cycle
262         *          The associated request.
263         * @return True if the request contains browser event data.
264         */
265        public static boolean hasBrowserEvent(IRequestCycle cycle)
266        {
267            Defense.notNull(cycle, "cycle");
268    
269            return cycle.getParameter(NAME) != null;
270        }
271    
272        public String toString()
273        {
274            return "BrowserEvent[" +
275                   "_name='" + _name + '\'' +
276                   '\n' +
277                   ", _type='" + _type + '\'' +
278                   '\n' +
279                   ", _keys=" + (_keys == null ? null : Arrays.asList(_keys)) +
280                   '\n' +
281                   ", _charCode='" + _charCode + '\'' +
282                   '\n' +
283                   ", _pageX='" + _pageX + '\'' +
284                   '\n' +
285                   ", _pageY='" + _pageY + '\'' +
286                   '\n' +
287                   ", _layerX='" + _layerX + '\'' +
288                   '\n' +
289                   ", _layerY='" + _layerY + '\'' +
290                   '\n' +
291                   ", _target=" + _target +
292                   '\n' +
293                   ", _componentId='" + _componentId + '\'' +
294                   '\n' +
295                   ", _componentIdPath='" + _componentIdPath + '\'' +
296                   '\n' +
297                   ", _methodArguments='" + _methodArguments + '\'' +
298                   '\n' +
299                   ", _methodArgumentsArray=" + _methodArgumentsArray +
300                   '\n' +
301                   ']';
302        }
303    
304        public boolean equals(Object o)
305        {
306            if (this == o) return true;
307            if (o == null || getClass() != o.getClass()) return false;
308    
309            BrowserEvent event = (BrowserEvent) o;
310    
311            if (_charCode != null ? !_charCode.equals(event._charCode) : event._charCode != null) return false;
312            if (!Arrays.equals(_keys, event._keys)) return false;
313            if (_layerX != null ? !_layerX.equals(event._layerX) : event._layerX != null) return false;
314            if (_layerY != null ? !_layerY.equals(event._layerY) : event._layerY != null) return false;
315            if (_methodArguments != null ? !_methodArguments.equals(event._methodArguments) : event._methodArguments != null) return false;
316            if (_methodArgumentsArray != null ? !_methodArgumentsArray.equals(event._methodArgumentsArray) : event._methodArgumentsArray != null) return false;
317            if (_name != null ? !_name.equals(event._name) : event._name != null) return false;
318            if (_pageX != null ? !_pageX.equals(event._pageX) : event._pageX != null) return false;
319            if (_pageY != null ? !_pageY.equals(event._pageY) : event._pageY != null) return false;
320            if (_target != null ? !_target.equals(event._target) : event._target != null) return false;
321            if (_type != null ? !_type.equals(event._type) : event._type != null) return false;
322    
323            return true;
324        }
325    
326        public int hashCode()
327        {
328            int result;
329            result = (_name != null ? _name.hashCode() : 0);
330            result = 31 * result + (_type != null ? _type.hashCode() : 0);
331            result = 31 * result + (_keys != null ? Arrays.hashCode(_keys) : 0);
332            result = 31 * result + (_charCode != null ? _charCode.hashCode() : 0);
333            result = 31 * result + (_pageX != null ? _pageX.hashCode() : 0);
334            result = 31 * result + (_pageY != null ? _pageY.hashCode() : 0);
335            result = 31 * result + (_layerX != null ? _layerX.hashCode() : 0);
336            result = 31 * result + (_layerY != null ? _layerY.hashCode() : 0);
337            result = 31 * result + (_target != null ? _target.hashCode() : 0);
338            result = 31 * result + (_methodArguments != null ? _methodArguments.hashCode() : 0);
339            result = 31 * result + (_methodArgumentsArray != null ? _methodArgumentsArray.hashCode() : 0);
340            return result;
341        }
342    }