package org.jacorb.orb.dsi; /* * JacORB - a free Java ORB * * Copyright (C) 1997-2014 Gerald Brose / The JacORB Team. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ import java.util.Iterator; import java.util.List; import org.jacorb.config.Configuration; import org.jacorb.orb.CDRInputStream; import org.jacorb.orb.CDROutputStream; import org.jacorb.orb.giop.GIOPConnection; import org.jacorb.orb.giop.Messages; import org.jacorb.orb.giop.ReplyOutputStream; import org.jacorb.orb.giop.RequestInputStream; import org.jacorb.orb.portableInterceptor.ServerInterceptorIterator; import org.jacorb.orb.portableInterceptor.ServerRequestInfoImpl; import org.jacorb.poa.util.ByteArrayKey; import org.jacorb.poa.util.POAUtil; import org.jacorb.util.Time; import org.omg.CORBA.BAD_INV_ORDER; import org.omg.CORBA.BAD_PARAM; import org.omg.CORBA.NamedValue; import org.omg.GIOP.ReplyStatusType_1_2; import org.omg.IOP.INVOCATION_POLICIES; import org.omg.IOP.ServiceContext; import org.omg.IOP.TAG_GROUP; import org.omg.MIOP.UIPMC_ProfileBody; import org.omg.MIOP.UIPMC_ProfileBodyHelper; import org.omg.Messaging.PolicyValue; import org.omg.Messaging.PolicyValueSeqHelper; import org.omg.Messaging.REPLY_END_TIME_POLICY_TYPE; import org.omg.Messaging.REQUEST_END_TIME_POLICY_TYPE; import org.omg.Messaging.REQUEST_START_TIME_POLICY_TYPE; import org.omg.PortableGroup.TagGroupTaggedComponent; import org.omg.PortableGroup.TagGroupTaggedComponentHelper; import org.omg.PortableInterceptor.ForwardRequest; import org.omg.TimeBase.UtcT; import org.slf4j.Logger; /** * @author Gerald Brose, FU Berlin */ public class ServerRequest extends org.omg.CORBA.ServerRequest implements org.omg.CORBA.portable.ResponseHandler { private final RequestInputStream inputStream; private ReplyOutputStream out; private final GIOPConnection connection; private UtcT requestStartTime = null, requestEndTime = null, replyEndTime = null; /** * <code>scopes</code> caches the scoped poa names. */ private List<String> scopes; /** config property */ private final boolean cachePoaNames; private int replyStatus = ReplyStatusType_1_2._NO_EXCEPTION; private byte[] oid; private byte[] object_key; /** * <code>rest_of_name</code> is target poa's name in relation to parent. */ private String[] rest_of_name = null; /* is this request stream or DSI-based ? */ private boolean isStreamBased; private org.omg.CORBA.SystemException sys_ex; private org.omg.PortableServer.ForwardRequest location_forward; private org.omg.CORBA.Any exception; private org.omg.CORBA.Any result; private org.jacorb.orb.NVList argList; private final org.jacorb.orb.ORB orb; private ServerRequestInfoImpl info = null; private final Logger logger; //MIOP private ByteArrayKey byteArrayKey; private TagGroupTaggedComponent tagGroup = null; public ServerRequest( org.jacorb.orb.ORB orb, RequestInputStream inStream, GIOPConnection _connection ) { super(); this.orb = orb; Configuration config = orb.getConfiguration(); this.logger = config.getLogger("org.jacorb.org.giop"); this.cachePoaNames = config.getAttributeAsBoolean("jacorb.cachePoaNames", false); this.inputStream = inStream; connection = _connection; calcTimingPolicies(); // MIOP if(connection.getTransport() instanceof org.jacorb.orb.miop.ServerMIOPConnection) { CDRInputStream uipmcInStream = new CDRInputStream (orb, inStream.req_hdr.target.profile ().profile_data); uipmcInStream.openEncapsulatedArray (); UIPMC_ProfileBody upb = UIPMC_ProfileBodyHelper.read (uipmcInStream); uipmcInStream.close(); for (int i=0; i<upb.components.length; i++) { if (upb.components[i].tag == TAG_GROUP.value) { CDRInputStream groupInStream = new CDRInputStream (orb, upb.components[i].component_data); groupInStream.openEncapsulatedArray(); tagGroup = TagGroupTaggedComponentHelper.read (groupInStream); groupInStream.close (); break; } } } else { object_key = orb.mapObjectKey(org.jacorb.orb.ParsedIOR.extractObjectKey(inStream.req_hdr.target, orb)); oid = org.jacorb.poa.util.POAUtil.extractOID( object_key ); } } //MIOP //seter for object Id public void setObjectKey(byte[] objectKey) { object_key = objectKey; oid = org.jacorb.poa.util.POAUtil.extractOID( object_key ); } public TagGroupTaggedComponent getTagGroup() { return tagGroup; } /* * if this request could not be delivered directly to the correct * POA because the POA's adapter activator could not be called * when the parent POA was in holding state, the parent will queue * the request and later return it to the adapter layer. In order * to be able to find the right POA when trying to deliver again, * we have to remember the target POA's name */ public void setRemainingPOAName(String [] rest_of_name) { this.rest_of_name = rest_of_name; } /** * <code>remainingPOAName</code> retrieves (if any) the target poa's * name in relation to parent. * @return a <code>String[]</code> value */ public String[] remainingPOAName() { return rest_of_name; } @Override public String operation() { return inputStream.req_hdr.operation; } /** * The resulting any must be used to create an input stream from * which the result value can be read. */ public org.omg.CORBA.Any result() { if( isStreamBased ) { org.omg.CORBA.Any any = orb.create_any(); // create the output stream for the result CDROutputStream _out = ((CDROutputStream)any.create_output_stream()); // get a copy of the content of this reply byte[] result_buf = orb.getBufferManager().getBuffer( out.size() - out.getBodyBegin()); System.arraycopy( out.getBufferCopy(), out.getBodyBegin(), result_buf, 0, result_buf.length ); // ... and insert it _out.setBuffer( result_buf ); // important: set the _out buffer's position to the end of the contents! _out.skip( result_buf.length ); return any; } return result; } public org.omg.CORBA.NVList arguments() { if( isStreamBased ) { throw new BAD_INV_ORDER("This ServerRequest is stream-based!"); } return argList; } public org.omg.CORBA.Any except() { if( isStreamBased ) { throw new BAD_INV_ORDER("This ServerRequest is stream-based!"); } return exception; } public ReplyStatusType_1_2 status() { return ReplyStatusType_1_2.from_int( replyStatus ); } @Override public org.omg.CORBA.Context ctx() { return null; } @Override public void arguments(org.omg.CORBA.NVList list) { argList = (org.jacorb.orb.NVList)list; // unmarshal if( argList != null ) { inputStream.mark(0); for( Iterator<NamedValue> e = argList.iterator(); e.hasNext(); ) { NamedValue namedValue = e.next(); if( namedValue.flags() != org.omg.CORBA.ARG_OUT.value ) { // out parameters are not received try { namedValue.value().read_value( inputStream, namedValue.value().type() ); } catch (Exception e1) { throw new org.omg.CORBA.MARSHAL("Couldn't unmarshal object of type " + namedValue.value().type() + " in ServerRequest."); } } } try { inputStream.reset(); } catch (Exception e1) { throw new org.omg.CORBA.UNKNOWN("Could not reset input stream"); } if (info != null) { //invoke interceptors org.omg.Dynamic.Parameter[] params = new org.omg.Dynamic.Parameter[argList.count()]; for (int i = 0; i < params.length; i++) { try { org.omg.CORBA.NamedValue value = argList.item(i); org.omg.CORBA.ParameterMode mode = null; if (value.flags() == org.omg.CORBA.ARG_IN.value) { mode = org.omg.CORBA.ParameterMode.PARAM_IN; } else if (value.flags() == org.omg.CORBA.ARG_OUT.value) { mode = org.omg.CORBA.ParameterMode.PARAM_OUT; } else if (value.flags() == org.omg.CORBA.ARG_INOUT.value) { mode = org.omg.CORBA.ParameterMode.PARAM_INOUT; } params[i] = new org.omg.Dynamic.Parameter(value.value(), mode); } catch (Exception e) { logger.info("DSI arguments: Caught exception ", e); } } info.setArguments (params); ServerInterceptorIterator intercept_iter = orb.getInterceptorManager().getServerIterator(); try { intercept_iter.iterate(info, ServerInterceptorIterator.RECEIVE_REQUEST); } catch (ForwardRequest e) { setLocationForward(new org.omg.PortableServer.ForwardRequest(e.forward)); } catch(org.omg.CORBA.UserException e) { logger.error("uncaught userexception", e); } catch (org.omg.CORBA.SystemException _sys_ex) { setSystemException(_sys_ex); } info = null; } } } @Override public void set_result(org.omg.CORBA.Any res) { if( isStreamBased ) { throw new BAD_INV_ORDER("This ServerRequest is stream-based!"); } result = res; } @Override public void set_exception(org.omg.CORBA.Any exception) { if( isStreamBased ) { throw new BAD_INV_ORDER("This ServerRequest is stream-based!"); } this.exception = exception; replyStatus = ReplyStatusType_1_2._USER_EXCEPTION; } // BasicAdapter / ServerRequestListener / IMR public void reply() { if( responseExpected() ) { if( logger.isDebugEnabled() ) { logger.debug( "ServerRequest: reply to " + operation() ); } try { if( out == null ) { out = new ReplyOutputStream(orb, requestId(), ReplyStatusType_1_2.from_int(replyStatus), inputStream.getGIOPMinor(), inputStream.isLocateRequest(), logger); } /* * DSI-based servers set results and user exceptions * using anys, so we have to treat this differently */ if( !isStreamBased ) { if( replyStatus == ReplyStatusType_1_2._USER_EXCEPTION ) { exception.write_value( out ); } else if( replyStatus == ReplyStatusType_1_2._NO_EXCEPTION ) { if( result != null ) { result.write_value( out ); } if( argList != null ) { for( Iterator<NamedValue> e = argList.iterator(); e.hasNext(); ) { NamedValue namedValue = e.next(); if( namedValue.flags() != org.omg.CORBA.ARG_IN.value ) { // in parameters are not returned try { namedValue.value().write_value(out); } catch (Exception e1) { throw new org.omg.CORBA.MARSHAL("Couldn't return (in)out arg of type " + namedValue.value().type() + " in ServerRequest."); } } } } } } /* * these two exceptions are set in the same way for * both stream-based and DSI-based servers */ if( replyStatus == ReplyStatusType_1_2._LOCATION_FORWARD ) { out.write_Object( location_forward.forward_reference ); } else if( replyStatus == ReplyStatusType_1_2._SYSTEM_EXCEPTION ) { org.jacorb.orb.SystemExceptionHelper.write( out, sys_ex ); } /* * everything is written to out by now, be it results * or exceptions. */ connection.sendReply( out ); } catch ( Exception ioe ) { logger.info("Error replying to request!", ioe); } finally { out.close(); // nullify output stream to force its recreation on next call out = null; } } } /* ResponseHandler */ @Override public org.omg.CORBA.portable.OutputStream createReply() { isStreamBased = true; if( out != null ) { // The reply was already created. This happens in oneway // operations using SyncScope SYNC_WITH_SERVER, and does // not do any harm. return out; } out = new ReplyOutputStream(orb, requestId(), ReplyStatusType_1_2.NO_EXCEPTION, inputStream.getGIOPMinor(), inputStream.isLocateRequest(), logger ); out.updateMutatorConnection(connection); return out; } @Override public org.omg.CORBA.portable.OutputStream createExceptionReply() { isStreamBased = true; replyStatus = ReplyStatusType_1_2._USER_EXCEPTION; out = new ReplyOutputStream(orb, requestId(), ReplyStatusType_1_2.USER_EXCEPTION, inputStream.getGIOPMinor(), inputStream.isLocateRequest(), logger ); return out; } /** our own: */ public void setSystemException(org.omg.CORBA.SystemException exception) { replyStatus = ReplyStatusType_1_2._SYSTEM_EXCEPTION; /* we need to create a new output stream here because a system exception may have occurred *after* a no_exception request header was written onto the original output stream*/ out = new ReplyOutputStream(orb, requestId(), ReplyStatusType_1_2.SYSTEM_EXCEPTION, inputStream.getGIOPMinor(), inputStream.isLocateRequest(), logger); String msg = exception.getMessage(); if (msg != null) { out.addServiceContext (createExceptionDetailMessage (msg)); } sys_ex = exception; } /** * Creates a ServiceContext for transmitting an exception detail message, * as per section 1.15.2 of the Java Mapping. */ public static ServiceContext createExceptionDetailMessage (String message) { final CDROutputStream out = new CDROutputStream(); try { out.beginEncapsulatedArray(); out.write_wstring(message); return new ServiceContext(org.omg.IOP.ExceptionDetailMessage.value, out.getBufferCopy()); } finally { out.close(); } } public void setLocationForward(org.omg.PortableServer.ForwardRequest request) { replyStatus = ReplyStatusType_1_2._LOCATION_FORWARD; out = new ReplyOutputStream(orb, requestId(), ReplyStatusType_1_2.LOCATION_FORWARD, inputStream.getGIOPMinor(), inputStream.isLocateRequest(), logger ); location_forward = request; } /** * @return the InputStream. This operation sets the * request be stream-based, ie. all attempts to extract * data using DII-based operations will throw exceptions * For internal access to the stream use get_in() * */ public org.jacorb.orb.CDRInputStream getInputStream() { isStreamBased = true; return inputStream; } public ReplyOutputStream getReplyOutputStream() { if (out == null) { createReply(); } isStreamBased = true; return out; } public boolean responseExpected() { return Messages.responseExpected(inputStream.req_hdr.response_flags); } /** * Returns the SyncScope of this request, as expressed in the * header's response_flags. Note that here, on the server side, * this no longer differentiates between SYNC_NONE and SYNC_WITH_TRANSPORT. * The former is returned in both cases. */ public short syncScope() { final short result; switch (inputStream.req_hdr.response_flags) { case 0x00: result = org.omg.Messaging.SYNC_NONE.value; break; case 0x01: result = org.omg.Messaging.SYNC_WITH_SERVER.value; break; case 0x03: result = org.omg.Messaging.SYNC_WITH_TARGET.value; break; default: throw new BAD_PARAM("Illegal SYNC_SCOPE: " + inputStream.req_hdr.response_flags); } return result; } public org.omg.CORBA.SystemException getSystemException() { return sys_ex; } public int requestId() { return inputStream.req_hdr.request_id; } public byte[] objectKey() { return object_key; } /** * <code>getScopes</code> returns the cached list of poa_names. * * @return a <code>List</code> value containing Strings separated by * {@link org.jacorb.poa.POAConstants#OBJECT_KEY_SEPARATOR OBJECT_KEY_SEPARATOR} */ public List<String> getScopes () { if (scopes == null || !cachePoaNames ) { scopes = POAUtil.extractScopedPOANames (POAUtil.extractPOAName (object_key)); } return scopes; } public org.omg.IOP.ServiceContext[] getServiceContext() { return inputStream.req_hdr.service_context; } public byte[] objectId() { return oid; } public synchronized ByteArrayKey objectIdAsByteArrayKey() { if (byteArrayKey == null) { byteArrayKey = new ByteArrayKey(oid); } return byteArrayKey; } public boolean streamBased() { return isStreamBased; } public RequestInputStream get_in() { return inputStream; } /** * If a new output stream has to be created, the request itself isn't fixed * to stream-based. */ public ReplyOutputStream get_out() { if (out == null) { out = new ReplyOutputStream(orb, requestId(), status(), inputStream.getGIOPMinor(), inputStream.isLocateRequest(), logger ); } return out; } public void setServerRequestInfo(ServerRequestInfoImpl info) { this.info = info; } public org.omg.CORBA.Object getForwardReference() { if (location_forward != null) { return location_forward.forward_reference; } return null; } public GIOPConnection getConnection() { return connection; } /** * If this request has a service context with timing policies, * this method decodes them and puts them into the corresponding * instance variables (requestStartTime, requestEndTime, replyEndTime). */ private void calcTimingPolicies() { ServiceContext ctx = inputStream.getServiceContext(INVOCATION_POLICIES.value); if (ctx != null) { final CDRInputStream input = new CDRInputStream (ctx.context_data); try { input.openEncapsulatedArray(); PolicyValue[] policy = PolicyValueSeqHelper.read (input); for (int i=0; i < policy.length; i++) { if (policy[i].ptype == REQUEST_START_TIME_POLICY_TYPE.value) { requestStartTime = Time.fromCDR (policy[i].pvalue); } else if (policy[i].ptype == REQUEST_END_TIME_POLICY_TYPE.value) { requestEndTime = Time.fromCDR (policy[i].pvalue); } else if (policy[i].ptype == REPLY_END_TIME_POLICY_TYPE.value) { replyEndTime = Time.fromCDR (policy[i].pvalue); } } } finally { input.close(); } } } /** * Returns the time after which a reply to this request may no longer * be obtained or returned to the client; null if no such time has * been specified. */ public UtcT getReplyEndTime() { return replyEndTime; } /** * Returns the time after which this request may no longer be * delivered to its target; null if no such time has been specified. */ public UtcT getRequestEndTime() { return requestEndTime; } /** * Returns the time after which this request may be delivered to * its target; null if no such time has been specified. */ public UtcT getRequestStartTime() { return requestStartTime; } }