| /* |
| * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0, which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| * version 2 with the GNU Classpath Exception, which is available at |
| * https://www.gnu.org/software/classpath/license.html. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| */ |
| |
| package com.sun.enterprise.iiop.security; |
| |
| /** |
| * This class is a server side request interceptor for CSIV2. |
| * It is used to send and receive the service context in a |
| * a service context element in the service context list in |
| * an IIOP header. |
| * |
| * @author: Nithya Subramanian |
| */ |
| |
| import com.sun.enterprise.common.iiop.security.SecurityContext; |
| import org.omg.CORBA.*; |
| import org.omg.PortableInterceptor.*; |
| import org.omg.IOP.*; |
| |
| import java.security.cert.CertPath; |
| import java.security.cert.Certificate; |
| import java.security.cert.CertificateFactory; |
| import java.security.cert.X509Certificate; |
| |
| /* Import classes generated from CSIV2 idl files */ |
| import com.sun.corba.ee.org.omg.CSI.*; |
| import com.sun.corba.ee.spi.legacy.connection.Connection; |
| import com.sun.corba.ee.spi.legacy.interceptor.RequestInfoExt; |
| import com.sun.enterprise.common.iiop.security.AnonCredential; |
| import com.sun.enterprise.common.iiop.security.GSSUPName; |
| |
| import javax.security.auth.*; |
| import javax.security.auth.x500.X500Principal; |
| |
| import com.sun.enterprise.security.auth.login.common.PasswordCredential; |
| import com.sun.enterprise.security.auth.login.common.X509CertificateCredential; |
| |
| import com.sun.enterprise.util.LocalStringManagerImpl; |
| |
| import com.sun.logging.LogDomains; |
| |
| import java.io.ByteArrayInputStream; |
| import java.net.Socket; |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| import java.util.List; |
| import java.util.logging.*; |
| import org.glassfish.enterprise.iiop.api.GlassFishORBHelper; |
| |
| /* |
| * Security server request interceptor |
| */ |
| |
| public class SecServerRequestInterceptor extends org.omg.CORBA.LocalObject implements ServerRequestInterceptor { |
| |
| private static java.util.logging.Logger _logger = null; |
| static { |
| _logger = LogDomains.getLogger(SecServerRequestInterceptor.class, LogDomains.SECURITY_LOGGER); |
| } |
| private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(SecServerRequestInterceptor.class); |
| private InheritableThreadLocal counterForCalls = new InheritableThreadLocal(); |
| |
| /** |
| * Hard code the value of 15 for SecurityAttributeService until it is defined in IOP.idl. sc.context_id = |
| * SecurityAttributeService.value; |
| */ |
| protected static final int SECURITY_ATTRIBUTE_SERVICE_ID = 15; |
| // the major and minor codes for a invalid mechanism |
| private static final int INVALID_MECHANISM_MAJOR = 2; |
| private static final int INVALID_MECHANISM_MINOR = 1; |
| |
| public static final String SERVER_CONNECTION_CONTEXT = "ServerConnContext"; |
| |
| /* used when inserting into service context field */ |
| private static final boolean NO_REPLACE = false; |
| |
| /* name of interceptor used for logging purposes (name + "::") */ |
| private String prname; |
| private String name; |
| private Codec codec; |
| // private ORB orb; |
| private SecurityContextUtil secContextUtil = null; |
| private GlassFishORBHelper orbHelper; |
| private SecurityMechanismSelector smSelector = null; |
| |
| // Not required |
| // SecurityService secsvc = null; // Security Service |
| public SecServerRequestInterceptor(String name, Codec codec) { |
| this.name = name; |
| this.codec = codec; |
| this.prname = name + "::"; |
| secContextUtil = Lookups.getSecurityContextUtil(); |
| orbHelper = Lookups.getGlassFishORBHelper(); |
| smSelector = Lookups.getSecurityMechanismSelector(); |
| } |
| |
| public String name() { |
| return name; |
| } |
| |
| /** |
| * Create a ContextError message. This is currently designed to work only for the GSSUP mechanism. |
| */ |
| |
| /* Create a ContexError Message */ |
| private SASContextBody createContextError(int status) { |
| /** |
| * CSIV2 SPEC NOTE: |
| * |
| * Check that CSIV2 spec does not require an error token to be sent for the GSSUP mechanism. |
| */ |
| |
| return createContextError(1, status); |
| } |
| |
| /* |
| * create a context error with the specified major and minor status |
| */ |
| private SASContextBody createContextError(int major, int minor) { |
| |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Creating ContextError message: major code = " + major + "minor code= " + minor); |
| } |
| byte error_token[] = {}; |
| ContextError ce = new ContextError(0, /* stateless client id */ |
| major, // major |
| minor, // minor |
| error_token); |
| SASContextBody sasctxtbody = new SASContextBody(); |
| sasctxtbody.error_msg(ce); |
| return sasctxtbody; |
| } |
| |
| /** |
| * Create a CompleteEstablishContext Message. This currently works only for the GSSUP mechanism. |
| */ |
| private SASContextBody createCompleteEstablishContext(int status) { |
| /** |
| * CSIV2 SPEC NOTE: |
| * |
| * Check CSIV2 spec to make sure that there is no final_context_token for GSSUP mechanism |
| */ |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Creating CompleteEstablishContext message"); |
| } |
| byte[] final_context_token = {}; |
| CompleteEstablishContext cec = new CompleteEstablishContext(0, // stateless client id |
| false, // for stateless |
| final_context_token); |
| SASContextBody sasctxtbody = new SASContextBody(); |
| sasctxtbody.complete_msg(cec); |
| return sasctxtbody; |
| } |
| |
| /** |
| * CDR encode a SAS Context body and then construct a service context element. |
| */ |
| private ServiceContext createSvcContext(SASContextBody sasctxtbody, ORB orb) { |
| |
| ServiceContext sc = null; |
| |
| Any a = orb.create_any(); |
| SASContextBodyHelper.insert(a, sasctxtbody); |
| |
| byte[] cdr_encoded_saselm = {}; |
| try { |
| cdr_encoded_saselm = codec.encode_value(a); |
| } catch (Exception e) { |
| _logger.log(Level.SEVERE, "iiop.encode_exception", e); |
| } |
| sc = new ServiceContext(); |
| sc.context_id = SECURITY_ATTRIBUTE_SERVICE_ID; |
| sc.context_data = cdr_encoded_saselm; |
| return sc; |
| |
| } |
| |
| /** |
| * Create an identity from an Identity Token and stores it as a public credential in the JAAS subject in a security |
| * context. |
| * |
| * Set the identcls field in the security context. |
| * |
| */ |
| private void createIdCred(SecurityContext sc, IdentityToken idtok) throws Exception { |
| |
| byte[] derenc; // used to hold DER encodings |
| Any any; // Any object returned from codec.decode_value() |
| |
| switch (idtok.discriminator()) { |
| |
| case ITTAbsent.value: |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Identity token type is Absent"); |
| } |
| sc.identcls = null; |
| break; |
| |
| case ITTAnonymous.value: |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Identity token type is Anonymous"); |
| _logger.log(Level.FINE, "Adding AnonyCredential to subject's PublicCredentials"); |
| } |
| sc.subject.getPublicCredentials().add(new AnonCredential()); |
| sc.identcls = AnonCredential.class; |
| break; |
| |
| case ITTDistinguishedName.value: |
| /* Construct a X500Principal */ |
| |
| derenc = idtok.dn(); |
| /* Issue 5766: Decode CDR encoding if necessary */ |
| if (isCDR(derenc)) { |
| any = codec.decode_value(derenc, X501DistinguishedNameHelper.type()); |
| |
| /* Extract CDR encoding */ |
| derenc = X501DistinguishedNameHelper.extract(any); |
| } |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Create an X500Principal object from identity token"); |
| } |
| X500Principal xname = new X500Principal(derenc); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Identity to be asserted is " + xname.toString()); |
| _logger.log(Level.FINE, "Adding X500Principal to subject's PublicCredentials"); |
| } |
| sc.subject.getPublicCredentials().add(xname); |
| sc.identcls = X500Principal.class; |
| break; |
| |
| case ITTX509CertChain.value: |
| /* Construct a X509CertificateChain */ |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Identity token type is a X509 Certificate Chain"); |
| } |
| derenc = idtok.certificate_chain(); |
| /* Issue 5766: Decode CDR encoding if necessary */ |
| if (isCDR(derenc)) { |
| /* Decode CDR encoding */ |
| any = codec.decode_value(derenc, X509CertificateChainHelper.type()); |
| |
| /* Extract DER encoding */ |
| derenc = X509CertificateChainHelper.extract(any); |
| } |
| |
| List<? extends Certificate> certificates = CertificateFactory.getInstance("X.509") |
| .generateCertPath(new ByteArrayInputStream(derenc)) |
| .getCertificates(); |
| |
| X509Certificate[] certchain = new X509Certificate[certificates.size()]; |
| |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Contents of X509 Certificate chain:"); |
| } |
| for (int i = 0; i < certchain.length; i++) { |
| certchain[i] = (X509Certificate) certificates.get(i); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, " " + certchain[i].getSubjectX500Principal().getName()); |
| } |
| } |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Creating a X509CertificateCredential object from certchain"); |
| } |
| /** |
| * The alias field in the X509CertificateCredential is currently ignored by the RI. So it is set to "dummy". |
| * |
| */ |
| X509CertificateCredential cred = new X509CertificateCredential(certchain, certchain[0].getSubjectX500Principal().getName(), "default"); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Adding X509CertificateCredential to subject's PublicCredentials"); |
| } |
| sc.subject.getPublicCredentials().add(cred); |
| sc.identcls = X509CertificateCredential.class; |
| break; |
| |
| case ITTPrincipalName.value: |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Identity token type is GSS Exported Name"); |
| } |
| byte[] expname = idtok.principal_name(); |
| /* Issue 5766: Decode CDR encoding if necessary */ |
| if (isCDR(expname)) { |
| /* Decode CDR encoding */ |
| any = codec.decode_value(expname, GSS_NT_ExportedNameHelper.type()); |
| |
| expname = GSS_NT_ExportedNameHelper.extract(any); |
| } |
| if (!GSSUtils.verifyMechOID(GSSUtils.GSSUP_MECH_OID, expname)) { |
| throw new SecurityException( |
| localStrings.getLocalString("secserverreqinterceptor.err_unknown_idassert_type", "Unknown identity assertion type.")); |
| } |
| |
| GSSUPName gssname = new GSSUPName(expname); |
| |
| sc.subject.getPublicCredentials().add(gssname); |
| sc.identcls = GSSUPName.class; |
| _logger.log(Level.FINE, "Adding GSSUPName credential to subject"); |
| break; |
| |
| default: |
| _logger.log(Level.SEVERE, "iiop.unknown_identity"); |
| throw new SecurityException(localStrings.getLocalString("secserverreqinterceptor.err_unknown_idassert_type", "Unknown identity assertion type.")); |
| } |
| } |
| |
| /** |
| * Check if given byte is CDR encapsulated. |
| * |
| * @param bytes an input array of byte |
| * @return boolean indicates whether input is CDR |
| */ |
| private boolean isCDR(byte[] bytes) { |
| return (bytes != null && bytes.length > 0 && (bytes[0] == 0x0 || bytes[0] == 0x1)); |
| } |
| |
| /** |
| * Create an auth credential from authentication token and store it as a private credential in the JAAS subject in the |
| * security context. |
| * |
| * Set the authcls field in the security context. |
| * |
| * This method currently only works for PasswordCredential tokens. |
| */ |
| private void createAuthCred(SecurityContext sc, byte[] authtok, ORB orb) throws Exception { |
| _logger.log(Level.FINE, "Constructing a PasswordCredential from client authentication token"); |
| /* create a GSSUPToken from the authentication token */ |
| GSSUPToken tok = GSSUPToken.getServerSideInstance(orb, codec, authtok); |
| |
| final PasswordCredential pwdcred = tok.getPwdcred(); |
| final SecurityContext fsc = sc; |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Password credential = " + pwdcred.toString()); |
| _logger.log(Level.FINE, "Adding PasswordCredential to subject's PrivateCredentials"); |
| } |
| java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() { |
| public java.lang.Object run() { |
| fsc.subject.getPrivateCredentials().add(pwdcred); |
| return null; |
| } |
| }); |
| sc = fsc; |
| sc.authcls = PasswordCredential.class; |
| } |
| |
| private void handle_null_service_context(ServerRequestInfo ri, ORB orb) { |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "No SAS context element found in service context list for operation: " + ri.operation()); |
| } |
| ServiceContext sc = null; |
| int secStatus = secContextUtil.setSecurityContext(null, ri.object_id(), ri.operation(), getServerSocket()); |
| |
| if (secStatus == SecurityContextUtil.STATUS_FAILED) { |
| SASContextBody sasctxbody = createContextError(INVALID_MECHANISM_MAJOR, INVALID_MECHANISM_MINOR); |
| sc = createSvcContext(sasctxbody, orb); |
| ri.add_reply_service_context(sc, NO_REPLACE); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "SecServerRequestInterceptor.receive_request: NO_PERMISSION"); |
| } |
| throw new NO_PERMISSION(); |
| } |
| } |
| |
| public void receive_request(ServerRequestInfo ri) throws ForwardRequest { |
| SecurityContext seccontext = null; // SecurityContext to be sent |
| ServiceContext sc = null; // service context |
| int status = 0; |
| boolean raise_no_perm = false; |
| |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "++++ Entered " + prname + "receive_request"); |
| } |
| |
| // secsvc = Csiv2Manager.getSecurityService(); |
| ORB orb = orbHelper.getORB(); |
| |
| try { |
| sc = ri.get_request_service_context(SECURITY_ATTRIBUTE_SERVICE_ID); |
| if (sc == null) { |
| handle_null_service_context(ri, orb); |
| return; |
| } |
| } catch (org.omg.CORBA.BAD_PARAM e) { |
| handle_null_service_context(ri, orb); |
| return; |
| } |
| |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Received a non null SAS context element"); |
| } |
| /* Decode the service context field */ |
| Any SasAny; |
| try { |
| SasAny = codec.decode_value(sc.context_data, SASContextBodyHelper.type()); |
| } catch (Exception e) { |
| _logger.log(Level.SEVERE, "iiop.decode_exception", e); |
| throw new SecurityException(localStrings.getLocalString("secserverreqinterceptor.err_cdr_decode", "CDR Decoding error for SAS context element.")); |
| } |
| |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Successfully decoded CDR encoded SAS context element."); |
| } |
| SASContextBody sasctxbody = SASContextBodyHelper.extract(SasAny); |
| |
| short sasdiscr = sasctxbody.discriminator(); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "SAS context element is a/an " + SvcContextUtils.getMsgname(sasdiscr) + " message"); |
| } |
| /* Check message type received */ |
| |
| /** |
| * CSIV2 SPEC NOTE: |
| * |
| * Section 4.3 "TSS State Machine" , table 4-4 "TSS State Table" shows that a MessageInContext can be received. In this |
| * case the table is somewhat unclear. But in this case a ContextError with the status code "No Context" ( specified in |
| * section 4.5 "ContextError Values and Exceptions" must be sent back. A NO_PERMISSION exception must also be raised. |
| * |
| * ISSUE: should setSecurityContext(null) be called ? |
| */ |
| |
| if (sasdiscr == MTMessageInContext.value) { |
| sasctxbody = createContextError(SvcContextUtils.MessageInContextMinor); |
| sc = createSvcContext(sasctxbody, orb); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Adding ContextError message to service context list"); |
| _logger.log(Level.FINE, "SecurityContext set to null"); |
| } |
| ri.add_reply_service_context(sc, NO_REPLACE); |
| // no need to set the security context |
| // secsvc.setSecurityContext(null, ri.object_id(), ri.operation()); |
| |
| throw new NO_PERMISSION(); |
| } |
| |
| /** |
| * CSIV2 SPEC NOTE: |
| * |
| * CSIV2 spec does not specify the actions for any message other than a MessageInContext and EstablishContext message.So |
| * for such messages, this implementation simply drops the message on the floor. No other message is sent back. Neither |
| * is an exception raised. |
| * |
| * ISSUE: Should there be some other action ? |
| */ |
| |
| if (sasdiscr != MTEstablishContext.value) { |
| _logger.log(Level.SEVERE, "iiop.not_establishcontext_msg"); |
| throw new SecurityException( |
| localStrings.getLocalString("secserverreqinterceptor.err_not_ec_msg", "Received message not an EstablishContext message.")); |
| } |
| |
| EstablishContext ec = sasctxbody.establish_msg(); |
| |
| seccontext = new SecurityContext(); |
| seccontext.subject = new Subject(); |
| |
| try { |
| if (ec.client_authentication_token.length != 0) { |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Message contains Client Authentication Token"); |
| } |
| createAuthCred(seccontext, ec.client_authentication_token, orb); |
| } |
| } catch (Exception e) { |
| _logger.log(Level.SEVERE, "iiop.authentication_exception", e); |
| throw new SecurityException( |
| localStrings.getLocalString("secsercverreqinterceptor.err_cred_create", "Error while creating a JAAS subject credential.")); |
| |
| } |
| |
| try { |
| if (ec.identity_token != null) { |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Message contains an Identity Token"); |
| } |
| createIdCred(seccontext, ec.identity_token); |
| } |
| } catch (SecurityException secex) { |
| _logger.log(Level.SEVERE, "iiop.security_exception", secex); |
| sasctxbody = createContextError(INVALID_MECHANISM_MAJOR, INVALID_MECHANISM_MINOR); |
| sc = createSvcContext(sasctxbody, orb); |
| ri.add_reply_service_context(sc, NO_REPLACE); |
| throw new NO_PERMISSION(); |
| } catch (Exception e) { |
| _logger.log(Level.SEVERE, "iiop.generic_exception", e); |
| throw new SecurityException( |
| localStrings.getLocalString("secsercverreqinterceptor.err_cred_create", "Error while creating a JAAS subject credential.")); |
| |
| } |
| |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Invoking setSecurityContext() to set security context"); |
| } |
| status = secContextUtil.setSecurityContext(seccontext, ri.object_id(), ri.operation(), getServerSocket()); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "setSecurityContext() returned status code " + status); |
| } |
| /** |
| * CSIV2 SPEC NOTE: |
| * |
| * If ec.client_context_id is non zero, then this is a stateful request. As specified in section 4.2.1, a stateless |
| * server must attempt to validate the security tokens in the security context field. If validation succeeds then |
| * CompleteEstablishContext message is sent back. If validation fails, a ContextError must be sent back. |
| */ |
| if (status == SecurityContextUtil.STATUS_FAILED) { |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "setSecurityContext() returned STATUS_FAILED"); |
| } |
| sasctxbody = createContextError(status); |
| sc = createSvcContext(sasctxbody, orb); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Adding ContextError message to service context list"); |
| } |
| ri.add_reply_service_context(sc, NO_REPLACE); |
| throw new NO_PERMISSION(); |
| } |
| |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "setSecurityContext() returned SUCCESS"); |
| } |
| sasctxbody = createCompleteEstablishContext(status); |
| sc = createSvcContext(sasctxbody, orb); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Adding CompleteEstablisContext message to service context list"); |
| } |
| ri.add_reply_service_context(sc, NO_REPLACE); |
| } |
| |
| /* |
| * This method is keeping a track of when to unset the security context Currently with the re-use of the threads made by |
| * the orb the security context does not get unset. This method determines when to unset the security context |
| */ |
| public void receive_request_service_contexts(ServerRequestInfo ri) throws ForwardRequest { |
| // cannot set this in receive_request due to the PI flow control |
| // semantics. e.g. if receive_req for some other PI throws an |
| // exception - the send_exception will be called that will muck |
| // the stack up |
| Counter cntr = (Counter) counterForCalls.get(); |
| if (cntr == null) { |
| cntr = new Counter(); |
| counterForCalls.set(cntr); |
| } |
| if (cntr.count == 0) { |
| // Not required |
| // SecurityService secsvc = Csiv2Manager.getSecurityService(); |
| SecurityContextUtil.unsetSecurityContext(isLocal()); |
| } |
| cntr.increment(); |
| |
| Socket s = null; |
| Connection c = null; |
| if (ri instanceof RequestInfoExt) { |
| c = ((RequestInfoExt) ri).connection(); |
| } |
| ServerConnectionContext scc = null; |
| if (c != null) { |
| s = c.getSocket(); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "RECEIVED request on connection: " + c); |
| _logger.log(Level.FINE, "Socket =" + s); |
| } |
| scc = new ServerConnectionContext(s); |
| } else { |
| scc = new ServerConnectionContext(); |
| } |
| setServerConnectionContext(scc); |
| } |
| |
| public void send_reply(ServerRequestInfo ri) { |
| unsetSecurityContext(); |
| } |
| |
| public void send_exception(ServerRequestInfo ri) throws ForwardRequest { |
| unsetSecurityContext(); |
| } |
| |
| public void send_other(ServerRequestInfo ri) throws ForwardRequest { |
| unsetSecurityContext(); |
| } |
| |
| public void destroy() { |
| } |
| |
| private void unsetSecurityContext() { |
| try { |
| Counter cntr = (Counter) counterForCalls.get(); |
| if (cntr == null) { // sanity check |
| cntr = new Counter(1); |
| } |
| cntr.decrement(); |
| if (cntr.count == 0) { |
| SecurityContextUtil.unsetSecurityContext(isLocal()); |
| |
| } |
| } finally { |
| ConnectionExecutionContext.removeClientThreadID(); |
| } |
| } |
| |
| private boolean isLocal() { |
| boolean local = true; |
| ServerConnectionContext scc = getServerConnectionContext(); |
| if (scc != null && scc.getSocket() != null) { |
| local = false; |
| } |
| Long clientID = ConnectionExecutionContext.readClientThreadID(); |
| if (clientID != null && clientID == Thread.currentThread().getId()) { |
| local = true; |
| } |
| return local; |
| } |
| |
| private Socket getServerSocket() { |
| ServerConnectionContext scc = getServerConnectionContext(); |
| if (scc != null) { |
| return scc.getSocket(); |
| } |
| return null; |
| } |
| |
| private ServerConnectionContext getServerConnectionContext() { |
| Hashtable h = ConnectionExecutionContext.getContext(); |
| ServerConnectionContext scc = (ServerConnectionContext) h.get(SERVER_CONNECTION_CONTEXT); |
| return scc; |
| } |
| |
| public static void setServerConnectionContext(ServerConnectionContext scc) { |
| Hashtable h = ConnectionExecutionContext.getContext(); |
| h.put(SERVER_CONNECTION_CONTEXT, scc); |
| } |
| } |
| |
| class Counter { |
| |
| public int count = 0; |
| |
| public Counter(int count) { |
| this.count = count; |
| } |
| |
| public Counter() { |
| count = 0; |
| } |
| |
| public void setCount(int counter) { |
| count = counter; |
| } |
| |
| public void increment() { |
| count++; |
| } |
| |
| public void decrement() { |
| count--; |
| } |
| |
| public String display() { |
| return " Counter = " + count; |
| } |
| } |