Package org.jboss.web.tomcat.service.session.distributedcache.impl.jbc

Source Code of org.jboss.web.tomcat.service.session.distributedcache.impl.jbc.JBossCacheService

/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.web.tomcat.service.session.distributedcache.impl.jbc;

import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.transaction.TransactionManager;

import org.jboss.cache.Cache;
import org.jboss.cache.CacheException;
import org.jboss.cache.CacheManager;
import org.jboss.cache.CacheStatus;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.cache.Region;
import org.jboss.cache.buddyreplication.BuddyManager;
import org.jboss.cache.config.BuddyReplicationConfig;
import org.jboss.cache.config.CacheLoaderConfig;
import org.jboss.cache.pojo.impl.InternalConstant;
import org.jboss.cache.transaction.BatchModeTransactionManager;
import org.jboss.ha.framework.interfaces.CachableMarshalledValue;
import org.jboss.ha.framework.server.CacheManagerLocator;
import org.jboss.ha.framework.server.MarshalledValueHelper;
import org.jboss.ha.framework.server.SimpleCachableMarshalledValue;
import org.jboss.logging.Logger;
import org.jboss.web.tomcat.service.session.distributedcache.spi.BatchingManager;
import org.jboss.web.tomcat.service.session.distributedcache.spi.ClusteringNotSupportedException;
import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSession;
import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSessionMetadata;
import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSessionTimestamp;
import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributedCacheManager;
import org.jboss.web.tomcat.service.session.distributedcache.spi.LocalDistributableSessionManager;
import org.jboss.web.tomcat.service.session.distributedcache.spi.SessionSerializationFactory;

/**
* A wrapper class to JBossCache. This is currently needed to handle various operations such as
* <ul>
* <li>Using MarshalledValue to replace Serializable used inside different web app class loader context.</li>
* <li>Stripping out any id string after ".". This is to handle the JK failover properly with
* Tomcat JvmRoute.</li>
* <li>Cache exception retry.</li>
* <li>Helper APIS.</li>
* </ul>
*/
public class JBossCacheService implements DistributedCacheManager
{  
   protected static Logger log_ = Logger.getLogger(JBossCacheService.class);
   public static final String BUDDY_BACKUP = BuddyManager.BUDDY_BACKUP_SUBTREE;
   public static final Fqn BUDDY_BACKUP_FQN = BuddyManager.BUDDY_BACKUP_SUBTREE_FQN;
   public static final String SESSION = "JSESSION";
   public static final String ATTRIBUTE = "ATTRIBUTE";
     
   public static final String FQN_DELIMITER = "/";
  
   private Cache plainCache_;
  
   /** name of webapp's virtual host; hostName + webAppPath + session id is a unique combo. */
   protected String hostName_;
   /** Context path for webapp; hostName + webAppPath + session id is a unique combo. */
   protected String webAppPath_;
   protected BatchingManager batchingManager;

   private LocalDistributableSessionManager manager_;
   private ClassLoader webAppClassLoader_;
   private CacheListener cacheListener_;
   protected JBossCacheWrapper cacheWrapper_;
  
   /** Do we have to marshall attributes ourself or can we let JBC do it? */
   private boolean useTreeCacheMarshalling_ = false;
  
   /** Are we configured for passivation? */
   private boolean usePassivation_ = false;
   private PassivationListener passivationListener_;
  
   /** Is cache configured for buddy replication? */
   private boolean useBuddyReplication_ = false;
  
   private String cacheConfigName_;;
  
   public JBossCacheService(String cacheConfigName) throws ClusteringNotSupportedException
   {
      this(Util.findPlainCache(cacheConfigName));
     
      this.cacheConfigName_ = cacheConfigName;
   }
  
   public JBossCacheService(Cache cache)
   {
      plainCache_ = cache;
     
      cacheWrapper_ = new JBossCacheWrapper(plainCache_);
     
      useTreeCacheMarshalling_ = plainCache_.getConfiguration().isUseRegionBasedMarshalling();
      CacheLoaderConfig clc = plainCache_.getConfiguration().getCacheLoaderConfig();
      if(clc != null)
      {
         usePassivation_ = (clc.isPassivation() && !clc.isShared());
      }
   }
  
   protected LocalDistributableSessionManager getManager()
   {
      return manager_;
   }
  
   protected Cache getCache()
   {
      return plainCache_;
   }
  
   protected void setCache(Cache cache)
   {
      this.plainCache_ = cache;
   }
  
   protected boolean isFieldBased()
   {
      return false;
   }

   public void start(ClassLoader tcl, LocalDistributableSessionManager manager)
   {
      manager_ = manager;
      webAppClassLoader_ = tcl;
     
      String path = manager_.getContextName();
      if( path.length() == 0 || path.equals("/")) {
         // If this is root.
         webAppPath_ = "ROOT";
      } else if ( path.startsWith("/") ) {
         webAppPath_ = path.substring(1);
      } else {
         webAppPath_ = path;
      }
      // JBAS-3941 -- context path can be multi-level, but we don't
      // want that turning into a multilevel Fqn, so escape it
      // Use '?' which is illegal in a context path
      webAppPath_ = webAppPath_.replace('/', '?');
      log_.debug("Old and new web app path are: " +path + ", " +webAppPath_);
     
      String host = manager_.getHostName();
      if( host == null || host.length() == 0) {
         hostName_ = "localhost";
      }else {
         hostName_ = host;
      }
      log_.debug("Old and new virtual host name are: " + host + ", " + hostName_);

      if (plainCache_.getCacheStatus() != CacheStatus.STARTED)
      {
         plainCache_.start();
      }

      // We require the cache batchingManager to be BatchModeTransactionManager now.
      TransactionManager tm = plainCache_.getConfiguration().getRuntimeConfig().getTransactionManager();
      if( ! (tm instanceof BatchModeTransactionManager) )
      {
         throw new RuntimeException("start(): JBoss Cache transaction manager " +
                                    "is not of type BatchModeTransactionManager. " +
                                    "It is " + (tm == null ? "null" : tm.getClass().getName()));
      }
      this.batchingManager = new BatchingManagerImpl(tm);
     
      Object[] objs = new Object[]{SESSION, hostName_, webAppPath_};
      Fqn pathFqn = Fqn.fromList(Arrays.asList(objs), true);
     
      BuddyReplicationConfig brc = plainCache_.getConfiguration().getBuddyReplicationConfig();
      this.useBuddyReplication_ = brc != null && brc.isEnabled();
      if (useTreeCacheMarshalling_ || this.useBuddyReplication_)
      {
         // JBAS-5628/JBAS-5629 -- clean out persistent store
         cleanWebappRegion(pathFqn);
      }

      // Listen for cache changes
      cacheListener_ = new CacheListener(cacheWrapper_, manager_, hostName_, webAppPath_, isFieldBased());
      plainCache_.addCacheListener(cacheListener_);
     
      if(useTreeCacheMarshalling_)
      {
         // register the tcl and bring over the state for the webapp
         try
         {
           
            log_.debug("UseMarshalling is true. We will register the fqn: " +
                        pathFqn + " with class loader" +webAppClassLoader_ +
                        " and activate the webapp's Region");
            Node root = plainCache_.getRoot();
            if (root.hasChild(pathFqn) == false)
            {
               plainCache_.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
               root.addChild(pathFqn);
            }
            Region region = plainCache_.getRegion(pathFqn, true);
            region.registerContextClassLoader(webAppClassLoader_);
            region.activate();
         }
         catch (Exception ex)
         {
            throw new RuntimeException("Can't register class loader", ex);
         }
      }
     
      if(manager_.isPassivationEnabled())
      {
         log_.debug("Passivation is enabled");
         passivationListener_ = new PassivationListener(manager_, hostName_, webAppPath_);
         plainCache_.addCacheListener(passivationListener_);
      }
      else
      {
         log_.debug("Passivation is disabled");
      }
   }

   private void cleanWebappRegion(Fqn regionFqn)
   {
      try {
         // Remove locally.
         plainCache_.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
         plainCache_.removeNode(regionFqn);
      }
      catch (CacheException e)
      {
         log_.error("can't clean content from the underlying distributed cache");
      }
   }

   public void stop()
   {
      plainCache_.removeCacheListener(cacheListener_);     
      if (passivationListener_ != null)
         plainCache_.removeCacheListener(passivationListener_);
     
      // Construct the fqn
      Object[] objs = new Object[]{SESSION, hostName_, webAppPath_};
      Fqn pathFqn = Fqn.fromList(Arrays.asList(objs), true);

      if(useTreeCacheMarshalling_)
      {
         log_.debug("UseMarshalling is true. We will inactivate the fqn: " +
                    pathFqn + " and un-register its classloader");
           
         try {
            Region region = plainCache_.getRegion(pathFqn, false);
            if (region != null)
            {
               region.deactivate();
               region.unregisterContextClassLoader();
            }
         }
         catch (Exception e)
         {
            log_.error("Exception during inactivation of webapp region " + pathFqn +
                       " or un-registration of its class loader", e);
         }
      }
      BuddyReplicationConfig brc = plainCache_.getConfiguration().getBuddyReplicationConfig();
      this.useBuddyReplication_ = brc != null && brc.isEnabled();
      if (useTreeCacheMarshalling_ || this.useBuddyReplication_)
      {
         // JBAS-5628/JBAS-5629 -- clean out persistent store
         cleanWebappRegion(pathFqn);
      }
      // remove session data
      // BES 2007/08/18 Can't do this as it will
      // 1) blow away passivated sessions
      // 2) leave the cache in an inconsistent state if the war
      //    is restarted
//      cacheWrapper_.removeLocalSubtree(pathFqn);
     
      if (cacheConfigName_ != null)
      {
         releaseCacheToManager(cacheConfigName_);
      }
   }

   /**
    * Get specfically the BatchModeTransactionManager.
    */
   public BatchingManager getBatchingManager()
   {
      return batchingManager;
   }
  
   /**
    * Gets whether TreeCache-based marshalling is available
    */
   public boolean isMarshallingAvailable()
   {
      return useTreeCacheMarshalling_;
   }

   /**
    * Loads any serialized data in the cache into the given session
    * using its <code>readExternal</code> method.
    *
    * @return the session passed as <code>toLoad</code>, or
    *         <code>null</code> if the cache had no data stored
    *         under the given session id.
    */
   public <T extends DistributableSession> T loadSession(String realId, T toLoad)
   {
      Fqn fqn = getSessionFqn(realId);
      Map sessionData =  cacheWrapper_.getData(fqn, true);
     
      if (sessionData == null) {
         // Requested session is no longer in the cache; return null
         return null;
      }
     
      setupSessionRegion(toLoad, fqn);
     
      Integer version = (Integer) sessionData.get(VERSION_KEY);
      DistributableSessionTimestamp timestamp = (DistributableSessionTimestamp) sessionData.get(TIMESTAMP_KEY);
      DistributableSessionMetadata metadata = (DistributableSessionMetadata) sessionData.get(METADATA_KEY);
      Map attrs = (Map) getUnMarshalledValue(sessionData.get(ATTRIBUTE_KEY));
      toLoad.update(version, timestamp, metadata, attrs);
     
      return toLoad;
   }

   public void putSession(String realId, DistributableSession session)
   {
      if (log_.isTraceEnabled())
      {
         log_.trace("putSession(): putting session " + session.getIdInternal());
      }    
     
      Fqn fqn = getSessionFqn(realId);
     
      setupSessionRegion(session, fqn);
     
      Map map = new HashMap();
      map.put(VERSION_KEY, new Integer(session.getVersion()));
     
      boolean replicateTimestamp = false;
     
      if (session.isSessionMetadataDirty())
      {  
         map.put(METADATA_KEY, session.getSessionMetadata());
         replicateTimestamp = true;
      }
    
      if (session.isSessionAttributeMapDirty())
      {
         Map attrs = session.getSessionAttributeMap();
         // May be null if the session type doesn't use this mechanism to store
         // attributes (i.e. isn't SessionBasedClusteredSession)
         if (attrs != null)
         {
            map.put(ATTRIBUTE_KEY, getMarshalledValue(attrs));
         }
        
         replicateTimestamp = true;
      }
     
      if (replicateTimestamp || session.getMustReplicateTimestamp())
      {
         map.put(TIMESTAMP_KEY, session.getSessionTimestamp());
      }
     
      cacheWrapper_.put(fqn, map);
   }

   /**
    * If the session requires a region in the cache, establishes one.
    *
    * @param session the session
    * @param fqn the fqn for the session
    */
   private void setupSessionRegion(DistributableSession session, Fqn fqn)
   {
      if (session.needRegionForSession())
      {
         plainCache_.getRegion(fqn, true);
         session.createdRegionForSession();
         if (log_.isTraceEnabled())
         {
            log_.trace("Created region for session at " + fqn);
         }
      }
   }

   public void removeSession(String realId, boolean removeRegion)
   {
      Fqn fqn = getSessionFqn(realId);
      if (log_.isTraceEnabled())
      {
         log_.trace("Remove session from distributed store. Fqn: " + fqn);
      }
     
      if (removeRegion)
      {
         plainCache_.removeRegion(fqn);
      }

      cacheWrapper_.remove(fqn);
   }

   public void removeSessionLocal(String realId, boolean removeRegion)
   {
      Fqn fqn = getSessionFqn(realId);
      if (log_.isTraceEnabled())
      {
         log_.trace("Remove session from my own distributed store only. Fqn: " + fqn);
      }
     
      if (removeRegion)
      {
         plainCache_.removeRegion(fqn);
      }
     
      cacheWrapper_.removeLocal(fqn);
   }

   public void removeSessionLocal(String realId, String dataOwner)
   {
      if (dataOwner == null)
      {
         removeSessionLocal(realId, false);
      }
      else
      {        
         Fqn fqn = getSessionFqn(realId, dataOwner);
         if (log_.isTraceEnabled())
         {
            log_.trace("Remove session from my own distributed store only. Fqn: " + fqn);
         }
         cacheWrapper_.removeLocal(fqn);
      }
   }  
     
   public void evictSession(String realId)
   {
      evictSession(realId, null);     
   }  
     
   public void evictSession(String realId, String dataOwner)
   {   
      Fqn fqn = dataOwner == null ? getSessionFqn(realId) : getSessionFqn(realId, dataOwner);
      if(log_.isTraceEnabled())
      {
         log_.trace("evictSession(): evicting session from my distributed store. Fqn: " + fqn);
      }
      cacheWrapper_.evictSubtree(fqn);     
   }
  
   public Map getSessionData(String realId, String dataOwner)
   {
      Fqn fqn = dataOwner == null ? getSessionFqn(realId) : getSessionFqn(realId, dataOwner);
      return cacheWrapper_.getData(fqn, false);
   }

   public Object getAttribute(String realId, String key)
   {
      Fqn fqn = getAttributeFqn(realId);
      return getUnMarshalledValue(cacheWrapper_.get(fqn, key));
   }

   public void putAttribute(String realId, String key, Object value)
   {
      Fqn fqn = getAttributeFqn(realId);
      cacheWrapper_.put(fqn, key, getMarshalledValue(value));
   }

   public void putAttribute(String realId, Map map)
   {
      // Duplicate the map with marshalled values
      Map marshalled = new HashMap(map.size());
      Set entries = map.entrySet();
      for (Iterator it = entries.iterator(); it.hasNext(); )
      {
         Map.Entry entry = (Map.Entry) it.next();
         marshalled.put(entry.getKey(), getMarshalledValue(entry.getValue()));
      }
     
      Fqn fqn = getAttributeFqn(realId);
      cacheWrapper_.put(fqn, marshalled);
     
   }

   public void removeAttributes(String realId)
   {
      Fqn fqn = getAttributeFqn(realId);
      cacheWrapper_.remove(fqn);
   }

   public Object removeAttribute(String realId, String key)
   {
      Fqn fqn = getAttributeFqn(realId);
      if (log_.isTraceEnabled())
      {
         log_.trace("Remove attribute from distributed store. Fqn: " + fqn + " key: " + key);
      }
      return getUnMarshalledValue(cacheWrapper_.remove(fqn, key));
   }

   public void removeAttributesLocal(String realId)
   {
      Fqn fqn = getAttributeFqn(realId);
      if (log_.isTraceEnabled())
      {
         log_.trace("Remove attributes from my own distributed store only. Fqn: " + fqn);
      }
      cacheWrapper_.removeLocal(fqn);
   }

   /**
    * Obtain the keys associated with this fqn. Note that it is not the fqn children.
    *
    */
   public Set getAttributeKeys(String realId)
   {
      Set keys = null;
      Fqn fqn = getAttributeFqn(realId);
      try
      {
         Node node = plainCache_.getRoot().getChild(fqn);
         if (node != null)
            keys = node.getKeys();
      }
      catch (CacheException e)
      {
         log_.error("getAttributeKeys(): Exception getting keys for session " + realId, e);
      }
     
      return keys;
   }

   /**
    * Return all attributes associated with this session id.
    *
    * @param realId the session id with any jvmRoute removed
    * @return the attributes, or any empty Map if none are found.
    */
   public Map getAttributes(String realId)
   {
      if (realId == null || realId.length() == 0) return new HashMap();
     
      Map attrs = new HashMap();
      Fqn fqn = getAttributeFqn(realId);
     
      Node node = plainCache_.getRoot().getChild(fqn);
      Map rawData = node.getData();
     
      for (Iterator it = rawData.entrySet().iterator(); it.hasNext();)
      {
         Entry entry = (Entry) it.next();
         attrs.put(entry.getKey(), getUnMarshalledValue(entry.getValue()));
      }
     
      return attrs;
   }

   /**
    * Gets the ids of all sessions in the underlying cache.
    *
    * @return Map<String, String> containing all of the session ids of sessions in the cache
    *         (with any jvmRoute removed) as keys, and the identifier of the data owner for
    *         the session as value (or a <code>null</code>  value if buddy
    *         replication is not enabled.) Will not return <code>null</code>.
    */
   public Map<String, String> getSessionIds()
   {
      Map<String, String> result = new HashMap<String, String>();
     
      Node bbRoot = plainCache_.getRoot().getChild(BUDDY_BACKUP_FQN);
      if (bbRoot != null)
      {
         Set owners = bbRoot.getChildren();
         if (owners != null)
         {
            for (Iterator it = owners.iterator(); it.hasNext();)
            {
               Node owner = (Node) it.next();
               Node webRoot = owner.getChild(getWebappFqn());
               if (webRoot != null)
               {
                  Set<String> ids = webRoot.getChildrenNames();
                  storeSessionOwners(ids, (String) owner.getFqn().getLastElement(), result);
               }
            }
         }
      }
     
      storeSessionOwners(getChildrenNames(getWebappFqn()), null, result);

      return result;
   }
  
   protected Set getChildrenNames(Fqn fqn)
   {
      Node node = plainCache_.getRoot().getChild(fqn);
      return (node == null ? null : node.getChildrenNames());
   }

   private void storeSessionOwners(Set<String> ids, String owner, Map<String, String> map)
   {
      if (ids != null)
      {
         for (String id : ids)
         {           
            if (!InternalConstant.JBOSS_INTERNAL_STRING.equals(id))
            {
               map.put(id, owner);
            }
         }
      }
   }
   public boolean isPassivationEnabled()
   {
      return usePassivation_;     
   }

   protected Fqn getWebappFqn()
   {
      // /SESSION/hostname/webAppPath
      Object[] objs = new Object[]{SESSION, hostName_, webAppPath_};
      return Fqn.fromList(Arrays.asList(objs), true);
   }
  
   protected Fqn getSessionFqn(String id)
   {
      return getSessionFqn(hostName_, webAppPath_, id);
   }
  
   public static Fqn getSessionFqn(String hostname, String contextPath, String sessionId)
   {
      Object[] objs = new Object[]{SESSION, hostname, contextPath, sessionId};
      return Fqn.fromList(Arrays.asList(objs), true);
   }

   private Fqn getSessionFqn(String id, String dataOwner)
   {
      return getSessionFqn(dataOwner, hostName_, webAppPath_, id);
   }
  
   public static Fqn getSessionFqn(String dataOwner, String hostname, String contextPath, String sessionId)
   {
      Object[] objs = new Object[]{BUDDY_BACKUP, dataOwner, SESSION, hostname, contextPath, sessionId};
      return Fqn.fromList(Arrays.asList(objs), true);
   }

   protected Fqn getAttributeFqn(String id)
   {
      return getAttributeFqn(hostName_, webAppPath_, id);
   }

   public static Fqn getAttributeFqn(String hostname, String contextPath, String sessionId)
   {
      Object[] objs = new Object[]{SESSION, hostname, contextPath, sessionId, ATTRIBUTE};
      return Fqn.fromList(Arrays.asList(objs), true);
   }
  
   protected void releaseCacheToManager(String cacheConfigName)
   {     
      try
      {
         CacheManager cm = CacheManagerLocator.getCacheManagerLocator().getCacheManager(null);
         cm.releaseCache(cacheConfigName);
      }
      catch (Exception e)
      {
         log_.error("Problem releasing cache to CacheManager -- config is " + cacheConfigName, e);
      }
   }

   private Object getMarshalledValue(Object value)
   {
      // JBAS-2920.  For now, continue using MarshalledValue, as
      // it allows lazy deserialization of the attribute on remote nodes
      // For Branch_4_0 this is what we have to do anyway for backwards
      // compatibility. For HEAD we'll follow suit for now.
      // TODO consider only using MV for complex objects (i.e. not primitives)
      // and Strings longer than X.
     
//      if (useTreeCacheMarshalling_)
//      {
//         return value;
//      }
//      else
//      {
        
         // JBAS-2921 - replaced MarshalledValue calls with SessionSerializationFactory calls
         // to allow for switching between JBossSerialization and JavaSerialization using
         // system property -D=session.serialization.jboss=true / false
         // MarshalledValue mv = new MarshalledValue(value);
         if  (MarshalledValueHelper.isTypeExcluded(value.getClass()))
         {
            return value;              
         }
         else
         {
            try
            {
               CachableMarshalledValue mv = SessionSerializationFactory.createMarshalledValue((Serializable) value);
               return mv;
            }
            catch (ClassCastException e)
            {
               throw new IllegalArgumentException(value + " does not implement java.io.Serializable");
            }
         }
//      }
   }

   private Object getUnMarshalledValue(Object obj)
   {
      if (!(obj instanceof SimpleCachableMarshalledValue))
            return obj;
        
      // Swap in/out the tcl for this web app. Needed only for un marshalling.
      ClassLoader prevTCL = Thread.currentThread().getContextClassLoader();
      Thread.currentThread().setContextClassLoader(webAppClassLoader_);
      try
      {
         SimpleCachableMarshalledValue mv = (SimpleCachableMarshalledValue) obj;
         mv.setObjectStreamSource(SessionSerializationFactory.getObjectStreamSource());
         return mv.get();
      }
      catch (IOException e)
      {
         log_.error("IOException occurred unmarshalling value ", e);
         return null;
      }
      catch (ClassNotFoundException e)
      {
         log_.error("ClassNotFoundException occurred unmarshalling value ", e);
         return null;
      }
      finally
      {
         Thread.currentThread().setContextClassLoader(prevTCL);
      }
   }

}
TOP

Related Classes of org.jboss.web.tomcat.service.session.distributedcache.impl.jbc.JBossCacheService

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.