1 /*************************************************************************
3 * $RCSfile: Interceptor.java,v $
7 * last change: $Author: rt $ $Date: 2005-01-31 16:38:44 $
9 * The Contents of this file are made available subject to the terms of
12 * Copyright (c) 2003 by Sun Microsystems, Inc.
13 * All rights reserved.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. Neither the name of Sun Microsystems, Inc. nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
34 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *************************************************************************/
41 // __________ Imports __________
43 import com
.sun
.star
.uno
.UnoRuntime
;
47 import java
.util
.Vector
;
49 // __________ Implementation __________
52 * This class can be used to intercept dispatched URL's
53 * on any frame used in this demo application.
54 * It intercept all URL's wich try to create a new empty frame.
55 * (e.g. "private:factory/swriter")
56 * Nobody can guarantee that this interception will be realy used -
57 * because another interceptor (registered at a later time then this one!)
58 * will be called before this one.
59 * Implementation is executed inside a new thread to prevent application
60 * against possible deadlocks. This deadlocks can occure if
61 * synchronous/asynchronous ... normal ones and oneway calls are mixed.
62 * Notifications of listener will be oneway mostly - her reactions can
63 * be synchronous then. => deadlocks are possible
65 * @author Andreas Schlüns
66 * @created 06.03.2002 09:38
68 public class Interceptor
implements com
.sun
.star
.frame
.XFrameActionListener
,
69 com
.sun
.star
.frame
.XDispatchProviderInterceptor
,
70 com
.sun
.star
.frame
.XDispatchProvider
,
71 com
.sun
.star
.frame
.XDispatch
,
72 com
.sun
.star
.frame
.XInterceptorInfo
,
76 // ____________________
80 * All these URL's are intercepted by this implementation.
82 private static final String
[] INTERCEPTED_URLS
= { "private:factory/*" ,
87 // ____________________
90 * @member m_xMaster use this interceptor if he doesn't handle queried dispatch request
91 * @member m_xSlave we can forward all unhandled requests to this slave interceptor
92 * @member m_xFrame intercepted frame
93 * @member m_bDead there exist more then one way to finish an object of this class - we must know it sometimes
95 private com
.sun
.star
.frame
.XDispatchProvider m_xMaster
;
96 private com
.sun
.star
.frame
.XDispatchProvider m_xSlave
;
97 private com
.sun
.star
.frame
.XFrame m_xFrame
;
98 private boolean m_bIsActionListener
;
99 private boolean m_bIsRegistered
;
100 private boolean m_bDead
;
102 // ____________________
106 * Initialize the new interceptor. Given frame reference can be used to
107 * register this interceptor on it automaticly later.
109 * @seealso startListening()
112 * this interceptor will register himself at this frame to intercept dispatched URLs
114 Interceptor(/*IN*/ com
.sun
.star
.frame
.XFrame xFrame
)
119 m_bIsRegistered
= false ;
120 m_bIsActionListener
= false ;
124 //_____________________
127 * start working as frame action listener realy.
128 * We will be frame action listener here. In case
129 * we get a frame action which indicates, that we should
130 * update our interception. Because such using of an interecptor
131 * isn't guaranteed - in case a newer one was registered ...
133 public void startListening()
135 com
.sun
.star
.frame
.XFrame xFrame
= null;
142 if (m_bIsActionListener
==true)
146 m_xFrame
.addFrameActionListener(this);
149 m_bIsActionListener
=true;
153 //_____________________
156 * In case we got an oneway listener callback - we had to use the office
157 * asynchronous then. This method is the callback from the started thread
158 * (started inside the original oneway method). We found all parameters of
159 * the original request packed inside a vector. Here we unpack it and
160 * call the right internal helper method, which implements the right
163 * @seealso frameAction()
164 * @seealso dispatch()
167 * indicates, which was the original request (identifies the
168 * original called method)
171 * the vector with all packed parameters of the original request
173 public void execOneway(/*IN*/ int nRequest
,/*IN*/ Vector lParams
)
181 // was it frameAction()?
182 if (nRequest
==OnewayExecutor
.REQUEST_FRAMEACTION
)
184 com
.sun
.star
.frame
.FrameActionEvent
[] lOutAction
= new com
.sun
.star
.frame
.FrameActionEvent
[1];
185 Vector
[] lInParams
= new Vector
[1];
186 lInParams
[0] = lParams
;
188 OnewayExecutor
.codeFrameAction( OnewayExecutor
.DECODE_PARAMS
,
191 impl_frameAction(lOutAction
[0]);
194 // was it dispatch()?
195 if (nRequest
==OnewayExecutor
.REQUEST_DISPATCH
)
197 com
.sun
.star
.util
.URL
[] lOutURL
= new com
.sun
.star
.util
.URL
[1];
198 com
.sun
.star
.beans
.PropertyValue
[][] lOutProps
= new com
.sun
.star
.beans
.PropertyValue
[1][];
199 Vector
[] lInParams
= new Vector
[1];
200 lInParams
[0] = lParams
;
202 OnewayExecutor
.codeDispatch( OnewayExecutor
.DECODE_PARAMS
,
206 impl_dispatch(lOutURL
[0],lOutProps
[0]);
210 // ____________________
213 * call back for frame action events
214 * We use it to update our interception. Because if a new component was loaded into
215 * the frame or another interceptor was registered, we should refresh our connection
216 * to the frame. Otherwhise we can't guarantee full functionality here.
218 * Note: Don't react synchronous in an asynchronous listener callback. So use a thread
219 * here to update anything.
221 * @seealso impl_frameAction()
224 * describes the action
226 public /*ONEWAY*/ void frameAction(/*IN*/ com
.sun
.star
.frame
.FrameActionEvent aEvent
)
234 boolean bHandle
= false;
235 switch(aEvent
.Action
.getValue())
237 case com
.sun
.star
.frame
.FrameAction
.COMPONENT_ATTACHED_value
: bHandle
=true; break;
238 case com
.sun
.star
.frame
.FrameAction
.COMPONENT_DETACHING_value
: bHandle
=true; break;
239 case com
.sun
.star
.frame
.FrameAction
.COMPONENT_REATTACHED_value
: bHandle
=true; break;
240 // Don't react for CONTEXT_CHANGED here. Ok it indicates, that may another interceptor
241 // was registered at the frame ... but if we register ourself there - we get a context
242 // changed too :-( Best way to produce a never ending recursion ...
243 // May be that somewhere find a safe mechanism to detect own produced frame action events
245 case com
.sun
.star
.frame
.FrameAction
.CONTEXT_CHANGED_value
:
246 System
.out
.println("Time to update interception ... but may it will start a recursion. So I let it :-(");
251 // ignore some events
255 // pack the event and start thread - which call us back later
256 Vector
[] lOutParams
= new Vector
[1];
257 com
.sun
.star
.frame
.FrameActionEvent
[] lInAction
= new com
.sun
.star
.frame
.FrameActionEvent
[1];
258 lInAction
[0] = aEvent
;
260 OnewayExecutor
.codeFrameAction( OnewayExecutor
.ENCODE_PARAMS
,
263 OnewayExecutor aExecutor
= new OnewayExecutor( (IOnewayLink
)this ,
264 OnewayExecutor
.REQUEST_FRAMEACTION
,
269 // ____________________
272 * Indicates using of us as an interceptor.
273 * Now we have to react for the requests, we are registered.
274 * That means: load new empty documents - triggered by the new menu of the office.
275 * Because it's oneway - use thread for loading!
277 * @seealso impl_dispatch()
280 * describes the document, which should be loaded
283 * optional parameters for loading
285 public /*ONEWAY*/ void dispatch(/*IN*/ com
.sun
.star
.util
.URL aURL
,/*IN*/ com
.sun
.star
.beans
.PropertyValue
[] lArguments
)
293 Vector
[] lOutParams
= new Vector
[1];
294 com
.sun
.star
.util
.URL
[] lInURL
= new com
.sun
.star
.util
.URL
[1];
295 com
.sun
.star
.beans
.PropertyValue
[][] lInArguments
= new com
.sun
.star
.beans
.PropertyValue
[1][];
297 lInArguments
[0] = lArguments
;
299 OnewayExecutor
.codeDispatch( OnewayExecutor
.ENCODE_PARAMS
,
303 OnewayExecutor aExecutor
= new OnewayExecutor( (IOnewayLink
)this ,
304 OnewayExecutor
.REQUEST_DISPATCH
,
310 //_____________________
313 * Internal call back for frame action events, triggered by the used
314 * OnewayExecutor thread we started in frameAction().
315 * We use it to update our interception on the internal saved frame.
318 * describes the action
320 public void impl_frameAction(/*IN*/ com
.sun
.star
.frame
.FrameActionEvent aEvent
)
328 // deregistration will be done everytime ...
329 // But may it's not neccessary to establish a new registration!
330 // Don't look for ignoring actions - it was done already inside original frameAction() call!
331 boolean bRegister
= false;
333 // analyze the event and decide which reaction is usefull
334 switch(aEvent
.Action
.getValue())
336 case com
.sun
.star
.frame
.FrameAction
.COMPONENT_ATTACHED_value
: bRegister
= true ; break;
337 case com
.sun
.star
.frame
.FrameAction
.COMPONENT_REATTACHED_value
: bRegister
= true ; break;
338 case com
.sun
.star
.frame
.FrameAction
.COMPONENT_DETACHING_value
: bRegister
= false; break;
341 com
.sun
.star
.frame
.XFrame xFrame
= null ;
342 boolean bIsRegistered
= false;
345 bIsRegistered
= m_bIsRegistered
;
346 m_bIsRegistered
= false;
350 com
.sun
.star
.frame
.XDispatchProviderInterception xRegistration
= (com
.sun
.star
.frame
.XDispatchProviderInterception
)UnoRuntime
.queryInterface(
351 com
.sun
.star
.frame
.XDispatchProviderInterception
.class,
354 if(xRegistration
==null)
358 xRegistration
.releaseDispatchProviderInterceptor(this);
363 xRegistration
.registerDispatchProviderInterceptor(this);
366 m_bIsRegistered
= true;
370 // ____________________
373 * Implementation of interface XDispatchProviderInterceptor
374 * These functions are used to build a list of interceptor objects
375 * connected in both ways.
376 * Searching for a right interceptor is made by forwarding any request
377 * from toppest master to lowest slave of this hierarchy.
378 * If an interceptor whish to handle the request he can break that
379 * and return himself as a dispatcher.
381 public com
.sun
.star
.frame
.XDispatchProvider
getSlaveDispatchProvider()
389 // ____________________
391 public void setSlaveDispatchProvider(com
.sun
.star
.frame
.XDispatchProvider xSlave
)
399 // ____________________
401 public com
.sun
.star
.frame
.XDispatchProvider
getMasterDispatchProvider()
409 // ____________________
411 public void setMasterDispatchProvider(com
.sun
.star
.frame
.XDispatchProvider xMaster
)
419 // ____________________
422 * Implementation of interface XDispatchProvider
423 * These functions are called from our master if he willn't handle the outstanding request.
424 * Given parameter should be checked if they are right for us. If it's true, the returned
425 * dispatcher should be this implementation himself; otherwise call should be forwarded
429 * describes the request, which should be handled
432 * specifies the target frame for this request
434 * @param nSearchFlags
435 * optional search flags, if sTarget isn't a special one
437 * @return [XDispatch]
438 * a dispatch object, which can handle the given URL
441 public com
.sun
.star
.frame
.XDispatch
queryDispatch(/*IN*/ com
.sun
.star
.util
.URL aURL
,/*IN*/ String sTarget
,/*IN*/ int nSearchFlags
)
449 // intercept loading empty documents into new created frames
451 (sTarget
.compareTo ("_blank" ) == 0 ) &&
452 (aURL
.Complete
.startsWith("private:factory") == true)
455 System
.out
.println("intercept private:factory");
459 // intercept opening the SaveAs dialog
460 if (aURL
.Complete
.startsWith(".uno:SaveAs") == true)
462 System
.out
.println("intercept SaveAs by returning null!");
466 // intercept "File->Exit" inside the menu
468 (aURL
.Complete
.startsWith("slot:5300") == true) ||
469 (aURL
.Complete
.startsWith(".uno:Quit") == true)
472 System
.out
.println("intercept File->Exit");
479 return m_xSlave
.queryDispatch(aURL
, sTarget
, nSearchFlags
);
485 // ____________________
487 public com
.sun
.star
.frame
.XDispatch
[] queryDispatches(/*IN*/ com
.sun
.star
.frame
.DispatchDescriptor
[] lDescriptor
)
494 // Resolve any request seperatly by using own "dispatch()" method.
495 // Note: Don't pack return list if "null" objects occure!
496 int nCount
= lDescriptor
.length
;
497 com
.sun
.star
.frame
.XDispatch
[] lDispatcher
= new com
.sun
.star
.frame
.XDispatch
[nCount
];
498 for(int i
=0; i
<nCount
; ++i
)
500 lDispatcher
[i
] = queryDispatch(lDescriptor
[i
].FeatureURL
,
501 lDescriptor
[i
].FrameName
,
502 lDescriptor
[i
].SearchFlags
);
507 // ____________________
510 * This method is called if this interceptor "wins the request".
511 * We intercepted creation of new frames and loading of empty documents.
515 * describes the document
518 * optional arguments for loading
520 public void impl_dispatch(/*IN*/ com
.sun
.star
.util
.URL aURL
,/*IN*/ com
.sun
.star
.beans
.PropertyValue
[] lArguments
)
529 (aURL
.Complete
.startsWith("slot:5300") == true) ||
530 (aURL
.Complete
.startsWith(".uno:Quit") == true)
536 if (aURL
.Complete
.startsWith("private:factory") == true)
538 // Create view frame for showing loaded documents on demand.
539 // The visible state is neccessary for JNI functionality to get the HWND and plug office
540 // inside a java window hierarchy!
541 DocumentView aNewView
= new DocumentView();
542 aNewView
.setVisible(true);
543 aNewView
.createFrame();
544 aNewView
.load(aURL
.Complete
,lArguments
);
548 // ____________________
551 * Notification of status listener isn't guaranteed (instead of listener on XNotifyingDispatch interface).
552 * So this interceptor doesn't support that realy ...
554 public /*ONEWAY*/ void addStatusListener(/*IN*/ com
.sun
.star
.frame
.XStatusListener xListener
,/*IN*/ com
.sun
.star
.util
.URL aURL
)
556 /* if (aURL.Complete.startsWith(".uno:SaveAs")==true)
558 com.sun.star.frame.FeatureStateEvent aEvent = new com.sun.star.frame.FeatureStateEvent(
567 System.out.println("interceptor disable SavAs by listener notify");
568 xListener.statusChanged(aEvent);
573 // ____________________
575 public /*ONEWAY*/ void removeStatusListener(/*IN*/ com
.sun
.star
.frame
.XStatusListener xListener
,/*IN*/ com
.sun
.star
.util
.URL aURL
)
579 // ____________________
582 * Implements (optional!) optimization for interceptor mechanism.
583 * Any interceptor which provides this special interface is called automaticly
584 * at registration time on this method. Returned URL's will be used to
585 * call this interceptor directly without calling his masters before, IF(!)
586 * following rules will be true:
587 * (1) every master supports this optional interface too
588 * (2) nobody of these masters whish to intercept same URL then this one
589 * This interceptor whish to intercept creation of new documents.
591 public String
[] getInterceptedURLs()
593 return INTERCEPTED_URLS
;
596 // ____________________
599 * This class listen on the intercepted frame to free all used ressources on closing.
600 * We forget the reference to the frame only here. Deregistration
601 * isn't neccessary here - because this frame dies and wish to forgoten.
604 * must be our internal saved frame, on which we listen for frame action events
606 public /*ONEAY*/ void disposing(/*IN*/ com
.sun
.star
.lang
.EventObject aSource
)
612 if (m_xFrame
!=null && UnoRuntime
.areSame(aSource
.Source
,m_xFrame
))
614 m_bIsActionListener
= false;
621 // ____________________
624 * If this java application shutdown - we must cancel all current existing
625 * listener connections. Otherwhise the office will run into some
626 * DisposedExceptions if it tries to use these forgotten listener references.
627 * And of course it can die doing that.
628 * We are registered at a central object to be informed if the VM will exit.
631 public void shutdown()
633 com
.sun
.star
.frame
.XFrame xFrame
= null ;
634 boolean bIsRegistered
= false;
635 boolean bIsActionListener
= false;
638 // don't react a second time here!
643 bIsRegistered
= m_bIsRegistered
;
644 m_bIsRegistered
= false;
646 bIsActionListener
= m_bIsActionListener
;
647 m_bIsActionListener
= false;
653 // it's a good idead to cancel listening for frame action events
654 // before(!) we deregister us as an interceptor.
655 // Because registration and deregistratio nof interceptor objects
656 // will force sending of frame action events ...!
657 if (bIsActionListener
)
658 xFrame
.removeFrameActionListener(this);
662 com
.sun
.star
.frame
.XDispatchProviderInterception xRegistration
= (com
.sun
.star
.frame
.XDispatchProviderInterception
)UnoRuntime
.queryInterface(
663 com
.sun
.star
.frame
.XDispatchProviderInterception
.class,
666 if(xRegistration
!=null)
667 xRegistration
.releaseDispatchProviderInterceptor(this);