1 /* gnuServantObject.java --
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.CORBA.Poa;
41 import gnu.CORBA.GIOP.ReplyHeader;
42 import gnu.CORBA.IorDelegate;
43 import gnu.CORBA.IorObject;
44 import gnu.CORBA.Interceptor.gnuServerRequestInfo;
45 import gnu.CORBA.typecodes.RecordTypeCode;
47 import gnu.CORBA.IorProvider;
48 import gnu.CORBA.Minor;
49 import gnu.CORBA.ObjectCreator;
50 import gnu.CORBA.Unexpected;
51 import gnu.CORBA.ResponseHandlerImpl;
52 import gnu.CORBA.StreamHolder;
54 import org.omg.CORBA.Any;
55 import org.omg.CORBA.BAD_OPERATION;
56 import org.omg.CORBA.BAD_PARAM;
57 import org.omg.CORBA.CompletionStatus;
58 import org.omg.CORBA.OBJECT_NOT_EXIST;
59 import org.omg.CORBA.OBJ_ADAPTER;
60 import org.omg.CORBA.ORB;
61 import org.omg.CORBA.SystemException;
62 import org.omg.CORBA.TCKind;
63 import org.omg.CORBA.TRANSIENT;
64 import org.omg.CORBA.UserException;
65 import org.omg.CORBA.portable.InputStream;
66 import org.omg.CORBA.portable.InvokeHandler;
67 import org.omg.CORBA.portable.ObjectImpl;
68 import org.omg.CORBA.portable.OutputStream;
69 import org.omg.CORBA.portable.ResponseHandler;
70 import org.omg.PortableInterceptor.ForwardRequest;
71 import org.omg.PortableInterceptor.ServerRequestInterceptorOperations;
72 import org.omg.PortableServer.CurrentOperations;
73 import org.omg.PortableServer.DynamicImplementation;
74 import org.omg.PortableServer.ImplicitActivationPolicyValue;
75 import org.omg.PortableServer.POA;
76 import org.omg.PortableServer.POAManager;
77 import org.omg.PortableServer.POAManagerPackage.State;
78 import org.omg.PortableServer.Servant;
79 import org.omg.PortableServer.ServantLocatorPackage.CookieHolder;
80 import org.omg.PortableServer.ServantRetentionPolicyValue;
81 import org.omg.PortableServer.portable.Delegate;
83 import java.io.IOException;
85 import java.util.Arrays;
88 * Represents a CORBA object, being locally served by the associated servant.
89 * The calls to the object are forwarded to the calls to the servant.
91 * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
93 public class gnuServantObject extends ObjectImpl
94 implements org.omg.CORBA.Object,
100 * The associated servant that must also implement the {@link InvokeHandler}
101 * interface. This value can be temporary null if the object was created using
102 * POA.create_reference or POA.create_reference_with_id, private to force
103 * always to use {@link setServant}.
105 private Servant servant;
108 * The Id of this object.
110 public final byte[] Id;
113 * The poa that takes care about this object.
115 public final gnuPOA poa;
118 * The POA manager, used to control the work of this object.
120 public final POAManager manager;
125 public final ORB_1_4 orb;
128 * The object repository ids, if they were specified separately. Normally, the
129 * ids are requested from the servant.
131 public final String[] repository_ids;
134 * True indicates that the NO_RETAIN policy applies for the servant.
135 * The servant must be discarded after the each call.
140 * Create an object with no connected servant. The servant must be set later.
142 * @param a_repository_ids an array of repository ids, can be null (then ids
143 * will be requested from the servant).
144 * @param an_id the object id.
145 * @param a_poa the POA.
147 public gnuServantObject(String[] a_repository_ids, byte[] an_id,
148 gnuPOA a_poa, ORB_1_4 an_orb
151 repository_ids = a_repository_ids;
153 manager = a_poa.the_POAManager();
157 noRetain = poa.applies(ServantRetentionPolicyValue.NON_RETAIN);
161 * Get the IOR as it would be for this object.
165 return orb.getLocalIor(this);
169 * Create a servant object, associated with the passed servant.
171 * @param a_servant a servant, serving this object.
172 * @param an_id an Object Id for this object.
174 * @throws BAD_PARAM if the passed servant is not an {@link InvokeHandler}.
176 public gnuServantObject(Servant a_servant, byte[] an_id, ORB_1_4 an_orb,
181 setServant(a_servant);
185 manager = poa.the_POAManager();
191 repository_ids = null;
194 noRetain = poa != null && poa.applies(ServantRetentionPolicyValue.NON_RETAIN);
198 * Set a servant, if it has not been previously set.
200 * @param a_servant a servant to set, can be null to indicate the necessity
201 * for the subsequent activation.
203 * @throws BAD_PARAM if the passed servant is not an {@link InvokeHandler} or
204 * {@link DynamicImplementation} and also not null.
206 public void setServant(Servant a_servant)
208 if (a_servant != null &&
209 !(a_servant instanceof InvokeHandler) &&
210 !(a_servant instanceof DynamicImplementation)
213 throw new BAD_PARAM("Must be either InvokeHandler or " +
214 "DynamicImplementation, but is " + a_servant
221 * Returns the associated servant.
223 public Servant getServant()
229 * Return the associated invocation handler.
231 public InvokeHandler getHandler(String operation, CookieHolder cookie,
232 boolean forwarding_allowed
233 ) throws gnuForwardRequest
235 if (servant != null && !noRetain)
237 return servantToHandler(servant);
241 // Use servant locator to locate the servant.
242 if (poa.servant_locator != null)
247 poa.servant_locator.preinvoke(Id, poa, operation, cookie);
248 return servantToHandler(servant);
250 catch (org.omg.PortableServer.ForwardRequest forw_ex)
252 if (forwarding_allowed)
254 throw new gnuForwardRequest(forw_ex.forward_reference);
259 ForwardedServant.create(forw_ex.forward_reference);
260 return servantToHandler(servant);
265 // Use servant activator to locate the servant.
266 if (poa.applies(ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION) &&
267 poa.applies(ServantRetentionPolicyValue.RETAIN)
272 poa.activate_object_with_id(Id, servant, forwarding_allowed);
273 servant = poa.id_to_servant(Id);
274 return servantToHandler(servant);
276 catch (gnuForwardRequest forwarded)
283 new BAD_OPERATION("Unable to activate", Minor.Activation,
284 CompletionStatus.COMPLETED_NO
290 else if (poa.default_servant != null)
292 servant = poa.default_servant;
293 return servantToHandler(servant);
296 // No servant and no servant manager - throw exception.
299 throw new BAD_OPERATION("Unable to activate", Minor.Activation,
300 CompletionStatus.COMPLETED_NO
307 * Convert the servant to invocation handler.
309 public InvokeHandler servantToHandler(Servant a_servant)
311 if (a_servant instanceof InvokeHandler)
313 return (InvokeHandler) a_servant;
315 else if (a_servant instanceof DynamicImplementation)
317 return new DynamicImpHandler((DynamicImplementation) a_servant);
321 throw new BAD_OPERATION(a_servant +
322 " must be either InvokeHandler or " + "POA DynamicImplementation"
328 * Create a servant object, associated with the passed servant. Requests the
329 * object id from the servant. Depending on the policies of the servants POA,
330 * the calls are eithe not synchronized or synchronized on POA or ORB.
332 * @param a_servant a servant, serving this object.
333 * @param an_id an Object Id for this object.
335 public gnuServantObject(Servant a_servant, gnuPOA a_poa)
337 this(a_servant, a_servant._object_id(), (ORB_1_4) a_servant._orb(), a_poa);
341 * Delegates call to servant, passing the poa and Id.
343 public String[] _ids()
345 if (repository_ids == null)
347 return getServant()._all_interfaces(poa, Id);
351 return repository_ids;
356 * Gets a string representation.
358 public String toString()
360 StringBuffer b = new StringBuffer("Servant object (");
361 for (int i = 0; i < Id.length; i++)
363 b.append(Integer.toHexString(Id [ i ] & 0xFF));
371 * Always returns true.
373 public boolean _is_local()
379 * Check if this object could be named by the given repository id.
381 * @param idl_id the repository id to check.
383 * @return true if it is one of the possible repository ids of this object.
385 public boolean _is_a(String idl_id)
387 String[] maybe = _ids();
388 for (int i = 0; i < maybe.length; i++)
390 if (maybe [ i ].equals(idl_id))
399 * Get an ORB, associated with the servant of this object.
405 return getServant()._orb();
409 * Handle the invocation (delegates to servant).
411 * @throws TRANSIENT minor 0x535503e9 if the POA is in discarding mode.
412 * @throws OBJ_ADAPTER minor 0x535503ea if the POA is inactivated.
413 * @throws OBJECT_NOT_EXISTS minor 0x535503ec if this object is inactivated.
415 * @specnote see {@link POAManagerOperations} for specnotes about the minor
418 public OutputStream _invoke(String method, InputStream input,
419 ResponseHandler r_handler
420 ) throws SystemException
422 boolean intercept = false;
423 ServerRequestInterceptorOperations interceptor = null;
424 gnuServerRequestInfo info = null;
425 ResponseHandlerImpl i_handler = null;
429 if (orb.iServer != null &&
430 r_handler instanceof ResponseHandlerImpl
433 interceptor = orb.iServer;
435 i_handler = (ResponseHandlerImpl) r_handler;
438 new gnuServerRequestInfo(this, i_handler.request_header,
439 i_handler.reply_header
443 interceptor.receive_request_service_contexts(info);
448 CookieHolder cookie = null;
449 AOM.Obj self = poa.aom.get(Id);
451 if (poa.servant_locator != null)
453 // If the servant locator is in use, it is always responsible
454 // for providing the servant.
455 self.servant = servant = null;
456 cookie = new CookieHolder();
458 else if (self != null && self.isDeactiveted())
461 ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION
463 poa.servant_activator != null
466 // Reset the servant, forcing the subsequent activation.
471 throw new OBJECT_NOT_EXIST("Object deactivated",
472 0x535503ec, CompletionStatus.COMPLETED_NO
477 InvokeHandler handler = getHandler(method, cookie, true);
483 d = servant._get_delegate();
484 orb.currents.put(Thread.currentThread(), this);
488 // In some cases exception is thrown if the delegate is not set.
490 if (d instanceof ServantDelegateImpl)
492 // If the delegate is already set, check maybe we can
493 // reuse the existing instance.
494 if (((ServantDelegateImpl) d).object != this)
496 servant._set_delegate(new ServantDelegateImpl(servant, poa, Id));
501 servant._set_delegate(new ServantDelegateImpl(servant, poa, Id));
506 switch (manager.get_state().value())
515 interceptor.receive_request(info);
518 rt = handler._invoke(method, input, r_handler);
522 // Handler is casted into i_handler.
523 if (i_handler.isExceptionReply())
525 info.m_reply_header.reply_status =
526 ReplyHeader.USER_EXCEPTION;
528 // Make Any, holding the user exception.
529 Any a = orb.create_any();
530 OutputStream buf = i_handler.getBuffer();
531 InputStream in = buf.create_input_stream();
532 String uex_idl = "unknown";
535 in.mark(Integer.MAX_VALUE);
536 uex_idl = in.read_string();
539 catch (IOException e)
541 throw new Unexpected(e);
546 UserException exception =
547 ObjectCreator.readUserException(uex_idl,
551 ObjectCreator.insertWithHelper(a,
557 // Failed due any reason, insert without
559 a.insert_Streamable(new StreamHolder(
560 buf.create_input_stream()
565 new RecordTypeCode(TCKind.tk_except);
567 r.setName(ObjectCreator.getDefaultName(
573 info.m_usr_exception = a;
574 interceptor.send_exception(info);
578 info.m_reply_header.reply_status =
579 ReplyHeader.NO_EXCEPTION;
580 interceptor.send_reply(info);
584 catch (SystemException sys_ex)
588 info.m_reply_header.reply_status =
589 ReplyHeader.SYSTEM_EXCEPTION;
590 info.m_sys_exception = sys_ex;
591 interceptor.send_exception(info);
598 case State._HOLDING :
600 // The holding mode is implemented
601 // relying on the holding capabilites of the network
603 // TODO FIXME in more recent CORBA applications, the
605 // ORB can free the connection and wait for a server side
606 // notification about the completed request. Implement
608 // as soon as JDK specification would allow bidirectional
613 // Wait till the state will be switched into some other
615 while (manager.get_state().value() == State._HOLDING)
625 catch (InterruptedException ex)
630 // Handle another mode.
631 return _invoke(method, input, r_handler);
633 case State._DISCARDING :
634 throw new TRANSIENT("Discarding mode", 0x535503e9,
635 CompletionStatus.COMPLETED_NO
638 case State._INACTIVE :
639 throw new OBJ_ADAPTER("POA deactivated", 0x535503ea,
640 CompletionStatus.COMPLETED_NO
644 throw new InternalError(); // No more states.
649 if (poa.servant_locator != null)
651 poa.servant_locator.postinvoke(Id, poa, method,
652 cookie.value, servant
659 orb.currents.remove(Thread.currentThread());
664 catch (ForwardRequest fex)
666 // May be thrown by interceptor.
672 info.m_reply_header.reply_status =
673 ReplyHeader.LOCATION_FORWARD;
674 info.m_forward_reference = fex.forward;
677 interceptor.send_other(info);
680 catch (ForwardRequest fex2)
682 info.m_forward_reference = fex2.forward;
683 fex.forward = info.m_forward_reference;
687 throw new gnuForwardRequest(fex.forward);
689 catch (gnuForwardRequest fex)
691 // May be thrown during activation.
697 info.m_reply_header.reply_status =
698 ReplyHeader.LOCATION_FORWARD;
699 info.m_forward_reference = fex.forward_reference;
702 interceptor.send_other(info);
705 catch (ForwardRequest fex2)
707 info.m_forward_reference = fex2.forward;
708 fex.forward_reference = (ObjectImpl) fex2.forward;
717 * Compare with another object for equality, comparing the object keys.
719 public boolean equals(java.lang.Object other)
721 if (other instanceof gnuServantObject)
723 gnuServantObject o = (gnuServantObject) other;
725 return Arrays.equals(o.Id, Id);
734 * Get the hash code, based on the object key.
736 public int hashCode()
740 for (int i = 0; i < Id.length; i++)
743 if (s > Integer.MAX_VALUE)
745 s = s % Integer.MAX_VALUE;
750 return (int) (s % Integer.MAX_VALUE);
756 public byte[] get_object_id()
770 * Returns without action.
772 public void _release()
777 * Returns without action.
779 public void _releaseReply(InputStream stream)
784 * Checks if this object is equivalent to another instance. These objects are
785 * assumed equal if they are connected to the same orb and poa under the same
786 * Id, regardless of they delegates.
788 * @param another instance to check.
791 public boolean _is_equivalent(org.omg.CORBA.Object other)
793 if (other instanceof gnuServantObject)
795 gnuServantObject g = (gnuServantObject) other;
796 return orb == g.orb && poa == g.poa && Arrays.equals(Id, g.Id);
798 else if (other instanceof IorObject)
800 IorObject ir = ((IorObject) other);
803 IorDelegate ird = (IorDelegate) ir._get_delegate();
804 byte[] ior_id = poa.idFormIor(ird.getIor().key);
805 if (ior_id != null && Arrays.equals(ior_id, Id))
816 // Non - typical delegate or very specific subclass of
817 // IOR_constructed_object.
818 return super._is_equivalent(other);
821 return super._is_equivalent(other);