Package com.sun.enterprise.ee.web.sessmgmt

Source Code of com.sun.enterprise.ee.web.sessmgmt.JxtaUnicastPipeUtil$JxtaUnicastPipeWrapper

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

package com.sun.enterprise.ee.web.sessmgmt;

import com.sun.logging.LogDomains;

import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

import net.jxta.document.MimeMediaType;
import net.jxta.document.XMLDocument;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.TextDocumentMessageElement;
import net.jxta.impl.endpoint.router.EndpointRouter;
import net.jxta.impl.pipe.BlockingWireOutputPipe;
import net.jxta.peer.PeerID;
import net.jxta.pipe.OutputPipe;
import net.jxta.protocol.RouteAdvertisement;

/*
* Utility methods for using Jxta unicast pipes.
*
* The purpose of this class is to provide a pool of unicast pipes to each
* instance.
*
* The number of pipes here is a little misleading -- each Jxta pipe is
* physically connected to the same socket (for a given instance). So
* no matter how many pipes there are, there is only one socket. This
* means that while it makes sense to have a few so that they can setup and
* multiplex in the appserver, we'll get more contention at the JXTA layer
* as we add pipes. We'll have to test to get to the optimal number but
* it is likely small.
*
* Hence, the pipes are put in a Deque (stack) so that we will end up creating
* a minimal number of them anyway, with an absolute upper bound based on the
* number of pipes configured. Note that if we cant get a pipe here, the JXTA
* layer is all clogged up anyway, so making more pipes doesn't help.
*
* FIXME: Should we just fail the call without waiting in that case?
*
*/
public class JxtaUnicastPipeUtil {

    private static HashMap<String, LinkedBlockingDeque<JxtaUnicastPipeWrapper>> pipeMap =
  new HashMap<String, LinkedBlockingDeque<JxtaUnicastPipeWrapper>>();
    private static int numPipes = ReplicationUtil.getNumberOfOutputPipes();

    private final static Level TRACE_LEVEL = Level.FINE;   
    public final static String LOGGER_MEM_REP
        = ReplicationState.LOGGER_MEM_REP;
   
    private static final Logger _logger
        = Logger.getLogger(LOGGER_MEM_REP);
    private static final Logger _pipelogger = ReplicationUtil.getPipeLogger();

    private static AtomicLong _unicastMessageFailures = new AtomicLong(0);
    private static int NUMBER_OF_PIPES = 1; // FIXME

    static {
  // FIXME
  // See comments above about this number; we'll test it to determine
  // the optimal value; this will probably not need to be configurable
  String s = System.getProperty("jxtaUnicastPipeWrappers");
  if (s != null) {
      try {
    NUMBER_OF_PIPES = Integer.parseInt(s);
      } catch (Exception e) {
    NUMBER_OF_PIPES = 5;
      }
  }
    }

    /****  PUBLIC METHODS  ****/
    public static void initializeUnicastOutputPipe(String instanceName) {
  synchronized(pipeMap) {
      // It won't be in the map unless we missed an event, but still...
        removeUnicastOutputPipe(instanceName);
      getDeque(instanceName, true);
  }
    }

    public static void removeUnicastOutputPipe(String instanceName) {
        LinkedBlockingDeque<JxtaUnicastPipeWrapper> deck = null;
        synchronized(pipeMap) {
            deck = pipeMap.remove(instanceName);
        }
        if (deck != null) {
            for (JxtaUnicastPipeWrapper pipeWrapper = deck.unlinkFirst(); pipeWrapper != null;
                pipeWrapper = deck.unlinkFirst()) {
                if (!pipeWrapper.closed) {
                    pipeWrapper.close();
                }
            }
            deck.close();
        }
    }


    public static void sendOverPropagatedPipe(ReplicationState state,
        String instanceName, boolean isResponse) {
  if (_logger.isLoggable(Level.FINE)) {
      _logger.fine("JxtaUnicastPipeUtil>>sendOverPropagatedPipe:toInstance=" + instanceName);
  }
  //use this to create our outputPipe
  RouteAdvertisement routeAdv = state.getRouteAdvertisement();
  Message msg = ReplicationState.createBroadcastMessage(state, isResponse, instanceName);
  //add routeAdvertisement element for return route (self-addressed stamped envelope)
  if (!isResponse) {
      JxtaUtil.addRoute(msg);
  }
  sendOverUnicastPipe(routeAdv, instanceName, (String) state.getId(),
      state.getCommand(), msg);
    }

    public static long getFailures() {
  return _unicastMessageFailures.get();
    }

    public static boolean sendOverUnicastPipe(RouteAdvertisement ra,
  String instanceName, String id, String command, Message msg) {

  boolean sendResult = false;
  final int MAX_RETRY = 6;
  JxtaUnicastPipeWrapper pw = null;
  for (int retryCount = 0; retryCount < MAX_RETRY; retryCount++) {
      try {
    pw = getPipe(instanceName, ra);
    if (pw == null) {
        if (_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.log(Level.FINE,
        "Aborting attempt to send " + command +
        " to unavailable instance " + instanceName);
        }
        return false;
    }
    if (_pipelogger.isLoggable(Level.FINEST)) {
        _pipelogger.log(Level.FINEST, "sending over unicast pipe for sessionid=" + id + " pipe= " + pw);
    }
    sendResult = pw.send(msg);
    if (sendResult) {
        break;
    }
    else {
        // If we got here, either
        //   1) we are congested.
        //   2) The remote side is down.
        //
        // If we don't wait for a small time, we will still
        // be congested, but we can't wait too long for a down
        // machine.
        try { Thread.sleep(10); } catch (InterruptedException ie) {}
        if (_pipelogger.isLoggable(Level.FINE)) {
      _pipelogger.fine("send over unicast pipe failed for sessionid=" + id + " pipe=" + pw);
        }
    }
      } catch (InterruptedException ie) {
    // Either we are very backed up, or the remote host is down
    // In either case, no use retrying
    return false;
      } catch (IOException ex) {
    if (_pipelogger.isLoggable(Level.FINE)) {
        _pipelogger.log(Level.FINE, "IOException sending unicast message over " + pw, ex);
    }
    if (pw != null)
        pw.error(ex);
    if (retryCount < MAX_RETRY) {
        if (_pipelogger.isLoggable(Level.FINE)) {
      _pipelogger.fine("unicast pipe send retrying");
        }
    }
      } finally {
    returnPipe(instanceName, pw);
      }
  }
  if (sendResult == false) {
      _unicastMessageFailures.incrementAndGet();
      if (_pipelogger.isLoggable(Level.INFO)) {
    _pipelogger.info("failed to send message over unicast pipe for sessionid=" + id + " cmd=" + command + " to instance " + instanceName);
      }
  }
  return sendResult;
    }

    /****  PRIVATE METHODS  ****/
    private JxtaUnicastPipeUtil() {
  throw new IllegalArgumentException("Don't instantiate UnicastPipeUtil");
    }

    private static JxtaUnicastPipeWrapper getPipe(
    String instance, RouteAdvertisement ra) throws IOException, InterruptedException {
  LinkedBlockingDeque<JxtaUnicastPipeWrapper> deck;
  deck = getDeque(instance, false);
  if (deck == null) {
      return null;
  }
  // We will only ever block here if the pool size is 1 and the remote
  // system is down.
  JxtaUnicastPipeWrapper pw = deck.pollFirst(5, TimeUnit.SECONDS);
  if (pw == null) {
      if (!deck.isClosed()) {
          _logger.warning("Waited 5 seconds for free JXTA unicast pipe to " + instance);
      }
      throw new InterruptedException("Timeout waiting for JXTA unicast pipe " + instance);
  }
  return check(pw, instance, ra);
    }

    private static void returnPipe(String instance, JxtaUnicastPipeWrapper pw) {
  if (pw == null)
      return;
  if (pw.closed) {
      pw.initPipeWrapper(null, null, null);
  }
  LinkedBlockingDeque<JxtaUnicastPipeWrapper> deck = getDeque(instance, false);
  if (deck != null) {
      boolean b = deck.offerFirst(pw);
  }
  // if deck == null, it means that someone is returning a pipe on an
  // instance that has been remove via GMS notification. Just ignore that.
    }

    private static void makePipe(JxtaUnicastPipeWrapper pw,
  String instanceName, RouteAdvertisement ra) throws IOException {

  PeerID peerID = JxtaStarter.getPeerID(instanceName);
        OutputPipe p = new BlockingWireOutputPipe(
    JxtaUtil.getNetPeerGroup(),
    JxtaUtil.getPropagatedPipeAdvertisement(), peerID, ra);
        if (_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("create PropagatedPipe instance=" +
        instanceName + " peerId="+ peerID + " routeAdv=" + ra);
        }
  pw.initPipeWrapper(p, ra, instanceName);
    }

    private static JxtaUnicastPipeWrapper check(
          JxtaUnicastPipeWrapper pw,
    String instanceName, RouteAdvertisement ra) throws IOException {
               
  if (pw.closed || pw.pipe == null || pw.pipe.isClosed()) {
      makePipe(pw, instanceName, ra);
        } else if (ra != null && pw.routeAdv != null && !ra.equals(pw.routeAdv)) {
      if (_pipelogger.isLoggable(Level.FINER)) {
    _pipelogger.finer(
              "detected a stale propagated pipe for instance=" +
              instanceName + " cached routeAdv=" +
              pw.routeAdv + " current routeAdv=" + ra);
      }
      // close stale pipe
      pw.close();
      makePipe(pw, instanceName, ra);
  } else if (_pipelogger.isLoggable(Level.FINEST)) {
            _pipelogger.finest(
        "cache hit for propagated pipe to instance=" +
        instanceName + " routeAdv=" + ra);   
        }
        return pw;
    }

    private static LinkedBlockingDeque<JxtaUnicastPipeWrapper>
      getDeque(String instance, boolean create) {
  LinkedBlockingDeque<JxtaUnicastPipeWrapper> deck;
  synchronized(pipeMap) {
      deck = pipeMap.get(instance);
      if (deck == null && create) {
    deck = new LinkedBlockingDeque<JxtaUnicastPipeWrapper>(NUMBER_OF_PIPES);
    pipeMap.put(instance, deck);
    for (int i = 0; i < NUMBER_OF_PIPES; i++) {
        deck.offerFirst(new JxtaUnicastPipeWrapper());
    }
      }
  }
  return deck;
    }

    private static class JxtaUnicastPipeWrapper {
        private OutputPipe pipe;
        private RouteAdvertisement routeAdv;
        private boolean closed = false;
        private String myInstance;

        public boolean send(Message m) throws IOException {
      // We set closed so that if the send fails for any reason, we know
      // not to reuse the pipe
      closed = true;
      try {
          boolean b = pipe.send(m);
          closed = false;
          return b;
      } finally {
          if (closed) {
        close();
          }
      }
        }

        public void initPipeWrapper(OutputPipe p,
            RouteAdvertisement ra, String s) {
      pipe = p;
      routeAdv = ra;
      myInstance = s;
        }

        public void error(Throwable t) {
      try {
          close();
      } catch (Throwable ignore) {
         // ignore
      }
        }

        public void close() {
      if (pipe != null)
          pipe.close();
      closed = true;
        }

        public String toString() {
      return "JXTA Unicast Pipe Wrapper #" +
    System.identityHashCode(this) +
          " connected to " + myInstance;
        }
    }

    /*
     * This class is a subset of the JDK 6 LinkedBlockingDeque class. When
     * Sailfin no longer supports JDK 5, this class should be removed and
     * the JDK 6 class used in its place -- except note that we have added
     * the isClosed functionality, so it will still need to be subclassed.
     */

    private static final class LinkedBlockingDeque<E> {
  private static final class Node<E> {
      E item;
      Node<E> prev;
      Node<E> next;
      Node(E x, Node<E> p, Node<E> n) {
    item = x;
    prev = p;
    next = n;
      }
  }

  private volatile boolean isClosed = false;
  private transient Node<E> first;
  private transient Node<E> last;
  private transient int count;
  private final int capacity;
  private final ReentrantLock lock = new ReentrantLock();
  private final Condition notEmpty = lock.newCondition();

  public LinkedBlockingDeque(int capacity) {
      if (capacity <= 0) throw new IllegalArgumentException();
      this.capacity = capacity;
  }

  public E pollFirst(long timeout, TimeUnit unit)
      throws InterruptedException {
      long nanos = unit.toNanos(timeout);
      lock.lockInterruptibly();
      try {
    for (;;) {
        E x = unlinkFirst();
        if (x != null)
      return x;
        if (isClosed)
      return null;
        if (nanos <= 0)
      return null;
        nanos = notEmpty.awaitNanos(nanos);
    }
      } finally {
    lock.unlock();
      }
  }

  public boolean offerFirst(E e) {
      if (e == null) throw new NullPointerException();
      lock.lock();
      try {
    return linkFirst(e);
      } finally {
    lock.unlock();
      }
  }

  public void close() {
      lock.lock();
      try {
          isClosed = true;
    notEmpty.signalAll();
      } finally {
    lock.unlock();
      }
  }

  public boolean isClosed() {
      return isClosed;
  }

  private boolean linkFirst(E e) {
      if (count >= capacity) {
    return false;
      }
      ++count;
      Node<E> f = first;
      Node<E> x = new Node<E>(e, null, f);
      first = x;
      if (last == null)
    last = x;
      else
    f.prev = x;
      notEmpty.signal();
      return true;
  }

  private E unlinkFirst() {
      Node<E> f = first;
      if (f == null)
    return null;
      Node<E> n = f.next;
      first = n;
      if (n == null)
    last = null;
      else n.prev = null;
      --count;
      return f.item;
  }
    }

}
TOP

Related Classes of com.sun.enterprise.ee.web.sessmgmt.JxtaUnicastPipeUtil$JxtaUnicastPipeWrapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.