This discussion is archived
8 Replies Latest reply: Apr 12, 2011 10:27 AM by sanjay92 RSS

Is there a way to keep a session pool?

539082 Newbie
Currently Being Moderated
I'm writing a servlet to do public search on Content DB. By doing so i created a special user "publicuser" who has no privilege. For each request, the search is performed by this user. So what i'm trying to do is to create a certain number of sessions for that user and put these live sessions to a pool. Logout is executed in "destroy" method of the servlet.
However, when the same session is used again to do search, an exception is thrown out.
07/06/06 08:58:21 java.lang.RuntimeException: AxisRemoteManagersFactory has not been correctly bootstrapped
07/06/06 08:58:21      at oracle.ifs.fdk.client.impl.AxisRemoteManagersFactory.update(AxisRemoteManagersFactory.java:879)
07/06/06 08:58:21      at oracle.ifs.fdk.client.impl.SearchManagerProxy.search(SearchManagerProxy.java:52)

I find that if i logout this session and then login, it works. But it costs lots of time. So is there a way to pool a number of live sessions?( here a session is an object of ManagersFactory class)
Thanks!
  • 1. Re: Is there a way to keep a session pool?
    mshannon Newbie
    Currently Being Moderated
    Hi,

    A few things to consider:

    1) You could create the servlet to run in-process avoiding the Web Services alltogether if you are willing to expose the servlet from the OC4J_Content container.

    See the CDB devkit for details on accessing FDK in-process.

    2) With pooled Web Service sessions, you need to be caseful of session timeout.

    Here is some connection pool code from the great Sancho Pinto that you could repurpose/adapt if you wanted to pool web service sessions :-
    package oracle.ifs.devutils.markup.session;

    import java.util.Stack;

    import oracle.ifs.fdk.FdkCredential;
    import oracle.ifs.fdk.FdkErrorCodes;
    import oracle.ifs.fdk.FdkException;
    import oracle.ifs.fdk.Item;
    import oracle.ifs.fdk.ManagersFactory;
    import oracle.ifs.fdk.S2SFdkCredential;

    import oracle.ifs.devutils.markup.MarkupException;

    import oracle.ifs.devutils.markup.util.MarkupProperties;
    import oracle.ifs.fdk.SimpleFdkCredential;

    /*
    * Copyright (c) 2006 Oracle Corporation. All rights reserved.
    *
    * History:
    *  2006-05-10  spinto    Created.
    *  2007-07-02  mshannon  Updated isSessionValid method to use non-cached property
    */

    /**
    * Maintains a pool of markup user ManagerFactorys. Ensures the ManagersFactory
    * that it returns is valid. The pool's parameters (maximum size and target size)
    * are specified in the markup.properties file.
    */
    public class ConnectionPool
    {
      private static ConnectionPool m_ConnectionPool = null;

      /** Pool of available connections. */
      private Stack m_Pool = new Stack();

      /** Overall total number of connections that have been allocated. */
      private int m_AllocatedNum = 0;

      /** Default maximum we permit to be allocated; */
      private int m_MaxConnections = 10;

      /** Default maximum we permit in the pool; this will be less than m_MaxConnections; */
      private int m_TargetConnections = 5;

      /**
       * Constructor.
       */
      private ConnectionPool()
        throws MarkupException
      {
        m_MaxConnections = MarkupProperties.getInstance().getMaxAllowedConnections();
        m_TargetConnections = MarkupProperties.getInstance().getMaxPoolSize();
      }

      /**
       * Returns a singleton instance of the ConnectionPool.
       *
       * @return the singleton ConnectionPool instance
       */
      public static synchronized ConnectionPool getInstance()
        throws MarkupException
      {
        if (m_ConnectionPool == null)
        {
          m_ConnectionPool = new ConnectionPool();
        }

        return m_ConnectionPool;
      }

      /**
       * Returns one valid session from the pool.
       *
       * @return a valid FdkSession
       *
       * @throws MarkupException if operation failed
       */
      public synchronized ManagersFactory getSession()
        throws MarkupException
      {
        ManagersFactory sess = null;

        try
        {
          if (!m_Pool.empty())
          {
            sess = (ManagersFactory) m_Pool.pop();

            if (!isSessionValid(sess))
            {
              System.out.println("Stale session - refresh session");
              sess = obtainConnection();
            }
            else
            {
              System.out.println("Reusing session from pool");
            }
          }
          else if (m_AllocatedNum < m_MaxConnections)
          {
            sess = obtainConnection();
            ++m_AllocatedNum;
            System.out.println("Allocated new session");
          }
          else
          {
            System.out.println("No sessions available!");
          }

          if (false)
          {
            logStatistics();
          }
        }
        catch (Exception e)
        {
          throw new MarkupException(oracle.ifs.devutils.markup.MarkupException.CONNECTION_FAILURE, e);
        }

        return sess;
      }

      /**
       * Puts a connection back to the pool.
       *
       * @param conn the session
       */
      public synchronized void releaseSession(ManagersFactory conn)
      {
        if ((conn == null) || !isSessionValid(conn))
        {
          throw new RuntimeException("called with disconnected connection");
        }

        if (m_Pool.size() < m_TargetConnections)
        {
          m_Pool.push(conn);
        }
        else
        {
          try
          {
            conn.logout();
          }
          catch (FdkException fe)
          {
            System.out.println("Error during best effort logout: "+fe);
          }
          --m_AllocatedNum;
        }

        if (false)
        {
          logStatistics();
        }
      }

      /**
       * Obtains a new FdkSession
       *
       * @return a new session
       *
       * @throws MarkupException if operation failed
       */
      private ManagersFactory obtainConnection()
        throws MarkupException
      {
        try
        {
          FdkCredential credential = null;
          if (MarkupProperties.getInstance().getApplicationUserPassword() == null)
          {
            credential =
               new S2SFdkCredential(MarkupProperties.getInstance().getApplicationUser(),
                                    MarkupProperties.getInstance().getTrustedAppName(),
                                    MarkupProperties.getInstance().getTrustedAppPassword(), null);
          }
          else
          {
            credential =
               new SimpleFdkCredential(MarkupProperties.getInstance().getApplicationUser(),
                                       MarkupProperties.getInstance().getApplicationUserPassword());      
          }
         
          return
            ManagersFactory.login(credential,
                                  MarkupProperties.getInstance().getContentServicesURL());
        }
        catch (Exception e)
        {
          throw new MarkupException(MarkupException.CONNECTION_FAILURE, e);
        }
      }


      /**
       * Checks whether the session is valid by making a call to the server
       */
      private boolean isSessionValid(ManagersFactory session)
      {
        try
        {
          SessionManager sessionM = session.getSessionManager();
          sessionM.keepAlive();
        }
        catch (FdkException e)
        {
          System.out.println("Stale session: "+e.getErrorCode() +"-"+e.getDetailedErrorCode());
          return false;
        }
        
        return true;
      }
      
      /**
       * Print the current pool statistics to the log.
       */
      private void logStatistics()
      {
        System.out.println("connection pool size: " + m_Pool.size() + "; maximum pool size: " +
          m_TargetConnections + "; allocated connections: " + m_AllocatedNum +
          "; maximum allocated connections: " + m_MaxConnections);
      }
    }
    Message was edited by mshannon on 2 July 2007 to fix isSessionValid method.
    mshannon
  • 2. Re: Is there a way to keep a session pool?
    539082 Newbie
    Currently Being Moderated
    Really appreciate your help!
    I have another question. In the following code:
    private boolean isSessionValid(ManagersFactory session)
    {
    try
    {
    Item user = session.getUser(null);
    }
    catch (FdkException e)
    {
    System.out.println("Stale session: "+e.getErrorCode() +"-"+e.getDetailedErrorCode());
    return false;
    }

    return true;
    }


    if an exception thrown from Item user = session.getUser(null), does it mean the session is time out or has been logout?
  • 3. Re: Is there a way to keep a session pool?
    539082 Newbie
    Currently Being Moderated
    i encountered the following exception when performing search, even if isSessionValid returns true.
    07/06/08 04:31:15 AxisFault
    faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.userException
    faultSubcode:
    faultString: ORACLE.FDK.SessionError:ORACLE.FDK.SessionNotConnected
    faultActor:
    faultNode:
    faultDetail:
         {http://xmlns.oracle.com/content/ws}fault:<detailedErrorCode xsi:type="xsd:string">ORACLE.FDK.SessionNotConnected</detailedErrorCode><errorCode xsi:type="xsd:string">ORACLE.FDK.SessionError</errorCode><exceptionEntries xsi:type="ns1:ArrayOfFdkExceptionEntry" xsi:nil="true"/><info xsi:type="ns1:ArrayOfNamedValue" xsi:nil="true"/><serverStackTraceId xsi:type="xsd:string"/>
         {http://xml.apache.org/axis/}hostname:dvod1.cn.oracle.com

    07/06/08 04:31:15 ORACLE.FDK.SessionError:ORACLE.FDK.SessionNotConnected
    07/06/08 04:31:15      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    07/06/08 04:31:15      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java)
    07/06/08 04:31:15      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    07/06/08 04:31:15      at java.lang.reflect.Constructor.newInstance(Constructor.java)
    07/06/08 04:31:15      at java.lang.Class.newInstance0(Class.java:308)
    07/06/08 04:31:15      at java.lang.Class.newInstance(Class.java)
    07/06/08 04:31:15      at org.apache.axis.encoding.ser.BeanDeserializer.<init>(BeanDeserializer.java:104)
    07/06/08 04:31:15      at org.apache.axis.encoding.ser.BeanDeserializer.<init>(BeanDeserializer.java:92)
    07/06/08 04:31:15      at oracle.ifs.fdk.FdkException.getDeserializer(FdkException.java:270)
    07/06/08 04:31:15      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    07/06/08 04:31:15      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java)
    07/06/08 04:31:15      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    07/06/08 04:31:15      at java.lang.reflect.Method.invoke(Method.java)
    07/06/08 04:31:15      at org.apache.axis.encoding.ser.BaseDeserializerFactory.getSpecialized(BaseDeserializerFactory.java:154)
    07/06/08 04:31:15      at org.apache.axis.encoding.ser.BaseDeserializerFactory.getDeserializerAs(BaseDeserializerFactory.java:84)
    07/06/08 04:31:15      at org.apache.axis.encoding.DeserializationContext.getDeserializer(DeserializationContext.java:464)
    07/06/08 04:31:15      at org.apache.axis.encoding.DeserializationContext.getDeserializerForType(DeserializationContext.java:547)
    07/06/08 04:31:15      at org.apache.axis.message.SOAPFaultDetailsBuilder.onStartChild(SOAPFaultDetailsBuilder.java:157)
    07/06/08 04:31:15      at org.apache.axis.encoding.DeserializationContext.startElement(DeserializationContext.java:1052)
    07/06/08 04:31:15      at oracle.xml.parser.v2.NonValidatingParser.parseElement(NonValidatingParser.java:1280)
    07/06/08 04:31:15      at oracle.xml.parser.v2.NonValidatingParser.parseRootElement(NonValidatingParser.java:328)
    07/06/08 04:31:15      at oracle.xml.parser.v2.NonValidatingParser.parseDocument(NonValidatingParser.java:295)
    07/06/08 04:31:15      at oracle.xml.parser.v2.XMLParser.parse(XMLParser.java:201)
    07/06/08 04:31:15      at oracle.xml.jaxp.JXSAXParser.parse(JXSAXParser.java)
    07/06/08 04:31:15      at org.apache.axis.encoding.DeserializationContext.parse(DeserializationContext.java:227)
    07/06/08 04:31:15      at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:696)
    07/06/08 04:31:15      at org.apache.axis.Message.getSOAPEnvelope(Message.java)
    07/06/08 04:31:15      at org.apache.axis.handlers.soap.MustUnderstandChecker.invoke(MustUnderstandChecker.java:66)
    07/06/08 04:31:15      at org.apache.axis.client.AxisClient.invoke(AxisClient.java:206)
    07/06/08 04:31:15      at org.apache.axis.client.Call.invokeEngine(Call.java:2767)
    07/06/08 04:31:15      at org.apache.axis.client.Call.invoke(Call.java:2748)
    07/06/08 04:31:15      at org.apache.axis.client.Call.invoke(Call.java:2424)
    07/06/08 04:31:15      at org.apache.axis.client.Call.invoke(Call.java)
    07/06/08 04:31:15      at org.apache.axis.client.Call.invoke(Call.java:1804)
    07/06/08 04:31:15      at oracle.ifs.fdk.SearchManagerSoapBindingStub.search(SearchManagerSoapBindingStub.java:297)
  • 4. Re: Is there a way to keep a session pool?
    mshannon Newbie
    Currently Being Moderated
    Really appreciate your help!
    I have another question. In the following code:
    private boolean isSessionValid(ManagersFactory
    session)
    {
    try
    {
    Item user = session.getUser(null);
    }
    catch (FdkException e)
    {
    System.out.println("Stale session:
    "+e.getErrorCode() +"-"+e.getDetailedErrorCode());
    return false;


    return true;
    }

    f an exception thrown from Item user =
    session.getUser(null), does it mean the session is
    time out or has been logout?
    Yes, if an FDK exception is returned when trying to return the user associated with the connection, then the connection is likely to have timed out (or there is some bad network/transport issue etc). Thus, a new session will be created and the old connection disposed. With this particular session pool code I gave you, logout is only called on a thread - when the total allocated thread count exceeds the m_TargetConnections count.

    cheers

    Matt.
  • 5. Re: Is there a way to keep a session pool?
    mshannon Newbie
    Currently Being Moderated
    Interesting ...

    How long after retrieving the session from the pool does it take you to perform the FDK operation (e.g. search?).

    Are you only requesting a session from the pool immediately prior to performing the FDK operations - and returning it straight away after performing the operations?

    If you grab a session from the pool, and don't use it immediately / hang on to it - then its possible for that session to timeout. the session timeout is dictacted in the web.xml file.

    cheers

    Matt.
  • 6. Re: Is there a way to keep a session pool?
    539082 Newbie
    Currently Being Moderated
    I met the error of "ORACLE.FDK.SessionNotConnected" again when i resuse the session from the pool to do search. Actually search is performed immediately after getting the session. and the following code is used to check whether the session is valid.
    private boolean isSessionValid(ManagersFactory session) {
    try {
    Item user = session.getUser(null);
    String userName=user.getName();
    logger.info("session user is: "+userName);
    SearchManager sm=session.getSearchManager();
    } catch (FdkException e) {
    logger.error("Stale session: " + e.getErrorCode() + "-" +
    e.getDetailedErrorCode());
    return false;
    }
    return true;
    }


    And from the log file there is: "CDBSessionPool (CDBSessionPool.java:46) - session user is: publicuser"

    which is from logger.info("session user is: "+userName);

    So is there another way to check whether the session got from pool is valid?

    Thanks!
  • 7. Re: Is there a way to keep a session pool?
    mshannon Newbie
    Currently Being Moderated
    Your absolutely right there was a bug with Sancho's code. I've updated the session pool code above accordingly to fix this.

    It turns out ((ManagersFactory) session).getUser(null) when supplying null as the parameter actually attempts to return a cached version of the item representing the user from a previous session.getUser() call – meaning a web service call to sessionM.getCurrentUser() may actually not occur!

    Whereas ((ManagersFactory) session).getUser(new AttributeRequest[] { ClientUtils.newAttributeRequest(Attributes.FIRST_NAME) }) will always return a non-cached version of the item representing the user – meaning a web service call to sessionM.getCurrentUser() will always be made!


    To fix the code.. change the isSessionValid(ManagersFactory session) method to something like ..
      /**
       * Checks whether the session is valid by making a call to the server
       */
      private boolean isSessionValid(ManagersFactory session)
      {
        try
        {
          SessionManager sessionM = session.getSessionManager();
          sessionM.keepAlive();
        }
        catch (FdkException e)
        {
          System.out.println("Stale session: "+e.getErrorCode() +"-"+e.getDetailedErrorCode());
          return false;
        }
        
        return true;
      }
    Thanks for finding the bug ..

    Matt.
  • 8. Re: Is there a way to keep a session pool?
    sanjay92 Newbie
    Currently Being Moderated
    Are these packages standard in CDB Dev kit ?

    package oracle.ifs.devutils.markup.session;

    import oracle.ifs.devutils.markup.MarkupException;

    import oracle.ifs.devutils.markup.util.MarkupProperties;



    if not, where do I get them ?