All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.remoting.MultiClassLoaderSerializer Maven / Gradle / Ivy

Go to download

Contains the bootstrap code to bridge separate JVMs into a single semi-shared space. Reusable outside Hudson.

There is a newer version: 3.0.3
Show newest version
/*******************************************************************************
 *
 * Copyright (c) 2004-2010 Oracle Corporation.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     
 *
 *******************************************************************************/ 

package hudson.remoting;

import hudson.remoting.RemoteClassLoader.IClassLoader;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * {@link ObjectInputStream}/{@link ObjectOutputStream} pair that can handle object graph that spans across
 * multiple classloaders.
 *
 * 

* To pass around ClassLoaders, this class uses OID instead of {@link IClassLoader}, since doing so * can results in recursive class resolution that may end up with NPE in ObjectInputStream.defaultReadFields like * described in the comment from huybrechts in HUDSON-4293. * * @author Kohsuke Kawaguchi * @see Capability#supportsMultiClassLoaderRPC() */ class MultiClassLoaderSerializer { static final class Output extends ObjectOutputStream { private final Channel channel; /** * Encountered Classloaders, to their indices. */ private final Map classLoaders = new HashMap(); Output(Channel channel, OutputStream out) throws IOException { super(out); this.channel = channel; } @Override protected void annotateClass(Class c) throws IOException { ClassLoader cl = c.getClassLoader(); if (cl==null) {// bootstrap classloader. no need to export. writeInt(TAG_SYSTEMCLASSLOADER); return; } Integer idx = classLoaders.get(cl); if (idx==null) { classLoaders.put(cl,classLoaders.size()); if (cl instanceof RemoteClassLoader) { int oid = ((RemoteClassLoader) cl).getOid(channel); if (oid>=0) { // this classloader came from where we are sending this classloader to. writeInt(TAG_LOCAL_CLASSLOADER); writeInt(oid); return; } } // tell the receiving side that they need to import a new classloader writeInt(TAG_EXPORTED_CLASSLOADER); writeInt(RemoteClassLoader.exportId(cl,channel)); } else {// reference to a classloader that's already written writeInt(idx); } } @Override protected void annotateProxyClass(Class cl) throws IOException { annotateClass(cl); } } static final class Input extends ObjectInputStream { private final Channel channel; private final List classLoaders = new ArrayList(); Input(Channel channel, InputStream in) throws IOException { super(in); this.channel = channel; } private ClassLoader readClassLoader() throws IOException, ClassNotFoundException { ClassLoader cl; int code = readInt(); switch (code) { case TAG_SYSTEMCLASSLOADER: return null; case TAG_LOCAL_CLASSLOADER: cl = ((RemoteClassLoader.ClassLoaderProxy)channel.getExportedObject(readInt())).cl; classLoaders.add(cl); return cl; case TAG_EXPORTED_CLASSLOADER: cl = channel.importedClassLoaders.get(readInt()); classLoaders.add(cl); return cl; default: return classLoaders.get(code); } } @Override protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { String name = desc.getName(); try { ClassLoader cl = readClassLoader(); Class c = Class.forName(name, false, cl); return c; } catch (ClassNotFoundException ex) { return super.resolveClass(desc); } } @Override protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { ClassLoader cl = readClassLoader(); Class[] classes = new Class[interfaces.length]; for (int i = 0; i < interfaces.length; i++) classes[i] = Class.forName(interfaces[i], false, cl); return Proxy.getProxyClass(cl, classes); } } /** * Indicates that the class being sent should be loaded from the system classloader. */ private static final int TAG_SYSTEMCLASSLOADER = -3; /** * Indicates that the class being sent originates from the sender side. The sender exports this classloader * and sends its OID in the following int. The receiver will import this classloader to resolve the class. */ private static final int TAG_EXPORTED_CLASSLOADER = -2; /** * Indicates that the class being sent originally came from the receiver. The following int indicates * the OID of the classloader exported from the receiver, which the sender used. */ private static final int TAG_LOCAL_CLASSLOADER = -1; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy