feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
140
jdkSrc/jdk8/sun/rmi/log/LogHandler.java
Normal file
140
jdkSrc/jdk8/sun/rmi/log/LogHandler.java
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.log;
|
||||
|
||||
import java.io.*;
|
||||
import sun.rmi.server.MarshalOutputStream;
|
||||
import sun.rmi.server.MarshalInputStream;
|
||||
|
||||
/**
|
||||
* A LogHandler represents snapshots and update records as serializable
|
||||
* objects.
|
||||
*
|
||||
* This implementation does not know how to create an initial snaphot or
|
||||
* apply an update to a snapshot. The client must specifiy these methods
|
||||
* via a subclass.
|
||||
*
|
||||
* @see ReliableLog
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
*/
|
||||
public abstract
|
||||
class LogHandler {
|
||||
|
||||
/**
|
||||
* Creates a LogHandler for a ReliableLog.
|
||||
*/
|
||||
public LogHandler() {}
|
||||
|
||||
/**
|
||||
* Creates and returns the initial state of data structure that needs
|
||||
* to be stably stored. This method is called when a ReliableLog is
|
||||
* created.
|
||||
* @return the initial state
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
public abstract
|
||||
Object initialSnapshot() throws Exception;
|
||||
|
||||
/**
|
||||
* Writes the snapshot object to a stream. This callback is
|
||||
* invoked when the client calls the snaphot method of ReliableLog.
|
||||
* @param out the output stream
|
||||
* @param value the snapshot
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
public
|
||||
void snapshot(OutputStream out, Object value) throws Exception {
|
||||
MarshalOutputStream s = new MarshalOutputStream(out);
|
||||
s.writeObject(value);
|
||||
s.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the snapshot object from a stream and returns the snapshot.
|
||||
* This callback is invoked when the client calls the recover method
|
||||
* of ReliableLog.
|
||||
* @param in the input stream
|
||||
* @return the state (snapshot)
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
|
||||
public
|
||||
Object recover(InputStream in) throws Exception {
|
||||
MarshalInputStream s = new MarshalInputStream(in);
|
||||
return s.readObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the representation (a serializable object) of an update
|
||||
* to a stream. This callback is invoked when the client calls the
|
||||
* update method of ReliableLog.
|
||||
* @param out the output stream
|
||||
* @param value the snapshot
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
public
|
||||
void writeUpdate(LogOutputStream out, Object value) throws Exception {
|
||||
|
||||
MarshalOutputStream s = new MarshalOutputStream(out);
|
||||
s.writeObject(value);
|
||||
s.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a stably logged update (a serializable object) from a
|
||||
* stream. This callback is invoked during recovery, once for
|
||||
* every record in the log. After reading the update, this method
|
||||
* invokes the applyUpdate (abstract) method in order to obtain
|
||||
* the new snapshot value. It then returns the new snapshot.
|
||||
*
|
||||
* @param in the input stream
|
||||
* @param state the current state
|
||||
* @return the new state
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
public
|
||||
Object readUpdate(LogInputStream in, Object state) throws Exception {
|
||||
MarshalInputStream s = new MarshalInputStream(in);
|
||||
return applyUpdate(s.readObject(), state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a stably logged update (a serializable object) from a stream.
|
||||
* This callback is invoked during recovery, once for every record in the
|
||||
* log. After reading the update, this method is invoked in order to
|
||||
* obtain the new snapshot value. The method should apply the update
|
||||
* object to the current state <code>state</code> and return the new
|
||||
* state (the new snapshot value).
|
||||
* @param update the update object
|
||||
* @param state the current state
|
||||
* @return the new state
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
public abstract
|
||||
Object applyUpdate(Object update, Object state) throws Exception;
|
||||
|
||||
}
|
||||
134
jdkSrc/jdk8/sun/rmi/log/LogInputStream.java
Normal file
134
jdkSrc/jdk8/sun/rmi/log/LogInputStream.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.log;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public
|
||||
class LogInputStream extends InputStream {
|
||||
private InputStream in;
|
||||
private int length;
|
||||
|
||||
/**
|
||||
* Creates a log input file with the specified system dependent
|
||||
* file descriptor.
|
||||
* @param fd the system dependent file descriptor
|
||||
* @param length the total number of bytes allowed to be read
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public LogInputStream(InputStream in, int length) throws IOException {
|
||||
this.in = in;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte of data. This method will block if no input is
|
||||
* available.
|
||||
* @return the byte read, or -1 if the end of the log or end of the
|
||||
* stream is reached.
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
if (length == 0)
|
||||
return -1;
|
||||
int c = in.read();
|
||||
length = (c != -1) ? length - 1 : 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data into an array of bytes.
|
||||
* This method blocks until some input is available.
|
||||
* @param b the buffer into which the data is read
|
||||
* @return the actual number of bytes read, or -1 if the end of the log
|
||||
* or end of the stream is reached.
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public int read(byte b[]) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data into an array of bytes.
|
||||
* This method blocks until some input is available.
|
||||
* @param b the buffer into which the data is read
|
||||
* @param off the start offset of the data
|
||||
* @param len the maximum number of bytes read
|
||||
* @return the actual number of bytes read, or -1 if the end of the log or
|
||||
* end of the stream is reached.
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
if (length == 0)
|
||||
return -1;
|
||||
len = (length < len) ? length : len;
|
||||
int n = in.read(b, off, len);
|
||||
length = (n != -1) ? length - n : 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips n bytes of input.
|
||||
* @param n the number of bytes to be skipped
|
||||
* @return the actual number of bytes skipped.
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public long skip(long n) throws IOException {
|
||||
if (n > Integer.MAX_VALUE)
|
||||
throw new IOException("Too many bytes to skip - " + n);
|
||||
if (length == 0)
|
||||
return 0;
|
||||
n = (length < n) ? length : n;
|
||||
n = in.skip(n);
|
||||
length -= n;
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that can be read without blocking.
|
||||
* @return the number of available bytes, which is initially
|
||||
* equal to the file size.
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
int avail = in.available();
|
||||
return (length < avail) ? length : avail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the input stream. No further input can be read.
|
||||
* the stream.
|
||||
*/
|
||||
public void close() {
|
||||
length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream when garbage is collected.
|
||||
*/
|
||||
protected void finalize() throws IOException {
|
||||
close();
|
||||
}
|
||||
}
|
||||
83
jdkSrc/jdk8/sun/rmi/log/LogOutputStream.java
Normal file
83
jdkSrc/jdk8/sun/rmi/log/LogOutputStream.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.log;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public
|
||||
class LogOutputStream extends OutputStream {
|
||||
|
||||
private RandomAccessFile raf;
|
||||
|
||||
/**
|
||||
* Creates an output file with the specified system dependent
|
||||
* file descriptor.
|
||||
* @param fd the system dependent file descriptor
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public LogOutputStream(RandomAccessFile raf) throws IOException {
|
||||
this.raf = raf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte of data. This method will block until the byte is
|
||||
* actually written.
|
||||
* @param b the byte to be written
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public void write(int b) throws IOException {
|
||||
raf.write(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an array of bytes. Will block until the bytes
|
||||
* are actually written.
|
||||
* @param b the data to be written
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public void write(byte b[]) throws IOException {
|
||||
raf.write(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a sub array of bytes.
|
||||
* @param b the data to be written
|
||||
* @param off the start offset in the data
|
||||
* @param len the number of bytes that are written
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
raf.write(b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can not close a LogOutputStream, so this does nothing.
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public final void close() throws IOException {
|
||||
}
|
||||
|
||||
}
|
||||
824
jdkSrc/jdk8/sun/rmi/log/ReliableLog.java
Normal file
824
jdkSrc/jdk8/sun/rmi/log/ReliableLog.java
Normal file
@@ -0,0 +1,824 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.log;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.rmi.server.RMIClassLoader;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* This class is a simple implementation of a reliable Log. The
|
||||
* client of a ReliableLog must provide a set of callbacks (via a
|
||||
* LogHandler) that enables a ReliableLog to read and write
|
||||
* checkpoints and log records. This implementation ensures that the
|
||||
* current value of the data stored (via a ReliableLog) is recoverable
|
||||
* after a system crash. <p>
|
||||
*
|
||||
* The secondary storage strategy is to record values in files using a
|
||||
* representation of the caller's choosing. Two sorts of files are
|
||||
* kept: snapshots and logs. At any instant, one snapshot is current.
|
||||
* The log consists of a sequence of updates that have occurred since
|
||||
* the current snapshot was taken. The current stable state is the
|
||||
* value of the snapshot, as modified by the sequence of updates in
|
||||
* the log. From time to time, the client of a ReliableLog instructs
|
||||
* the package to make a new snapshot and clear the log. A ReliableLog
|
||||
* arranges disk writes such that updates are stable (as long as the
|
||||
* changes are force-written to disk) and atomic : no update is lost,
|
||||
* and each update either is recorded completely in the log or not at
|
||||
* all. Making a new snapshot is also atomic. <p>
|
||||
*
|
||||
* Normal use for maintaining the recoverable store is as follows: The
|
||||
* client maintains the relevant data structure in virtual memory. As
|
||||
* updates happen to the structure, the client informs the ReliableLog
|
||||
* (all it "log") by calling log.update. Periodically, the client
|
||||
* calls log.snapshot to provide the current value of the data
|
||||
* structure. On restart, the client calls log.recover to obtain the
|
||||
* latest snapshot and the following sequences of updates; the client
|
||||
* applies the updates to the snapshot to obtain the state that
|
||||
* existed before the crash. <p>
|
||||
*
|
||||
* The current logfile format is: <ol>
|
||||
* <li> a format version number (two 4-octet integers, major and
|
||||
* minor), followed by
|
||||
* <li> a sequence of log records. Each log record contains, in
|
||||
* order, <ol>
|
||||
* <li> a 4-octet integer representing the length of the following log
|
||||
* data,
|
||||
* <li> the log data (variable length). </ol> </ol> <p>
|
||||
*
|
||||
* @see LogHandler
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
*
|
||||
*/
|
||||
public class ReliableLog {
|
||||
|
||||
public final static int PreferredMajorVersion = 0;
|
||||
public final static int PreferredMinorVersion = 2;
|
||||
|
||||
// sun.rmi.log.debug=false
|
||||
private boolean Debug = false;
|
||||
|
||||
private static String snapshotPrefix = "Snapshot.";
|
||||
private static String logfilePrefix = "Logfile.";
|
||||
private static String versionFile = "Version_Number";
|
||||
private static String newVersionFile = "New_Version_Number";
|
||||
private static int intBytes = 4;
|
||||
private static long diskPageSize = 512;
|
||||
|
||||
private File dir; // base directory
|
||||
private int version = 0; // current snapshot and log version
|
||||
private String logName = null;
|
||||
private LogFile log = null;
|
||||
private long snapshotBytes = 0;
|
||||
private long logBytes = 0;
|
||||
private int logEntries = 0;
|
||||
private long lastSnapshot = 0;
|
||||
private long lastLog = 0;
|
||||
//private long padBoundary = intBytes;
|
||||
private LogHandler handler;
|
||||
private final byte[] intBuf = new byte[4];
|
||||
|
||||
// format version numbers read from/written to this.log
|
||||
private int majorFormatVersion = 0;
|
||||
private int minorFormatVersion = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for the log file. If the system property
|
||||
* sun.rmi.log.class is non-null and the class specified by this
|
||||
* property a) can be loaded, b) is a subclass of LogFile, and c) has a
|
||||
* public two-arg constructor (String, String), ReliableLog uses the
|
||||
* constructor to construct the LogFile.
|
||||
**/
|
||||
private static final Constructor<? extends LogFile>
|
||||
logClassConstructor = getLogClassConstructor();
|
||||
|
||||
/**
|
||||
* Creates a ReliableLog to handle checkpoints and logging in a
|
||||
* stable storage directory.
|
||||
*
|
||||
* @param dirPath path to the stable storage directory
|
||||
* @param logCl the closure object containing callbacks for logging and
|
||||
* recovery
|
||||
* @param pad ignored
|
||||
* @exception IOException If a directory creation error has
|
||||
* occurred or if initialSnapshot callback raises an exception or
|
||||
* if an exception occurs during invocation of the handler's
|
||||
* snapshot method or if other IOException occurs.
|
||||
*/
|
||||
public ReliableLog(String dirPath,
|
||||
LogHandler handler,
|
||||
boolean pad)
|
||||
throws IOException
|
||||
{
|
||||
super();
|
||||
this.Debug = AccessController.doPrivileged(
|
||||
new GetBooleanAction("sun.rmi.log.debug")).booleanValue();
|
||||
dir = new File(dirPath);
|
||||
if (!(dir.exists() && dir.isDirectory())) {
|
||||
// create directory
|
||||
if (!dir.mkdir()) {
|
||||
throw new IOException("could not create directory for log: " +
|
||||
dirPath);
|
||||
}
|
||||
}
|
||||
//padBoundary = (pad ? diskPageSize : intBytes);
|
||||
this.handler = handler;
|
||||
lastSnapshot = 0;
|
||||
lastLog = 0;
|
||||
getVersion();
|
||||
if (version == 0) {
|
||||
try {
|
||||
snapshot(handler.initialSnapshot());
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new IOException("initial snapshot failed with " +
|
||||
"exception: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ReliableLog to handle checkpoints and logging in a
|
||||
* stable storage directory.
|
||||
*
|
||||
* @param dirPath path to the stable storage directory
|
||||
* @param logCl the closure object containing callbacks for logging and
|
||||
* recovery
|
||||
* @exception IOException If a directory creation error has
|
||||
* occurred or if initialSnapshot callback raises an exception
|
||||
*/
|
||||
public ReliableLog(String dirPath,
|
||||
LogHandler handler)
|
||||
throws IOException
|
||||
{
|
||||
this(dirPath, handler, false);
|
||||
}
|
||||
|
||||
/* public methods */
|
||||
|
||||
/**
|
||||
* Returns an object which is the value recorded in the current
|
||||
* snapshot. This snapshot is recovered by calling the client
|
||||
* supplied callback "recover" and then subsequently invoking
|
||||
* the "readUpdate" callback to apply any logged updates to the state.
|
||||
*
|
||||
* @exception IOException If recovery fails due to serious log
|
||||
* corruption, read update failure, or if an exception occurs
|
||||
* during the recover callback
|
||||
*/
|
||||
public synchronized Object recover()
|
||||
throws IOException
|
||||
{
|
||||
if (Debug)
|
||||
System.err.println("log.debug: recover()");
|
||||
|
||||
if (version == 0)
|
||||
return null;
|
||||
|
||||
Object snapshot;
|
||||
String fname = versionName(snapshotPrefix);
|
||||
File snapshotFile = new File(fname);
|
||||
InputStream in =
|
||||
new BufferedInputStream(new FileInputStream(snapshotFile));
|
||||
|
||||
if (Debug)
|
||||
System.err.println("log.debug: recovering from " + fname);
|
||||
|
||||
try {
|
||||
try {
|
||||
snapshot = handler.recover(in);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
if (Debug)
|
||||
System.err.println("log.debug: recovery failed: " + e);
|
||||
throw new IOException("log recover failed with " +
|
||||
"exception: " + e);
|
||||
}
|
||||
snapshotBytes = snapshotFile.length();
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
|
||||
return recoverUpdates(snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Records this update in the log file (does not force update to disk).
|
||||
* The update is recorded by calling the client's "writeUpdate" callback.
|
||||
* This method must not be called until this log's recover method has
|
||||
* been invoked (and completed).
|
||||
*
|
||||
* @param value the object representing the update
|
||||
* @exception IOException If an exception occurred during a
|
||||
* writeUpdate callback or if other I/O error has occurred.
|
||||
*/
|
||||
public synchronized void update(Object value) throws IOException {
|
||||
update(value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Records this update in the log file. The update is recorded by
|
||||
* calling the client's writeUpdate callback. This method must not be
|
||||
* called until this log's recover method has been invoked
|
||||
* (and completed).
|
||||
*
|
||||
* @param value the object representing the update
|
||||
* @param forceToDisk ignored; changes are always forced to disk
|
||||
* @exception IOException If force-write to log failed or an
|
||||
* exception occurred during the writeUpdate callback or if other
|
||||
* I/O error occurs while updating the log.
|
||||
*/
|
||||
public synchronized void update(Object value, boolean forceToDisk)
|
||||
throws IOException
|
||||
{
|
||||
// avoid accessing a null log field.
|
||||
if (log == null) {
|
||||
throw new IOException("log is inaccessible, " +
|
||||
"it may have been corrupted or closed");
|
||||
}
|
||||
|
||||
/*
|
||||
* If the entry length field spans a sector boundary, write
|
||||
* the high order bit of the entry length, otherwise write zero for
|
||||
* the entry length.
|
||||
*/
|
||||
long entryStart = log.getFilePointer();
|
||||
boolean spansBoundary = log.checkSpansBoundary(entryStart);
|
||||
writeInt(log, spansBoundary? 1<<31 : 0);
|
||||
|
||||
/*
|
||||
* Write update, and sync.
|
||||
*/
|
||||
try {
|
||||
handler.writeUpdate(new LogOutputStream(log), value);
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw (IOException)
|
||||
new IOException("write update failed").initCause(e);
|
||||
}
|
||||
log.sync();
|
||||
|
||||
long entryEnd = log.getFilePointer();
|
||||
int updateLen = (int) ((entryEnd - entryStart) - intBytes);
|
||||
log.seek(entryStart);
|
||||
|
||||
if (spansBoundary) {
|
||||
/*
|
||||
* If length field spans a sector boundary, then
|
||||
* the next two steps are required (see 4652922):
|
||||
*
|
||||
* 1) Write actual length with high order bit set; sync.
|
||||
* 2) Then clear high order bit of length; sync.
|
||||
*/
|
||||
writeInt(log, updateLen | 1<<31);
|
||||
log.sync();
|
||||
|
||||
log.seek(entryStart);
|
||||
log.writeByte(updateLen >> 24);
|
||||
log.sync();
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Write actual length; sync.
|
||||
*/
|
||||
writeInt(log, updateLen);
|
||||
log.sync();
|
||||
}
|
||||
|
||||
log.seek(entryEnd);
|
||||
logBytes = entryEnd;
|
||||
lastLog = System.currentTimeMillis();
|
||||
logEntries++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the constructor for the log file if the system property
|
||||
* sun.rmi.log.class is non-null and the class specified by the
|
||||
* property a) can be loaded, b) is a subclass of LogFile, and c) has a
|
||||
* public two-arg constructor (String, String); otherwise returns null.
|
||||
**/
|
||||
private static Constructor<? extends LogFile>
|
||||
getLogClassConstructor() {
|
||||
|
||||
String logClassName = AccessController.doPrivileged(
|
||||
new GetPropertyAction("sun.rmi.log.class"));
|
||||
if (logClassName != null) {
|
||||
try {
|
||||
ClassLoader loader =
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<ClassLoader>() {
|
||||
public ClassLoader run() {
|
||||
return ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
});
|
||||
Class<? extends LogFile> cl =
|
||||
loader.loadClass(logClassName).asSubclass(LogFile.class);
|
||||
return cl.getConstructor(String.class, String.class);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Exception occurred:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records this value as the current snapshot by invoking the client
|
||||
* supplied "snapshot" callback and then empties the log.
|
||||
*
|
||||
* @param value the object representing the new snapshot
|
||||
* @exception IOException If an exception occurred during the
|
||||
* snapshot callback or if other I/O error has occurred during the
|
||||
* snapshot process
|
||||
*/
|
||||
public synchronized void snapshot(Object value)
|
||||
throws IOException
|
||||
{
|
||||
int oldVersion = version;
|
||||
incrVersion();
|
||||
|
||||
String fname = versionName(snapshotPrefix);
|
||||
File snapshotFile = new File(fname);
|
||||
FileOutputStream out = new FileOutputStream(snapshotFile);
|
||||
try {
|
||||
try {
|
||||
handler.snapshot(out, value);
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new IOException("snapshot failed", e);
|
||||
}
|
||||
lastSnapshot = System.currentTimeMillis();
|
||||
} finally {
|
||||
out.close();
|
||||
snapshotBytes = snapshotFile.length();
|
||||
}
|
||||
|
||||
openLogFile(true);
|
||||
writeVersionFile(true);
|
||||
commitToNewVersion();
|
||||
deleteSnapshot(oldVersion);
|
||||
deleteLogFile(oldVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the stable storage directory in an orderly manner.
|
||||
*
|
||||
* @exception IOException If an I/O error occurs when the log is
|
||||
* closed
|
||||
*/
|
||||
public synchronized void close() throws IOException {
|
||||
if (log == null) return;
|
||||
try {
|
||||
log.close();
|
||||
} finally {
|
||||
log = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the snapshot file in bytes;
|
||||
*/
|
||||
public long snapshotSize() {
|
||||
return snapshotBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the log file in bytes;
|
||||
*/
|
||||
public long logSize() {
|
||||
return logBytes;
|
||||
}
|
||||
|
||||
/* private methods */
|
||||
|
||||
/**
|
||||
* Write an int value in single write operation. This method
|
||||
* assumes that the caller is synchronized on the log file.
|
||||
*
|
||||
* @param out output stream
|
||||
* @param val int value
|
||||
* @throws IOException if any other I/O error occurs
|
||||
*/
|
||||
private void writeInt(DataOutput out, int val)
|
||||
throws IOException
|
||||
{
|
||||
intBuf[0] = (byte) (val >> 24);
|
||||
intBuf[1] = (byte) (val >> 16);
|
||||
intBuf[2] = (byte) (val >> 8);
|
||||
intBuf[3] = (byte) val;
|
||||
out.write(intBuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a filename prepended with the stable storage directory path.
|
||||
*
|
||||
* @param name the leaf name of the file
|
||||
*/
|
||||
private String fName(String name) {
|
||||
return dir.getPath() + File.separator + name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a version 0 filename prepended with the stable storage
|
||||
* directory path
|
||||
*
|
||||
* @param name version file name
|
||||
*/
|
||||
private String versionName(String name) {
|
||||
return versionName(name, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a version filename prepended with the stable storage
|
||||
* directory path with the version number as a suffix.
|
||||
*
|
||||
* @param name version file name
|
||||
* @thisversion a version number
|
||||
*/
|
||||
private String versionName(String prefix, int ver) {
|
||||
ver = (ver == 0) ? version : ver;
|
||||
return fName(prefix) + String.valueOf(ver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the directory version number.
|
||||
*/
|
||||
private void incrVersion() {
|
||||
do { version++; } while (version==0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file.
|
||||
*
|
||||
* @param name the name of the file
|
||||
* @exception IOException If new version file couldn't be removed
|
||||
*/
|
||||
private void deleteFile(String name) throws IOException {
|
||||
|
||||
File f = new File(name);
|
||||
if (!f.delete())
|
||||
throw new IOException("couldn't remove file: " + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the new version number file.
|
||||
*
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void deleteNewVersionFile() throws IOException {
|
||||
deleteFile(fName(newVersionFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the snapshot file.
|
||||
*
|
||||
* @param ver the version to remove
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void deleteSnapshot(int ver) throws IOException {
|
||||
if (ver == 0) return;
|
||||
deleteFile(versionName(snapshotPrefix, ver));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the log file.
|
||||
*
|
||||
* @param ver the version to remove
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void deleteLogFile(int ver) throws IOException {
|
||||
if (ver == 0) return;
|
||||
deleteFile(versionName(logfilePrefix, ver));
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the log file in read/write mode. If file does not exist, it is
|
||||
* created.
|
||||
*
|
||||
* @param truncate if true and file exists, file is truncated to zero
|
||||
* length
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void openLogFile(boolean truncate) throws IOException {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException e) { /* assume this is okay */
|
||||
}
|
||||
|
||||
logName = versionName(logfilePrefix);
|
||||
|
||||
try {
|
||||
log = (logClassConstructor == null ?
|
||||
new LogFile(logName, "rw") :
|
||||
logClassConstructor.newInstance(logName, "rw"));
|
||||
} catch (Exception e) {
|
||||
throw (IOException) new IOException(
|
||||
"unable to construct LogFile instance").initCause(e);
|
||||
}
|
||||
|
||||
if (truncate) {
|
||||
initializeLogFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new log file, truncated and initialized with the format
|
||||
* version number preferred by this implementation.
|
||||
* <p>Environment: inited, synchronized
|
||||
* <p>Precondition: valid: log, log contains nothing useful
|
||||
* <p>Postcondition: if successful, log is initialised with the format
|
||||
* version number (Preferred{Major,Minor}Version), and logBytes is
|
||||
* set to the resulting size of the updatelog, and logEntries is set to
|
||||
* zero. Otherwise, log is in an indeterminate state, and logBytes
|
||||
* is unchanged, and logEntries is unchanged.
|
||||
*
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void initializeLogFile()
|
||||
throws IOException
|
||||
{
|
||||
log.setLength(0);
|
||||
majorFormatVersion = PreferredMajorVersion;
|
||||
writeInt(log, PreferredMajorVersion);
|
||||
minorFormatVersion = PreferredMinorVersion;
|
||||
writeInt(log, PreferredMinorVersion);
|
||||
logBytes = intBytes * 2;
|
||||
logEntries = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out version number to file.
|
||||
*
|
||||
* @param newVersion if true, writes to a new version file
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void writeVersionFile(boolean newVersion) throws IOException {
|
||||
String name;
|
||||
if (newVersion) {
|
||||
name = newVersionFile;
|
||||
} else {
|
||||
name = versionFile;
|
||||
}
|
||||
try (FileOutputStream fos = new FileOutputStream(fName(name));
|
||||
DataOutputStream out = new DataOutputStream(fos)) {
|
||||
writeInt(out, version);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the initial version file
|
||||
*
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void createFirstVersion() throws IOException {
|
||||
version = 0;
|
||||
writeVersionFile(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits (atomically) the new version.
|
||||
*
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void commitToNewVersion() throws IOException {
|
||||
writeVersionFile(false);
|
||||
deleteNewVersionFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads version number from a file.
|
||||
*
|
||||
* @param name the name of the version file
|
||||
* @return the version
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private int readVersion(String name) throws IOException {
|
||||
try (DataInputStream in = new DataInputStream
|
||||
(new FileInputStream(name))) {
|
||||
return in.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the version. If version file does not exist, the initial
|
||||
* version file is created.
|
||||
*
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void getVersion() throws IOException {
|
||||
try {
|
||||
version = readVersion(fName(newVersionFile));
|
||||
commitToNewVersion();
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
deleteNewVersionFile();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
version = readVersion(fName(versionFile));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
createFirstVersion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies outstanding updates to the snapshot.
|
||||
*
|
||||
* @param state the most recent snapshot
|
||||
* @exception IOException If serious log corruption is detected or
|
||||
* if an exception occurred during a readUpdate callback or if
|
||||
* other I/O error has occurred.
|
||||
* @return the resulting state of the object after all updates
|
||||
*/
|
||||
private Object recoverUpdates(Object state)
|
||||
throws IOException
|
||||
{
|
||||
logBytes = 0;
|
||||
logEntries = 0;
|
||||
|
||||
if (version == 0) return state;
|
||||
|
||||
String fname = versionName(logfilePrefix);
|
||||
InputStream in =
|
||||
new BufferedInputStream(new FileInputStream(fname));
|
||||
DataInputStream dataIn = new DataInputStream(in);
|
||||
|
||||
if (Debug)
|
||||
System.err.println("log.debug: reading updates from " + fname);
|
||||
|
||||
try {
|
||||
majorFormatVersion = dataIn.readInt(); logBytes += intBytes;
|
||||
minorFormatVersion = dataIn.readInt(); logBytes += intBytes;
|
||||
} catch (EOFException e) {
|
||||
/* This is a log which was corrupted and/or cleared (by
|
||||
* fsck or equivalent). This is not an error.
|
||||
*/
|
||||
openLogFile(true); // create and truncate
|
||||
in = null;
|
||||
}
|
||||
/* A new major version number is a catastrophe (it means
|
||||
* that the file format is incompatible with older
|
||||
* clients, and we'll only be breaking things by trying to
|
||||
* use the log). A new minor version is no big deal for
|
||||
* upward compatibility.
|
||||
*/
|
||||
if (majorFormatVersion != PreferredMajorVersion) {
|
||||
if (Debug) {
|
||||
System.err.println("log.debug: major version mismatch: " +
|
||||
majorFormatVersion + "." + minorFormatVersion);
|
||||
}
|
||||
throw new IOException("Log file " + logName + " has a " +
|
||||
"version " + majorFormatVersion +
|
||||
"." + minorFormatVersion +
|
||||
" format, and this implementation " +
|
||||
" understands only version " +
|
||||
PreferredMajorVersion + "." +
|
||||
PreferredMinorVersion);
|
||||
}
|
||||
|
||||
try {
|
||||
while (in != null) {
|
||||
int updateLen = 0;
|
||||
|
||||
try {
|
||||
updateLen = dataIn.readInt();
|
||||
} catch (EOFException e) {
|
||||
if (Debug)
|
||||
System.err.println("log.debug: log was sync'd cleanly");
|
||||
break;
|
||||
}
|
||||
if (updateLen <= 0) {/* crashed while writing last log entry */
|
||||
if (Debug) {
|
||||
System.err.println(
|
||||
"log.debug: last update incomplete, " +
|
||||
"updateLen = 0x" +
|
||||
Integer.toHexString(updateLen));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// this is a fragile use of available() which relies on the
|
||||
// twin facts that BufferedInputStream correctly consults
|
||||
// the underlying stream, and that FileInputStream returns
|
||||
// the number of bytes remaining in the file (via FIONREAD).
|
||||
if (in.available() < updateLen) {
|
||||
/* corrupted record at end of log (can happen since we
|
||||
* do only one fsync)
|
||||
*/
|
||||
if (Debug)
|
||||
System.err.println("log.debug: log was truncated");
|
||||
break;
|
||||
}
|
||||
|
||||
if (Debug)
|
||||
System.err.println("log.debug: rdUpdate size " + updateLen);
|
||||
try {
|
||||
state = handler.readUpdate(new LogInputStream(in, updateLen),
|
||||
state);
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new IOException("read update failed with " +
|
||||
"exception: " + e);
|
||||
}
|
||||
logBytes += (intBytes + updateLen);
|
||||
logEntries++;
|
||||
} /* while */
|
||||
} finally {
|
||||
if (in != null)
|
||||
in.close();
|
||||
}
|
||||
|
||||
if (Debug)
|
||||
System.err.println("log.debug: recovered updates: " + logEntries);
|
||||
|
||||
/* reopen log file at end */
|
||||
openLogFile(false);
|
||||
|
||||
// avoid accessing a null log field
|
||||
if (log == null) {
|
||||
throw new IOException("rmid's log is inaccessible, " +
|
||||
"it may have been corrupted or closed");
|
||||
}
|
||||
|
||||
log.seek(logBytes);
|
||||
log.setLength(logBytes);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* ReliableLog's log file implementation. This implementation
|
||||
* is subclassable for testing purposes.
|
||||
*/
|
||||
public static class LogFile extends RandomAccessFile {
|
||||
|
||||
private final FileDescriptor fd;
|
||||
|
||||
/**
|
||||
* Constructs a LogFile and initializes the file descriptor.
|
||||
**/
|
||||
public LogFile(String name, String mode)
|
||||
throws FileNotFoundException, IOException
|
||||
{
|
||||
super(name, mode);
|
||||
this.fd = getFD();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes sync on the file descriptor for this log file.
|
||||
*/
|
||||
protected void sync() throws IOException {
|
||||
fd.sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if writing 4 bytes starting at the specified file
|
||||
* position, would span a 512 byte sector boundary; otherwise returns
|
||||
* false.
|
||||
**/
|
||||
protected boolean checkSpansBoundary(long fp) {
|
||||
return fp % 512 > 508;
|
||||
}
|
||||
}
|
||||
}
|
||||
562
jdkSrc/jdk8/sun/rmi/registry/RegistryImpl.java
Normal file
562
jdkSrc/jdk8/sun/rmi/registry/RegistryImpl.java
Normal file
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.registry;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.io.FilePermission;
|
||||
import java.net.*;
|
||||
import java.rmi.*;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.ServerNotActiveException;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.rmi.server.RMIClientSocketFactory;
|
||||
import java.rmi.server.RMIServerSocketFactory;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Policy;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.PermissionCollection;
|
||||
import java.security.Permissions;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.Security;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import sun.misc.ObjectInputFilter;
|
||||
|
||||
import sun.rmi.runtime.Log;
|
||||
import sun.rmi.server.UnicastRef;
|
||||
import sun.rmi.server.UnicastServerRef;
|
||||
import sun.rmi.server.UnicastServerRef2;
|
||||
import sun.rmi.transport.LiveRef;
|
||||
|
||||
/**
|
||||
* A "registry" exists on every node that allows RMI connections to
|
||||
* servers on that node. The registry on a particular node contains a
|
||||
* transient database that maps names to remote objects. When the
|
||||
* node boots, the registry database is empty. The names stored in the
|
||||
* registry are pure and are not parsed. A service storing itself in
|
||||
* the registry may want to prefix its name of the service by a package
|
||||
* name (although not required), to reduce name collisions in the
|
||||
* registry.
|
||||
*
|
||||
* The LocateRegistry class is used to obtain registry for different hosts.
|
||||
* <p>
|
||||
* The default RegistryImpl exported restricts access to clients on the local host
|
||||
* for the methods {@link #bind}, {@link #rebind}, {@link #unbind} by checking
|
||||
* the client host in the skeleton.
|
||||
*
|
||||
* @see java.rmi.registry.LocateRegistry
|
||||
*/
|
||||
public class RegistryImpl extends java.rmi.server.RemoteServer
|
||||
implements Registry
|
||||
{
|
||||
|
||||
/* indicate compatibility with JDK 1.1.x version of class */
|
||||
private static final long serialVersionUID = 4666870661827494597L;
|
||||
private Hashtable<String, Remote> bindings
|
||||
= new Hashtable<>(101);
|
||||
private static Hashtable<InetAddress, InetAddress> allowedAccessCache
|
||||
= new Hashtable<>(3);
|
||||
private static RegistryImpl registry;
|
||||
private static ObjID id = new ObjID(ObjID.REGISTRY_ID);
|
||||
|
||||
private static ResourceBundle resources = null;
|
||||
|
||||
/**
|
||||
* Property name of the RMI Registry serial filter to augment
|
||||
* the built-in list of allowed types.
|
||||
* Setting the property in the {@code lib/security/java.security} file
|
||||
* will enable the augmented filter.
|
||||
*/
|
||||
private static final String REGISTRY_FILTER_PROPNAME = "sun.rmi.registry.registryFilter";
|
||||
|
||||
/** Registry max depth of remote invocations. **/
|
||||
private static final int REGISTRY_MAX_DEPTH = 20;
|
||||
|
||||
/** Registry maximum array size in remote invocations. **/
|
||||
private static final int REGISTRY_MAX_ARRAY_SIZE = 1_000_000;
|
||||
|
||||
/**
|
||||
* The registryFilter created from the value of the {@code "sun.rmi.registry.registryFilter"}
|
||||
* property.
|
||||
*/
|
||||
private static final ObjectInputFilter registryFilter =
|
||||
AccessController.doPrivileged((PrivilegedAction<ObjectInputFilter>)RegistryImpl::initRegistryFilter);
|
||||
|
||||
/**
|
||||
* Initialize the registryFilter from the security properties or system property; if any
|
||||
* @return an ObjectInputFilter, or null
|
||||
*/
|
||||
private static ObjectInputFilter initRegistryFilter() {
|
||||
ObjectInputFilter filter = null;
|
||||
String props = System.getProperty(REGISTRY_FILTER_PROPNAME);
|
||||
if (props == null) {
|
||||
props = Security.getProperty(REGISTRY_FILTER_PROPNAME);
|
||||
}
|
||||
if (props != null) {
|
||||
filter = ObjectInputFilter.Config.createFilter2(props);
|
||||
Log regLog = Log.getLog("sun.rmi.registry", "registry", -1);
|
||||
if (regLog.isLoggable(Log.BRIEF)) {
|
||||
regLog.log(Log.BRIEF, "registryFilter = " + filter);
|
||||
}
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new RegistryImpl on the specified port with the
|
||||
* given custom socket factory pair.
|
||||
*/
|
||||
public RegistryImpl(int port,
|
||||
RMIClientSocketFactory csf,
|
||||
RMIServerSocketFactory ssf)
|
||||
throws RemoteException
|
||||
{
|
||||
this(port, csf, ssf, RegistryImpl::registryFilter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new RegistryImpl on the specified port with the
|
||||
* given custom socket factory pair and ObjectInputFilter.
|
||||
*/
|
||||
public RegistryImpl(int port,
|
||||
RMIClientSocketFactory csf,
|
||||
RMIServerSocketFactory ssf,
|
||||
ObjectInputFilter serialFilter)
|
||||
throws RemoteException
|
||||
{
|
||||
if (port == Registry.REGISTRY_PORT && System.getSecurityManager() != null) {
|
||||
// grant permission for default port only.
|
||||
try {
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
||||
public Void run() throws RemoteException {
|
||||
LiveRef lref = new LiveRef(id, port, csf, ssf);
|
||||
setup(new UnicastServerRef2(lref, serialFilter));
|
||||
return null;
|
||||
}
|
||||
}, null, new SocketPermission("localhost:"+port, "listen,accept"));
|
||||
} catch (PrivilegedActionException pae) {
|
||||
throw (RemoteException)pae.getException();
|
||||
}
|
||||
} else {
|
||||
LiveRef lref = new LiveRef(id, port, csf, ssf);
|
||||
setup(new UnicastServerRef2(lref, serialFilter));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new RegistryImpl on the specified port.
|
||||
*/
|
||||
public RegistryImpl(int port)
|
||||
throws RemoteException
|
||||
{
|
||||
if (port == Registry.REGISTRY_PORT && System.getSecurityManager() != null) {
|
||||
// grant permission for default port only.
|
||||
try {
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
||||
public Void run() throws RemoteException {
|
||||
LiveRef lref = new LiveRef(id, port);
|
||||
setup(new UnicastServerRef(lref, RegistryImpl::registryFilter));
|
||||
return null;
|
||||
}
|
||||
}, null, new SocketPermission("localhost:"+port, "listen,accept"));
|
||||
} catch (PrivilegedActionException pae) {
|
||||
throw (RemoteException)pae.getException();
|
||||
}
|
||||
} else {
|
||||
LiveRef lref = new LiveRef(id, port);
|
||||
setup(new UnicastServerRef(lref, RegistryImpl::registryFilter));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the export the object using the parameter
|
||||
* <code>uref</code>
|
||||
*/
|
||||
private void setup(UnicastServerRef uref)
|
||||
throws RemoteException
|
||||
{
|
||||
/* Server ref must be created and assigned before remote
|
||||
* object 'this' can be exported.
|
||||
*/
|
||||
ref = uref;
|
||||
uref.exportObject(this, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remote object for specified name in the registry.
|
||||
* @exception RemoteException If remote operation failed.
|
||||
* @exception NotBoundException If name is not currently bound.
|
||||
*/
|
||||
public Remote lookup(String name)
|
||||
throws RemoteException, NotBoundException
|
||||
{
|
||||
synchronized (bindings) {
|
||||
Remote obj = bindings.get(name);
|
||||
if (obj == null)
|
||||
throw new NotBoundException(name);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the name to the specified remote object.
|
||||
* @exception RemoteException If remote operation failed.
|
||||
* @exception AlreadyBoundException If name is already bound.
|
||||
*/
|
||||
public void bind(String name, Remote obj)
|
||||
throws RemoteException, AlreadyBoundException, AccessException
|
||||
{
|
||||
// The access check preventing remote access is done in the skeleton
|
||||
// and is not applicable to local access.
|
||||
synchronized (bindings) {
|
||||
Remote curr = bindings.get(name);
|
||||
if (curr != null)
|
||||
throw new AlreadyBoundException(name);
|
||||
bindings.put(name, obj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind the name.
|
||||
* @exception RemoteException If remote operation failed.
|
||||
* @exception NotBoundException If name is not currently bound.
|
||||
*/
|
||||
public void unbind(String name)
|
||||
throws RemoteException, NotBoundException, AccessException
|
||||
{
|
||||
// The access check preventing remote access is done in the skeleton
|
||||
// and is not applicable to local access.
|
||||
synchronized (bindings) {
|
||||
Remote obj = bindings.get(name);
|
||||
if (obj == null)
|
||||
throw new NotBoundException(name);
|
||||
bindings.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebind the name to a new object, replaces any existing binding.
|
||||
* @exception RemoteException If remote operation failed.
|
||||
*/
|
||||
public void rebind(String name, Remote obj)
|
||||
throws RemoteException, AccessException
|
||||
{
|
||||
// The access check preventing remote access is done in the skeleton
|
||||
// and is not applicable to local access.
|
||||
bindings.put(name, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an enumeration of the names in the registry.
|
||||
* @exception RemoteException If remote operation failed.
|
||||
*/
|
||||
public String[] list()
|
||||
throws RemoteException
|
||||
{
|
||||
String[] names;
|
||||
synchronized (bindings) {
|
||||
int i = bindings.size();
|
||||
names = new String[i];
|
||||
Enumeration<String> enum_ = bindings.keys();
|
||||
while ((--i) >= 0)
|
||||
names[i] = enum_.nextElement();
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the caller has access to perform indicated operation.
|
||||
* The client must be on same the same host as this server.
|
||||
*/
|
||||
public static void checkAccess(String op) throws AccessException {
|
||||
try {
|
||||
/*
|
||||
* Get client host that this registry operation was made from.
|
||||
*/
|
||||
final String clientHostName = getClientHost();
|
||||
InetAddress clientHost;
|
||||
|
||||
try {
|
||||
clientHost = java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedExceptionAction<InetAddress>() {
|
||||
public InetAddress run()
|
||||
throws java.net.UnknownHostException
|
||||
{
|
||||
return InetAddress.getByName(clientHostName);
|
||||
}
|
||||
});
|
||||
} catch (PrivilegedActionException pae) {
|
||||
throw (java.net.UnknownHostException) pae.getException();
|
||||
}
|
||||
|
||||
// if client not yet seen, make sure client allowed access
|
||||
if (allowedAccessCache.get(clientHost) == null) {
|
||||
|
||||
if (clientHost.isAnyLocalAddress()) {
|
||||
throw new AccessException(
|
||||
op + " disallowed; origin unknown");
|
||||
}
|
||||
|
||||
try {
|
||||
final InetAddress finalClientHost = clientHost;
|
||||
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedExceptionAction<Void>() {
|
||||
public Void run() throws java.io.IOException {
|
||||
/*
|
||||
* if a ServerSocket can be bound to the client's
|
||||
* address then that address must be local
|
||||
*/
|
||||
(new ServerSocket(0, 10, finalClientHost)).close();
|
||||
allowedAccessCache.put(finalClientHost,
|
||||
finalClientHost);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (PrivilegedActionException pae) {
|
||||
// must have been an IOException
|
||||
|
||||
throw new AccessException(
|
||||
op + " disallowed; origin " +
|
||||
clientHost + " is non-local host");
|
||||
}
|
||||
}
|
||||
} catch (ServerNotActiveException ex) {
|
||||
/*
|
||||
* Local call from this VM: allow access.
|
||||
*/
|
||||
} catch (java.net.UnknownHostException ex) {
|
||||
throw new AccessException(op + " disallowed; origin is unknown host");
|
||||
}
|
||||
}
|
||||
|
||||
public static ObjID getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves text resources from the locale-specific properties file.
|
||||
*/
|
||||
private static String getTextResource(String key) {
|
||||
if (resources == null) {
|
||||
try {
|
||||
resources = ResourceBundle.getBundle(
|
||||
"sun.rmi.registry.resources.rmiregistry");
|
||||
} catch (MissingResourceException mre) {
|
||||
}
|
||||
if (resources == null) {
|
||||
// throwing an Error is a bit extreme, methinks
|
||||
return ("[missing resource file: " + key + "]");
|
||||
}
|
||||
}
|
||||
|
||||
String val = null;
|
||||
try {
|
||||
val = resources.getString(key);
|
||||
} catch (MissingResourceException mre) {
|
||||
}
|
||||
|
||||
if (val == null) {
|
||||
return ("[missing resource: " + key + "]");
|
||||
} else {
|
||||
return (val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ObjectInputFilter to filter Registry input objects.
|
||||
* The list of acceptable classes is limited to classes normally
|
||||
* stored in a registry.
|
||||
*
|
||||
* @param filterInfo access to the class, array length, etc.
|
||||
* @return {@link ObjectInputFilter.Status#ALLOWED} if allowed,
|
||||
* {@link ObjectInputFilter.Status#REJECTED} if rejected,
|
||||
* otherwise {@link ObjectInputFilter.Status#UNDECIDED}
|
||||
*/
|
||||
private static ObjectInputFilter.Status registryFilter(ObjectInputFilter.FilterInfo filterInfo) {
|
||||
if (registryFilter != null) {
|
||||
ObjectInputFilter.Status status = registryFilter.checkInput(filterInfo);
|
||||
if (status != ObjectInputFilter.Status.UNDECIDED) {
|
||||
// The Registry filter can override the built-in white-list
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (filterInfo.depth() > REGISTRY_MAX_DEPTH) {
|
||||
return ObjectInputFilter.Status.REJECTED;
|
||||
}
|
||||
Class<?> clazz = filterInfo.serialClass();
|
||||
if (clazz != null) {
|
||||
if (clazz.isArray()) {
|
||||
// Arrays are REJECTED only if they exceed the limit
|
||||
return (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > REGISTRY_MAX_ARRAY_SIZE)
|
||||
? ObjectInputFilter.Status.REJECTED
|
||||
: ObjectInputFilter.Status.UNDECIDED;
|
||||
}
|
||||
if (String.class == clazz
|
||||
|| java.lang.Number.class.isAssignableFrom(clazz)
|
||||
|| Remote.class.isAssignableFrom(clazz)
|
||||
|| java.lang.reflect.Proxy.class.isAssignableFrom(clazz)
|
||||
|| UnicastRef.class.isAssignableFrom(clazz)
|
||||
|| RMIClientSocketFactory.class.isAssignableFrom(clazz)
|
||||
|| RMIServerSocketFactory.class.isAssignableFrom(clazz)
|
||||
|| java.rmi.activation.ActivationID.class.isAssignableFrom(clazz)
|
||||
|| java.rmi.server.UID.class.isAssignableFrom(clazz)) {
|
||||
return ObjectInputFilter.Status.ALLOWED;
|
||||
} else {
|
||||
return ObjectInputFilter.Status.REJECTED;
|
||||
}
|
||||
}
|
||||
return ObjectInputFilter.Status.UNDECIDED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main program to start a registry. <br>
|
||||
* The port number can be specified on the command line.
|
||||
*/
|
||||
public static void main(String args[])
|
||||
{
|
||||
// Create and install the security manager if one is not installed
|
||||
// already.
|
||||
if (System.getSecurityManager() == null) {
|
||||
System.setSecurityManager(new RMISecurityManager());
|
||||
}
|
||||
|
||||
try {
|
||||
/*
|
||||
* Fix bugid 4147561: When JDK tools are executed, the value of
|
||||
* the CLASSPATH environment variable for the shell in which they
|
||||
* were invoked is no longer incorporated into the application
|
||||
* class path; CLASSPATH's only effect is to be the value of the
|
||||
* system property "env.class.path". To preserve the previous
|
||||
* (JDK1.1 and JDK1.2beta3) behavior of this tool, however, its
|
||||
* CLASSPATH should still be considered when resolving classes
|
||||
* being unmarshalled. To effect this old behavior, a class
|
||||
* loader that loads from the file path specified in the
|
||||
* "env.class.path" property is created and set to be the context
|
||||
* class loader before the remote object is exported.
|
||||
*/
|
||||
String envcp = System.getProperty("env.class.path");
|
||||
if (envcp == null) {
|
||||
envcp = "."; // preserve old default behavior
|
||||
}
|
||||
URL[] urls = sun.misc.URLClassPath.pathToURLs(envcp);
|
||||
ClassLoader cl = new URLClassLoader(urls);
|
||||
|
||||
/*
|
||||
* Fix bugid 4242317: Classes defined by this class loader should
|
||||
* be annotated with the value of the "java.rmi.server.codebase"
|
||||
* property, not the "file:" URLs for the CLASSPATH elements.
|
||||
*/
|
||||
sun.rmi.server.LoaderHandler.registerCodebaseLoader(cl);
|
||||
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
|
||||
final int regPort = (args.length >= 1) ? Integer.parseInt(args[0])
|
||||
: Registry.REGISTRY_PORT;
|
||||
try {
|
||||
registry = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<RegistryImpl>() {
|
||||
public RegistryImpl run() throws RemoteException {
|
||||
return new RegistryImpl(regPort);
|
||||
}
|
||||
}, getAccessControlContext(regPort));
|
||||
} catch (PrivilegedActionException ex) {
|
||||
throw (RemoteException) ex.getException();
|
||||
}
|
||||
|
||||
// prevent registry from exiting
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println(MessageFormat.format(
|
||||
getTextResource("rmiregistry.port.badnumber"),
|
||||
args[0] ));
|
||||
System.err.println(MessageFormat.format(
|
||||
getTextResource("rmiregistry.usage"),
|
||||
"rmiregistry" ));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an AccessControlContext with minimal permissions.
|
||||
* The approach used here is taken from the similar method
|
||||
* getAccessControlContext() in the sun.applet.AppletPanel class.
|
||||
*/
|
||||
private static AccessControlContext getAccessControlContext(int port) {
|
||||
// begin with permissions granted to all code in current policy
|
||||
PermissionCollection perms = AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<PermissionCollection>() {
|
||||
public PermissionCollection run() {
|
||||
CodeSource codesource = new CodeSource(null,
|
||||
(java.security.cert.Certificate[]) null);
|
||||
Policy p = java.security.Policy.getPolicy();
|
||||
if (p != null) {
|
||||
return p.getPermissions(codesource);
|
||||
} else {
|
||||
return new Permissions();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Anyone can connect to the registry and the registry can connect
|
||||
* to and possibly download stubs from anywhere. Downloaded stubs and
|
||||
* related classes themselves are more tightly limited by RMI.
|
||||
*/
|
||||
perms.add(new SocketPermission("*", "connect,accept"));
|
||||
perms.add(new SocketPermission("localhost:"+port, "listen,accept"));
|
||||
|
||||
perms.add(new RuntimePermission("accessClassInPackage.sun.jvmstat.*"));
|
||||
perms.add(new RuntimePermission("accessClassInPackage.sun.jvm.hotspot.*"));
|
||||
|
||||
perms.add(new FilePermission("<<ALL FILES>>", "read"));
|
||||
|
||||
/*
|
||||
* Create an AccessControlContext that consists of a single
|
||||
* protection domain with only the permissions calculated above.
|
||||
*/
|
||||
ProtectionDomain pd = new ProtectionDomain(
|
||||
new CodeSource(null,
|
||||
(java.security.cert.Certificate[]) null), perms);
|
||||
return new AccessControlContext(new ProtectionDomain[] { pd });
|
||||
}
|
||||
}
|
||||
199
jdkSrc/jdk8/sun/rmi/registry/RegistryImpl_Skel.java
Normal file
199
jdkSrc/jdk8/sun/rmi/registry/RegistryImpl_Skel.java
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package sun.rmi.registry;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
|
||||
import sun.misc.SharedSecrets;
|
||||
import sun.rmi.transport.StreamRemoteCall;
|
||||
|
||||
/**
|
||||
* Skeleton to dispatch RegistryImpl methods.
|
||||
* Originally generated by RMIC but frozen to match the stubs.
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "serial"})
|
||||
public final class RegistryImpl_Skel
|
||||
implements java.rmi.server.Skeleton {
|
||||
private static final java.rmi.server.Operation[] operations = {
|
||||
new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote)"),
|
||||
new java.rmi.server.Operation("java.lang.String list()[]"),
|
||||
new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String)"),
|
||||
new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote)"),
|
||||
new java.rmi.server.Operation("void unbind(java.lang.String)")
|
||||
};
|
||||
|
||||
private static final long interfaceHash = 4905912898345647071L;
|
||||
|
||||
public java.rmi.server.Operation[] getOperations() {
|
||||
return operations.clone();
|
||||
}
|
||||
|
||||
public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall remoteCall, int opnum, long hash)
|
||||
throws java.lang.Exception {
|
||||
if (opnum < 0) {
|
||||
if (hash == 7583982177005850366L) {
|
||||
opnum = 0;
|
||||
} else if (hash == 2571371476350237748L) {
|
||||
opnum = 1;
|
||||
} else if (hash == -7538657168040752697L) {
|
||||
opnum = 2;
|
||||
} else if (hash == -8381844669958460146L) {
|
||||
opnum = 3;
|
||||
} else if (hash == 7305022919901907578L) {
|
||||
opnum = 4;
|
||||
} else {
|
||||
throw new java.rmi.UnmarshalException("invalid method hash");
|
||||
}
|
||||
} else {
|
||||
if (hash != interfaceHash)
|
||||
throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch");
|
||||
}
|
||||
|
||||
sun.rmi.registry.RegistryImpl server = (sun.rmi.registry.RegistryImpl) obj;
|
||||
StreamRemoteCall call = (StreamRemoteCall) remoteCall;
|
||||
switch (opnum) {
|
||||
case 0: // bind(String, Remote)
|
||||
{
|
||||
// Check access before reading the arguments
|
||||
RegistryImpl.checkAccess("Registry.bind");
|
||||
|
||||
java.lang.String $param_String_1;
|
||||
java.rmi.Remote $param_Remote_2;
|
||||
try {
|
||||
ObjectInputStream in = (ObjectInputStream)call.getInputStream();
|
||||
$param_String_1 =
|
||||
SharedSecrets.getJavaObjectInputStreamReadString().readString(in);
|
||||
$param_Remote_2 = (java.rmi.Remote) in.readObject();
|
||||
} catch (ClassCastException | IOException | ClassNotFoundException e) {
|
||||
call.discardPendingRefs();
|
||||
throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
|
||||
} finally {
|
||||
call.releaseInputStream();
|
||||
}
|
||||
server.bind($param_String_1, $param_Remote_2);
|
||||
try {
|
||||
call.getResultStream(true);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling return", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: // list()
|
||||
{
|
||||
call.releaseInputStream();
|
||||
java.lang.String[] $result = server.list();
|
||||
try {
|
||||
java.io.ObjectOutput out = call.getResultStream(true);
|
||||
out.writeObject($result);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling return", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: // lookup(String)
|
||||
{
|
||||
java.lang.String $param_String_1;
|
||||
try {
|
||||
ObjectInputStream in = (ObjectInputStream)call.getInputStream();
|
||||
$param_String_1 =
|
||||
SharedSecrets.getJavaObjectInputStreamReadString().readString(in);
|
||||
} catch (ClassCastException | IOException e) {
|
||||
call.discardPendingRefs();
|
||||
throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
|
||||
} finally {
|
||||
call.releaseInputStream();
|
||||
}
|
||||
java.rmi.Remote $result = server.lookup($param_String_1);
|
||||
try {
|
||||
java.io.ObjectOutput out = call.getResultStream(true);
|
||||
out.writeObject($result);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling return", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: // rebind(String, Remote)
|
||||
{
|
||||
// Check access before reading the arguments
|
||||
RegistryImpl.checkAccess("Registry.rebind");
|
||||
|
||||
java.lang.String $param_String_1;
|
||||
java.rmi.Remote $param_Remote_2;
|
||||
try {
|
||||
ObjectInputStream in = (ObjectInputStream)call.getInputStream();
|
||||
$param_String_1 =
|
||||
SharedSecrets.getJavaObjectInputStreamReadString().readString(in);
|
||||
$param_Remote_2 = (java.rmi.Remote) in.readObject();
|
||||
} catch (ClassCastException | IOException | java.lang.ClassNotFoundException e) {
|
||||
call.discardPendingRefs();
|
||||
throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
|
||||
} finally {
|
||||
call.releaseInputStream();
|
||||
}
|
||||
server.rebind($param_String_1, $param_Remote_2);
|
||||
try {
|
||||
call.getResultStream(true);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling return", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // unbind(String)
|
||||
{
|
||||
// Check access before reading the arguments
|
||||
RegistryImpl.checkAccess("Registry.unbind");
|
||||
|
||||
java.lang.String $param_String_1;
|
||||
try {
|
||||
ObjectInputStream in = (ObjectInputStream)call.getInputStream();
|
||||
$param_String_1 =
|
||||
SharedSecrets.getJavaObjectInputStreamReadString().readString(in);
|
||||
} catch (ClassCastException | IOException e) {
|
||||
call.discardPendingRefs();
|
||||
throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
|
||||
} finally {
|
||||
call.releaseInputStream();
|
||||
}
|
||||
server.unbind($param_String_1);
|
||||
try {
|
||||
call.getResultStream(true);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling return", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new java.rmi.UnmarshalException("invalid method number");
|
||||
}
|
||||
}
|
||||
}
|
||||
192
jdkSrc/jdk8/sun/rmi/registry/RegistryImpl_Stub.java
Normal file
192
jdkSrc/jdk8/sun/rmi/registry/RegistryImpl_Stub.java
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.registry;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import sun.rmi.transport.StreamRemoteCall;
|
||||
|
||||
/**
|
||||
* Stubs to invoke RegistryImpl remote methods.
|
||||
* Originally generated from RMIC but frozen to match RegistryImpl_Skel.
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "serial"})
|
||||
public final class RegistryImpl_Stub
|
||||
extends java.rmi.server.RemoteStub
|
||||
implements java.rmi.registry.Registry, java.rmi.Remote {
|
||||
private static final java.rmi.server.Operation[] operations = {
|
||||
new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote)"),
|
||||
new java.rmi.server.Operation("java.lang.String list()[]"),
|
||||
new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String)"),
|
||||
new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote)"),
|
||||
new java.rmi.server.Operation("void unbind(java.lang.String)")
|
||||
};
|
||||
|
||||
private static final long interfaceHash = 4905912898345647071L;
|
||||
|
||||
// constructors
|
||||
public RegistryImpl_Stub() {
|
||||
super();
|
||||
}
|
||||
|
||||
public RegistryImpl_Stub(java.rmi.server.RemoteRef ref) {
|
||||
super(ref);
|
||||
}
|
||||
|
||||
// methods from remote interfaces
|
||||
|
||||
// implementation of bind(String, Remote)
|
||||
public void bind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
|
||||
throws java.rmi.AccessException, java.rmi.AlreadyBoundException, java.rmi.RemoteException {
|
||||
try {
|
||||
StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 0, interfaceHash);
|
||||
try {
|
||||
java.io.ObjectOutput out = call.getOutputStream();
|
||||
out.writeObject($param_String_1);
|
||||
out.writeObject($param_Remote_2);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling arguments", e);
|
||||
}
|
||||
ref.invoke(call);
|
||||
ref.done(call);
|
||||
} catch (java.lang.RuntimeException e) {
|
||||
throw e;
|
||||
} catch (java.rmi.RemoteException e) {
|
||||
throw e;
|
||||
} catch (java.rmi.AlreadyBoundException e) {
|
||||
throw e;
|
||||
} catch (java.lang.Exception e) {
|
||||
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
// implementation of list()
|
||||
public java.lang.String[] list()
|
||||
throws java.rmi.AccessException, java.rmi.RemoteException {
|
||||
try {
|
||||
StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 1, interfaceHash);
|
||||
ref.invoke(call);
|
||||
java.lang.String[] $result;
|
||||
try {
|
||||
java.io.ObjectInput in = call.getInputStream();
|
||||
$result = (java.lang.String[]) in.readObject();
|
||||
} catch (ClassCastException | IOException | ClassNotFoundException e) {
|
||||
call.discardPendingRefs();
|
||||
throw new java.rmi.UnmarshalException("error unmarshalling return", e);
|
||||
} finally {
|
||||
ref.done(call);
|
||||
}
|
||||
return $result;
|
||||
} catch (java.lang.RuntimeException e) {
|
||||
throw e;
|
||||
} catch (java.rmi.RemoteException e) {
|
||||
throw e;
|
||||
} catch (java.lang.Exception e) {
|
||||
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
// implementation of lookup(String)
|
||||
public java.rmi.Remote lookup(java.lang.String $param_String_1)
|
||||
throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException {
|
||||
try {
|
||||
StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 2, interfaceHash);
|
||||
try {
|
||||
java.io.ObjectOutput out = call.getOutputStream();
|
||||
out.writeObject($param_String_1);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling arguments", e);
|
||||
}
|
||||
ref.invoke(call);
|
||||
java.rmi.Remote $result;
|
||||
try {
|
||||
java.io.ObjectInput in = call.getInputStream();
|
||||
$result = (java.rmi.Remote) in.readObject();
|
||||
} catch (ClassCastException | IOException | ClassNotFoundException e) {
|
||||
call.discardPendingRefs();
|
||||
throw new java.rmi.UnmarshalException("error unmarshalling return", e);
|
||||
} finally {
|
||||
ref.done(call);
|
||||
}
|
||||
return $result;
|
||||
} catch (java.lang.RuntimeException e) {
|
||||
throw e;
|
||||
} catch (java.rmi.RemoteException e) {
|
||||
throw e;
|
||||
} catch (java.rmi.NotBoundException e) {
|
||||
throw e;
|
||||
} catch (java.lang.Exception e) {
|
||||
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
// implementation of rebind(String, Remote)
|
||||
public void rebind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
|
||||
throws java.rmi.AccessException, java.rmi.RemoteException {
|
||||
try {
|
||||
StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 3, interfaceHash);
|
||||
try {
|
||||
java.io.ObjectOutput out = call.getOutputStream();
|
||||
out.writeObject($param_String_1);
|
||||
out.writeObject($param_Remote_2);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling arguments", e);
|
||||
}
|
||||
ref.invoke(call);
|
||||
ref.done(call);
|
||||
} catch (java.lang.RuntimeException e) {
|
||||
throw e;
|
||||
} catch (java.rmi.RemoteException e) {
|
||||
throw e;
|
||||
} catch (java.lang.Exception e) {
|
||||
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
// implementation of unbind(String)
|
||||
public void unbind(java.lang.String $param_String_1)
|
||||
throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException {
|
||||
try {
|
||||
StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 4, interfaceHash);
|
||||
try {
|
||||
java.io.ObjectOutput out = call.getOutputStream();
|
||||
out.writeObject($param_String_1);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling arguments", e);
|
||||
}
|
||||
ref.invoke(call);
|
||||
ref.done(call);
|
||||
} catch (java.lang.RuntimeException e) {
|
||||
throw e;
|
||||
} catch (java.rmi.RemoteException e) {
|
||||
throw e;
|
||||
} catch (java.rmi.NotBoundException e) {
|
||||
throw e;
|
||||
} catch (java.lang.Exception e) {
|
||||
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
445
jdkSrc/jdk8/sun/rmi/rmic/BatchEnvironment.java
Normal file
445
jdkSrc/jdk8/sun/rmi/rmic/BatchEnvironment.java
Normal file
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Copyright (c) IBM Corporation 1998 */
|
||||
/* */
|
||||
/* (C) Copyright IBM Corp. 1998 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
package sun.rmi.rmic;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.jar.Attributes;
|
||||
import sun.tools.java.ClassPath;
|
||||
|
||||
/**
|
||||
* BatchEnvironment for rmic extends javac's version in four ways:
|
||||
* 1. It overrides errorString() to handle looking for rmic-specific
|
||||
* error messages in rmic's resource bundle
|
||||
* 2. It provides a mechanism for recording intermediate generated
|
||||
* files so that they can be deleted later.
|
||||
* 3. It holds a reference to the Main instance so that generators
|
||||
* can refer to it.
|
||||
* 4. It provides access to the ClassPath passed to the constructor.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*/
|
||||
|
||||
public class BatchEnvironment extends sun.tools.javac.BatchEnvironment {
|
||||
|
||||
/** instance of Main which created this environment */
|
||||
private Main main;
|
||||
|
||||
/**
|
||||
* Create a ClassPath object for rmic from a class path string.
|
||||
*/
|
||||
public static ClassPath createClassPath(String classPathString) {
|
||||
ClassPath[] paths = classPaths(null, classPathString, null, null);
|
||||
return paths[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ClassPath object for rmic from the relevant command line
|
||||
* options for class path, boot class path, and extension directories.
|
||||
*/
|
||||
public static ClassPath createClassPath(String classPathString,
|
||||
String sysClassPathString,
|
||||
String extDirsString)
|
||||
{
|
||||
/**
|
||||
* Previously, this method delegated to the
|
||||
* sun.tools.javac.BatchEnvironment.classPaths method in order
|
||||
* to supply default values for paths not specified on the
|
||||
* command line, expand extensions directories into specific
|
||||
* JAR files, and construct the ClassPath object-- but as part
|
||||
* of the fix for 6473331, which adds support for Class-Path
|
||||
* manifest entries in JAR files, those steps are now handled
|
||||
* here directly, with the help of a Path utility class copied
|
||||
* from the new javac implementation (see below).
|
||||
*/
|
||||
Path path = new Path();
|
||||
|
||||
if (sysClassPathString == null) {
|
||||
sysClassPathString = System.getProperty("sun.boot.class.path");
|
||||
}
|
||||
if (sysClassPathString != null) {
|
||||
path.addFiles(sysClassPathString);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class-Path manifest entries are supported for JAR files
|
||||
* everywhere except in the boot class path.
|
||||
*/
|
||||
path.expandJarClassPaths(true);
|
||||
|
||||
if (extDirsString == null) {
|
||||
extDirsString = System.getProperty("java.ext.dirs");
|
||||
}
|
||||
if (extDirsString != null) {
|
||||
path.addDirectories(extDirsString);
|
||||
}
|
||||
|
||||
/*
|
||||
* In the application class path, an empty element means
|
||||
* the current working directory.
|
||||
*/
|
||||
path.emptyPathDefault(".");
|
||||
|
||||
if (classPathString == null) {
|
||||
// The env.class.path property is the user's CLASSPATH
|
||||
// environment variable, and it set by the wrapper (ie,
|
||||
// javac.exe).
|
||||
classPathString = System.getProperty("env.class.path");
|
||||
if (classPathString == null) {
|
||||
classPathString = ".";
|
||||
}
|
||||
}
|
||||
path.addFiles(classPathString);
|
||||
|
||||
return new ClassPath(path.toArray(new String[path.size()]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a BatchEnvironment for rmic with the given class path,
|
||||
* stream for messages and Main.
|
||||
*/
|
||||
public BatchEnvironment(OutputStream out, ClassPath path, Main main) {
|
||||
super(out, new ClassPath(""), path);
|
||||
// use empty "sourcePath" (see 4666958)
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instance of Main which created this environment.
|
||||
*/
|
||||
public Main getMain() {
|
||||
return main;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ClassPath.
|
||||
*/
|
||||
public ClassPath getClassPath() {
|
||||
return binaryPath;
|
||||
}
|
||||
|
||||
/** list of generated source files created in this environment */
|
||||
private Vector<File> generatedFiles = new Vector<>();
|
||||
|
||||
/**
|
||||
* Remember a generated source file generated so that it
|
||||
* can be removed later, if appropriate.
|
||||
*/
|
||||
public void addGeneratedFile(File file) {
|
||||
generatedFiles.addElement(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the generated source files made during the execution
|
||||
* of this environment (those that have been registered with the
|
||||
* "addGeneratedFile" method).
|
||||
*/
|
||||
public void deleteGeneratedFiles() {
|
||||
synchronized(generatedFiles) {
|
||||
Enumeration<File> enumeration = generatedFiles.elements();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
File file = enumeration.nextElement();
|
||||
file.delete();
|
||||
}
|
||||
generatedFiles.removeAllElements();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release resources, if any.
|
||||
*/
|
||||
public void shutdown() {
|
||||
main = null;
|
||||
generatedFiles = null;
|
||||
super.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the formatted, localized string for a named error message
|
||||
* and supplied arguments. For rmic error messages, with names that
|
||||
* being with "rmic.", look up the error message in rmic's resource
|
||||
* bundle; otherwise, defer to java's superclass method.
|
||||
*/
|
||||
public String errorString(String err,
|
||||
Object arg0, Object arg1, Object arg2)
|
||||
{
|
||||
if (err.startsWith("rmic.") || err.startsWith("warn.rmic.")) {
|
||||
String result = Main.getText(err,
|
||||
(arg0 != null ? arg0.toString() : null),
|
||||
(arg1 != null ? arg1.toString() : null),
|
||||
(arg2 != null ? arg2.toString() : null));
|
||||
|
||||
if (err.startsWith("warn.")) {
|
||||
result = "warning: " + result;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return super.errorString(err, arg0, arg1, arg2);
|
||||
}
|
||||
}
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility for building paths of directories and JAR files. This
|
||||
* class was copied from com.sun.tools.javac.util.Paths as part of
|
||||
* the fix for 6473331, which adds support for Class-Path manifest
|
||||
* entries in JAR files. Diagnostic code is simply commented out
|
||||
* because rmic silently ignored these conditions historically.
|
||||
*/
|
||||
private static class Path extends LinkedHashSet<String> {
|
||||
private static final long serialVersionUID = 0;
|
||||
private static final boolean warn = false;
|
||||
|
||||
private static class PathIterator implements Collection<String> {
|
||||
private int pos = 0;
|
||||
private final String path;
|
||||
private final String emptyPathDefault;
|
||||
|
||||
public PathIterator(String path, String emptyPathDefault) {
|
||||
this.path = path;
|
||||
this.emptyPathDefault = emptyPathDefault;
|
||||
}
|
||||
public PathIterator(String path) { this(path, null); }
|
||||
public Iterator<String> iterator() {
|
||||
return new Iterator<String>() {
|
||||
public boolean hasNext() {
|
||||
return pos <= path.length();
|
||||
}
|
||||
public String next() {
|
||||
int beg = pos;
|
||||
int end = path.indexOf(File.pathSeparator, beg);
|
||||
if (end == -1)
|
||||
end = path.length();
|
||||
pos = end + 1;
|
||||
|
||||
if (beg == end && emptyPathDefault != null)
|
||||
return emptyPathDefault;
|
||||
else
|
||||
return path.substring(beg, end);
|
||||
}
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// required for Collection.
|
||||
public int size() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public boolean isEmpty() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public boolean contains(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public Object[] toArray() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public <T> T[] toArray(T[] a) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public boolean add(String o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public boolean remove(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public boolean addAll(Collection<? extends String> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public boolean equals(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public int hashCode() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/** Is this the name of a zip file? */
|
||||
private static boolean isZip(String name) {
|
||||
return new File(name).isFile();
|
||||
}
|
||||
|
||||
private boolean expandJarClassPaths = false;
|
||||
|
||||
public Path expandJarClassPaths(boolean x) {
|
||||
expandJarClassPaths = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** What to use when path element is the empty string */
|
||||
private String emptyPathDefault = null;
|
||||
|
||||
public Path emptyPathDefault(String x) {
|
||||
emptyPathDefault = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Path() { super(); }
|
||||
|
||||
public Path addDirectories(String dirs, boolean warn) {
|
||||
if (dirs != null)
|
||||
for (String dir : new PathIterator(dirs))
|
||||
addDirectory(dir, warn);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Path addDirectories(String dirs) {
|
||||
return addDirectories(dirs, warn);
|
||||
}
|
||||
|
||||
private void addDirectory(String dir, boolean warn) {
|
||||
if (! new File(dir).isDirectory()) {
|
||||
// if (warn)
|
||||
// log.warning(Position.NOPOS,
|
||||
// "dir.path.element.not.found", dir);
|
||||
return;
|
||||
}
|
||||
|
||||
for (String direntry : new File(dir).list()) {
|
||||
String canonicalized = direntry.toLowerCase();
|
||||
if (canonicalized.endsWith(".jar") ||
|
||||
canonicalized.endsWith(".zip"))
|
||||
addFile(dir + File.separator + direntry, warn);
|
||||
}
|
||||
}
|
||||
|
||||
public Path addFiles(String files, boolean warn) {
|
||||
if (files != null)
|
||||
for (String file : new PathIterator(files, emptyPathDefault))
|
||||
addFile(file, warn);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Path addFiles(String files) {
|
||||
return addFiles(files, warn);
|
||||
}
|
||||
|
||||
private void addFile(String file, boolean warn) {
|
||||
if (contains(file)) {
|
||||
/* Discard duplicates and avoid infinite recursion */
|
||||
return;
|
||||
}
|
||||
|
||||
File ele = new File(file);
|
||||
if (! ele.exists()) {
|
||||
/* No such file or directory exist */
|
||||
if (warn)
|
||||
// log.warning(Position.NOPOS,
|
||||
// "path.element.not.found", file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ele.isFile()) {
|
||||
/* File is an ordinay file */
|
||||
String arcname = file.toLowerCase();
|
||||
if (! (arcname.endsWith(".zip") ||
|
||||
arcname.endsWith(".jar"))) {
|
||||
/* File name don't have right extension */
|
||||
// if (warn)
|
||||
// log.warning(Position.NOPOS,
|
||||
// "invalid.archive.file", file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now what we have left is either a directory or a file name
|
||||
confirming to archive naming convention */
|
||||
|
||||
super.add(file);
|
||||
if (expandJarClassPaths && isZip(file))
|
||||
addJarClassPath(file, warn);
|
||||
}
|
||||
|
||||
// Adds referenced classpath elements from a jar's Class-Path
|
||||
// Manifest entry. In some future release, we may want to
|
||||
// update this code to recognize URLs rather than simple
|
||||
// filenames, but if we do, we should redo all path-related code.
|
||||
private void addJarClassPath(String jarFileName, boolean warn) {
|
||||
try {
|
||||
String jarParent = new File(jarFileName).getParent();
|
||||
JarFile jar = new JarFile(jarFileName);
|
||||
|
||||
try {
|
||||
Manifest man = jar.getManifest();
|
||||
if (man == null) return;
|
||||
|
||||
Attributes attr = man.getMainAttributes();
|
||||
if (attr == null) return;
|
||||
|
||||
String path = attr.getValue(Attributes.Name.CLASS_PATH);
|
||||
if (path == null) return;
|
||||
|
||||
for (StringTokenizer st = new StringTokenizer(path);
|
||||
st.hasMoreTokens();) {
|
||||
String elt = st.nextToken();
|
||||
if (jarParent != null)
|
||||
elt = new File(jarParent, elt).getCanonicalPath();
|
||||
addFile(elt, warn);
|
||||
}
|
||||
} finally {
|
||||
jar.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// log.error(Position.NOPOS,
|
||||
// "error.reading.file", jarFileName,
|
||||
// e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
jdkSrc/jdk8/sun/rmi/rmic/Constants.java
Normal file
44
jdkSrc/jdk8/sun/rmi/rmic/Constants.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic;
|
||||
|
||||
import sun.tools.java.Identifier;
|
||||
|
||||
/**
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*/
|
||||
public interface Constants extends sun.tools.java.Constants {
|
||||
|
||||
/*
|
||||
* Identifiers potentially useful for all Generators
|
||||
*/
|
||||
public static final Identifier idRemote =
|
||||
Identifier.lookup("java.rmi.Remote");
|
||||
public static final Identifier idRemoteException =
|
||||
Identifier.lookup("java.rmi.RemoteException");
|
||||
}
|
||||
79
jdkSrc/jdk8/sun/rmi/rmic/Generator.java
Normal file
79
jdkSrc/jdk8/sun/rmi/rmic/Generator.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic;
|
||||
|
||||
import java.io.File;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
|
||||
/**
|
||||
* Generator defines the protocol for back-end implementations to be added
|
||||
* to rmic. See the rmic.properties file for a description of the format for
|
||||
* adding new Generators to rmic.
|
||||
* <p>
|
||||
* Classes implementing this interface must have a public default constructor
|
||||
* which should set any required arguments to their defaults. When Main
|
||||
* encounters a command line argument which maps to a specific Generator
|
||||
* subclass, it will instantiate one and call parseArgs(...). At some later
|
||||
* point, Main will invoke the generate(...) method once for _each_ class passed
|
||||
* on the command line.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public interface Generator {
|
||||
|
||||
/**
|
||||
* Examine and consume command line arguments.
|
||||
* @param argv The command line arguments. Ignore null
|
||||
* and unknown arguments. Set each consumed argument to null.
|
||||
* @param main Report any errors using the main.error() methods.
|
||||
* @return true if no errors, false otherwise.
|
||||
*/
|
||||
public boolean parseArgs(String argv[], Main main);
|
||||
|
||||
/**
|
||||
* Generate output. Any source files created which need compilation should
|
||||
* be added to the compiler environment using the addGeneratedFile(File)
|
||||
* method.
|
||||
*
|
||||
* @param env The compiler environment
|
||||
* @param cdef The definition for the implementation class or interface from
|
||||
* which to generate output
|
||||
* @param destDir The directory for the root of the package hierarchy
|
||||
* for generated files. May be null.
|
||||
*/
|
||||
public void generate(BatchEnvironment env, ClassDefinition cdef, File destDir);
|
||||
}
|
||||
299
jdkSrc/jdk8/sun/rmi/rmic/IndentingWriter.java
Normal file
299
jdkSrc/jdk8/sun/rmi/rmic/IndentingWriter.java
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Copyright (c) IBM Corporation 1998 */
|
||||
/* */
|
||||
/* (C) Copyright IBM Corp. 1998 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
package sun.rmi.rmic;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* IndentingWriter is a BufferedWriter subclass that supports automatic
|
||||
* indentation of lines of text written to the underlying Writer.
|
||||
*
|
||||
* Methods are provided for compact, convenient indenting, writing text,
|
||||
* and writing lines in various combinations.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*/
|
||||
public class IndentingWriter extends BufferedWriter {
|
||||
|
||||
/** true if the next character written is the first on a line */
|
||||
private boolean beginningOfLine = true;
|
||||
|
||||
/** current number of spaces to prepend to lines */
|
||||
private int currentIndent = 0;
|
||||
|
||||
/** number of spaces to change indent when indenting in or out */
|
||||
private int indentStep = 4;
|
||||
|
||||
/** number of spaces to convert into tabs. Use MAX_VALUE to disable */
|
||||
private int tabSize = 8;
|
||||
|
||||
/**
|
||||
* Create a new IndentingWriter that writes indented text to the
|
||||
* given Writer. Use the default indent step of four spaces.
|
||||
*/
|
||||
public IndentingWriter(Writer out) {
|
||||
super(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new IndentingWriter that writes indented text to the
|
||||
* given Writer and uses the supplied indent step.
|
||||
*/
|
||||
public IndentingWriter(Writer out, int step) {
|
||||
this(out);
|
||||
|
||||
if (indentStep < 0)
|
||||
throw new IllegalArgumentException("negative indent step");
|
||||
|
||||
indentStep = step;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new IndentingWriter that writes indented text to the
|
||||
* given Writer and uses the supplied indent step and tab size.
|
||||
*/
|
||||
public IndentingWriter(Writer out, int step, int tabSize) {
|
||||
this(out);
|
||||
|
||||
if (indentStep < 0)
|
||||
throw new IllegalArgumentException("negative indent step");
|
||||
|
||||
indentStep = step;
|
||||
this.tabSize = tabSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a single character.
|
||||
*/
|
||||
public void write(int c) throws IOException {
|
||||
checkWrite();
|
||||
super.write(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a portion of an array of characters.
|
||||
*/
|
||||
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||
if (len > 0) {
|
||||
checkWrite();
|
||||
}
|
||||
super.write(cbuf, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a portion of a String.
|
||||
*/
|
||||
public void write(String s, int off, int len) throws IOException {
|
||||
if (len > 0) {
|
||||
checkWrite();
|
||||
}
|
||||
super.write(s, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a line separator. The next character written will be
|
||||
* preceded by an indent.
|
||||
*/
|
||||
public void newLine() throws IOException {
|
||||
super.newLine();
|
||||
beginningOfLine = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an indent needs to be written before writing the next
|
||||
* character.
|
||||
*
|
||||
* The indent generation is optimized (and made consistent with
|
||||
* certain coding conventions) by condensing groups of eight spaces
|
||||
* into tab characters.
|
||||
*/
|
||||
protected void checkWrite() throws IOException {
|
||||
if (beginningOfLine) {
|
||||
beginningOfLine = false;
|
||||
int i = currentIndent;
|
||||
while (i >= tabSize) {
|
||||
super.write('\t');
|
||||
i -= tabSize;
|
||||
}
|
||||
while (i > 0) {
|
||||
super.write(' ');
|
||||
-- i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the current indent by the indent step.
|
||||
*/
|
||||
protected void indentIn() {
|
||||
currentIndent += indentStep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease the current indent by the indent step.
|
||||
*/
|
||||
protected void indentOut() {
|
||||
currentIndent -= indentStep;
|
||||
if (currentIndent < 0)
|
||||
currentIndent = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent in.
|
||||
*/
|
||||
public void pI() {
|
||||
indentIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent out.
|
||||
*/
|
||||
public void pO() {
|
||||
indentOut();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write string.
|
||||
*/
|
||||
public void p(String s) throws IOException {
|
||||
write(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* End current line.
|
||||
*/
|
||||
public void pln() throws IOException {
|
||||
newLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write string; end current line.
|
||||
*/
|
||||
public void pln(String s) throws IOException {
|
||||
p(s);
|
||||
pln();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write string; end current line; indent in.
|
||||
*/
|
||||
public void plnI(String s) throws IOException {
|
||||
p(s);
|
||||
pln();
|
||||
pI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent out; write string.
|
||||
*/
|
||||
public void pO(String s) throws IOException {
|
||||
pO();
|
||||
p(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent out; write string; end current line.
|
||||
*/
|
||||
public void pOln(String s) throws IOException {
|
||||
pO(s);
|
||||
pln();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent out; write string; end current line; indent in.
|
||||
*
|
||||
* This method is useful for generating lines of code that both
|
||||
* end and begin nested blocks, like "} else {".
|
||||
*/
|
||||
public void pOlnI(String s) throws IOException {
|
||||
pO(s);
|
||||
pln();
|
||||
pI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Object.
|
||||
*/
|
||||
public void p(Object o) throws IOException {
|
||||
write(o.toString());
|
||||
}
|
||||
/**
|
||||
* Write Object; end current line.
|
||||
*/
|
||||
public void pln(Object o) throws IOException {
|
||||
p(o.toString());
|
||||
pln();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Object; end current line; indent in.
|
||||
*/
|
||||
public void plnI(Object o) throws IOException {
|
||||
p(o.toString());
|
||||
pln();
|
||||
pI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent out; write Object.
|
||||
*/
|
||||
public void pO(Object o) throws IOException {
|
||||
pO();
|
||||
p(o.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent out; write Object; end current line.
|
||||
*/
|
||||
public void pOln(Object o) throws IOException {
|
||||
pO(o.toString());
|
||||
pln();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent out; write Object; end current line; indent in.
|
||||
*
|
||||
* This method is useful for generating lines of code that both
|
||||
* end and begin nested blocks, like "} else {".
|
||||
*/
|
||||
public void pOlnI(Object o) throws IOException {
|
||||
pO(o.toString());
|
||||
pln();
|
||||
pI();
|
||||
}
|
||||
|
||||
}
|
||||
897
jdkSrc/jdk8/sun/rmi/rmic/Main.java
Normal file
897
jdkSrc/jdk8/sun/rmi/rmic/Main.java
Normal file
@@ -0,0 +1,897 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.Enumeration;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import sun.tools.java.ClassFile;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
import sun.tools.java.ClassDeclaration;
|
||||
import sun.tools.java.ClassNotFound;
|
||||
import sun.tools.java.Identifier;
|
||||
import sun.tools.java.ClassPath;
|
||||
|
||||
import sun.tools.javac.SourceClass;
|
||||
import sun.tools.util.CommandLine;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Main "rmic" program.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*/
|
||||
public class Main implements sun.rmi.rmic.Constants {
|
||||
String sourcePathArg;
|
||||
String sysClassPathArg;
|
||||
String extDirsArg;
|
||||
String classPathString;
|
||||
File destDir;
|
||||
int flags;
|
||||
long tm;
|
||||
Vector<String> classes;
|
||||
boolean nowrite;
|
||||
boolean nocompile;
|
||||
boolean keepGenerated;
|
||||
boolean status;
|
||||
String[] generatorArgs;
|
||||
Vector<Generator> generators;
|
||||
Class<? extends BatchEnvironment> environmentClass =
|
||||
BatchEnvironment.class;
|
||||
boolean iiopGeneration = false;
|
||||
|
||||
/**
|
||||
* Name of the program.
|
||||
*/
|
||||
String program;
|
||||
|
||||
/**
|
||||
* The stream where error message are printed.
|
||||
*/
|
||||
OutputStream out;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Main(OutputStream out, String program) {
|
||||
this.out = out;
|
||||
this.program = program;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a message.
|
||||
*/
|
||||
public void output(String msg) {
|
||||
PrintStream out =
|
||||
this.out instanceof PrintStream ? (PrintStream)this.out
|
||||
: new PrintStream(this.out, true);
|
||||
out.println(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Top level error message. This method is called when the
|
||||
* environment could not be set up yet.
|
||||
*/
|
||||
public void error(String msg) {
|
||||
output(getText(msg));
|
||||
}
|
||||
|
||||
public void error(String msg, String arg1) {
|
||||
output(getText(msg, arg1));
|
||||
}
|
||||
|
||||
public void error(String msg, String arg1, String arg2) {
|
||||
output(getText(msg, arg1, arg2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Usage
|
||||
*/
|
||||
public void usage() {
|
||||
error("rmic.usage", program);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the compiler
|
||||
*/
|
||||
public synchronized boolean compile(String argv[]) {
|
||||
|
||||
/*
|
||||
* Handle internal option to use the new (and incomplete) rmic
|
||||
* implementation. This option is handled here, rather than
|
||||
* in parseArgs, so that none of the arguments will be nulled
|
||||
* before delegating to the new implementation.
|
||||
*/
|
||||
for (int i = 0; i < argv.length; i++) {
|
||||
if (argv[i].equals("-Xnew")) {
|
||||
return (new sun.rmi.rmic.newrmic.Main(out,
|
||||
program)).compile(argv);
|
||||
}
|
||||
}
|
||||
|
||||
if (!parseArgs(argv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (classes.size() == 0) {
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((flags & F_WARNINGS) != 0) {
|
||||
for (Generator g : generators) {
|
||||
if (g instanceof RMIGenerator) {
|
||||
output(getText("rmic.jrmp.stubs.deprecated", program));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return doCompile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination directory.
|
||||
*/
|
||||
public File getDestinationDir() {
|
||||
return destDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the arguments for compile.
|
||||
*/
|
||||
public boolean parseArgs(String argv[]) {
|
||||
sourcePathArg = null;
|
||||
sysClassPathArg = null;
|
||||
extDirsArg = null;
|
||||
|
||||
classPathString = null;
|
||||
destDir = null;
|
||||
flags = F_WARNINGS;
|
||||
tm = System.currentTimeMillis();
|
||||
classes = new Vector<>();
|
||||
nowrite = false;
|
||||
nocompile = false;
|
||||
keepGenerated = false;
|
||||
generatorArgs = getArray("generator.args",true);
|
||||
if (generatorArgs == null) {
|
||||
return false;
|
||||
}
|
||||
generators = new Vector<>();
|
||||
|
||||
// Pre-process command line for @file arguments
|
||||
try {
|
||||
argv = CommandLine.parse(argv);
|
||||
} catch (FileNotFoundException e) {
|
||||
error("rmic.cant.read", e.getMessage());
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(out instanceof PrintStream ?
|
||||
(PrintStream) out :
|
||||
new PrintStream(out, true));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse arguments
|
||||
for (int i = 0 ; i < argv.length ; i++) {
|
||||
if (argv[i] != null) {
|
||||
if (argv[i].equals("-g")) {
|
||||
flags &= ~F_OPT;
|
||||
flags |= F_DEBUG_LINES | F_DEBUG_VARS;
|
||||
argv[i] = null;
|
||||
} else if (argv[i].equals("-O")) {
|
||||
flags &= ~F_DEBUG_LINES;
|
||||
flags &= ~F_DEBUG_VARS;
|
||||
flags |= F_OPT | F_DEPENDENCIES;
|
||||
argv[i] = null;
|
||||
} else if (argv[i].equals("-nowarn")) {
|
||||
flags &= ~F_WARNINGS;
|
||||
argv[i] = null;
|
||||
} else if (argv[i].equals("-debug")) {
|
||||
flags |= F_DUMP;
|
||||
argv[i] = null;
|
||||
} else if (argv[i].equals("-depend")) {
|
||||
flags |= F_DEPENDENCIES;
|
||||
argv[i] = null;
|
||||
} else if (argv[i].equals("-verbose")) {
|
||||
flags |= F_VERBOSE;
|
||||
argv[i] = null;
|
||||
} else if (argv[i].equals("-nowrite")) {
|
||||
nowrite = true;
|
||||
argv[i] = null;
|
||||
} else if (argv[i].equals("-Xnocompile")) {
|
||||
nocompile = true;
|
||||
keepGenerated = true;
|
||||
argv[i] = null;
|
||||
} else if (argv[i].equals("-keep") ||
|
||||
argv[i].equals("-keepgenerated")) {
|
||||
keepGenerated = true;
|
||||
argv[i] = null;
|
||||
} else if (argv[i].equals("-show")) {
|
||||
error("rmic.option.unsupported", "-show");
|
||||
usage();
|
||||
return false;
|
||||
} else if (argv[i].equals("-classpath")) {
|
||||
if ((i + 1) < argv.length) {
|
||||
if (classPathString != null) {
|
||||
error("rmic.option.already.seen", "-classpath");
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
argv[i] = null;
|
||||
classPathString = argv[++i];
|
||||
argv[i] = null;
|
||||
} else {
|
||||
error("rmic.option.requires.argument", "-classpath");
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
} else if (argv[i].equals("-sourcepath")) {
|
||||
if ((i + 1) < argv.length) {
|
||||
if (sourcePathArg != null) {
|
||||
error("rmic.option.already.seen", "-sourcepath");
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
argv[i] = null;
|
||||
sourcePathArg = argv[++i];
|
||||
argv[i] = null;
|
||||
} else {
|
||||
error("rmic.option.requires.argument", "-sourcepath");
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
} else if (argv[i].equals("-bootclasspath")) {
|
||||
if ((i + 1) < argv.length) {
|
||||
if (sysClassPathArg != null) {
|
||||
error("rmic.option.already.seen", "-bootclasspath");
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
argv[i] = null;
|
||||
sysClassPathArg = argv[++i];
|
||||
argv[i] = null;
|
||||
} else {
|
||||
error("rmic.option.requires.argument", "-bootclasspath");
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
} else if (argv[i].equals("-extdirs")) {
|
||||
if ((i + 1) < argv.length) {
|
||||
if (extDirsArg != null) {
|
||||
error("rmic.option.already.seen", "-extdirs");
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
argv[i] = null;
|
||||
extDirsArg = argv[++i];
|
||||
argv[i] = null;
|
||||
} else {
|
||||
error("rmic.option.requires.argument", "-extdirs");
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
} else if (argv[i].equals("-d")) {
|
||||
if ((i + 1) < argv.length) {
|
||||
if (destDir != null) {
|
||||
error("rmic.option.already.seen", "-d");
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
argv[i] = null;
|
||||
destDir = new File(argv[++i]);
|
||||
argv[i] = null;
|
||||
if (!destDir.exists()) {
|
||||
error("rmic.no.such.directory", destDir.getPath());
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
error("rmic.option.requires.argument", "-d");
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!checkGeneratorArg(argv,i)) {
|
||||
usage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now that all generators have had a chance at the args,
|
||||
// scan what's left for classes and illegal args...
|
||||
|
||||
for (int i = 0; i < argv.length; i++) {
|
||||
if (argv[i] != null) {
|
||||
if (argv[i].startsWith("-")) {
|
||||
error("rmic.no.such.option", argv[i]);
|
||||
usage();
|
||||
return false;
|
||||
} else {
|
||||
classes.addElement(argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If the generators vector is empty, add the default generator...
|
||||
|
||||
if (generators.size() == 0) {
|
||||
addGenerator("default");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this argument is for a generator, instantiate it, call
|
||||
* parseArgs(...) and add generator to generators vector.
|
||||
* Returns false on error.
|
||||
*/
|
||||
protected boolean checkGeneratorArg(String[] argv, int currentIndex) {
|
||||
boolean result = true;
|
||||
if (argv[currentIndex].startsWith("-")) {
|
||||
String arg = argv[currentIndex].substring(1).toLowerCase(); // Remove '-'
|
||||
for (int i = 0; i < generatorArgs.length; i++) {
|
||||
if (arg.equalsIgnoreCase(generatorArgs[i])) {
|
||||
// Got a match, add Generator and call parseArgs...
|
||||
Generator gen = addGenerator(arg);
|
||||
if (gen == null) {
|
||||
return false;
|
||||
}
|
||||
result = gen.parseArgs(argv,this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate and add a generator to the generators array.
|
||||
*/
|
||||
protected Generator addGenerator(String arg) {
|
||||
|
||||
Generator gen;
|
||||
|
||||
// Create an instance of the generator and add it to
|
||||
// the array...
|
||||
|
||||
String className = getString("generator.class." + arg);
|
||||
if (className == null) {
|
||||
error("rmic.missing.property",arg);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
gen = (Generator) Class.forName(className).newInstance();
|
||||
} catch (Exception e) {
|
||||
error("rmic.cannot.instantiate",className);
|
||||
return null;
|
||||
}
|
||||
|
||||
generators.addElement(gen);
|
||||
|
||||
// Get the environment required by this generator...
|
||||
|
||||
Class<?> envClass = BatchEnvironment.class;
|
||||
String env = getString("generator.env." + arg);
|
||||
if (env != null) {
|
||||
try {
|
||||
envClass = Class.forName(env);
|
||||
|
||||
// Is the new class a subclass of the current one?
|
||||
|
||||
if (environmentClass.isAssignableFrom(envClass)) {
|
||||
|
||||
// Yes, so switch to the new one...
|
||||
|
||||
environmentClass = envClass.asSubclass(BatchEnvironment.class);
|
||||
|
||||
} else {
|
||||
|
||||
// No. Is the current class a subclass of the
|
||||
// new one?
|
||||
|
||||
if (!envClass.isAssignableFrom(environmentClass)) {
|
||||
|
||||
// No, so it's a conflict...
|
||||
|
||||
error("rmic.cannot.use.both",environmentClass.getName(),envClass.getName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
error("rmic.class.not.found",env);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is the iiop stub generator, cache
|
||||
// that fact for the jrmp generator...
|
||||
|
||||
if (arg.equals("iiop")) {
|
||||
iiopGeneration = true;
|
||||
}
|
||||
return gen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab a resource string and parse it into an array of strings. Assumes
|
||||
* comma separated list.
|
||||
* @param name The resource name.
|
||||
* @param mustExist If true, throws error if resource does not exist. If
|
||||
* false and resource does not exist, returns zero element array.
|
||||
*/
|
||||
protected String[] getArray(String name, boolean mustExist) {
|
||||
String[] result = null;
|
||||
String value = getString(name);
|
||||
if (value == null) {
|
||||
if (mustExist) {
|
||||
error("rmic.resource.not.found",name);
|
||||
return null;
|
||||
} else {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
StringTokenizer parser = new StringTokenizer(value,", \t\n\r", false);
|
||||
int count = parser.countTokens();
|
||||
result = new String[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
result[i] = parser.nextToken();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the correct type of BatchEnvironment
|
||||
*/
|
||||
public BatchEnvironment getEnv() {
|
||||
|
||||
ClassPath classPath =
|
||||
BatchEnvironment.createClassPath(classPathString,
|
||||
sysClassPathArg,
|
||||
extDirsArg);
|
||||
BatchEnvironment result = null;
|
||||
try {
|
||||
Class<?>[] ctorArgTypes = {OutputStream.class,ClassPath.class,Main.class};
|
||||
Object[] ctorArgs = {out,classPath,this};
|
||||
Constructor<? extends BatchEnvironment> constructor =
|
||||
environmentClass.getConstructor(ctorArgTypes);
|
||||
result = constructor.newInstance(ctorArgs);
|
||||
result.reset();
|
||||
}
|
||||
catch (Exception e) {
|
||||
error("rmic.cannot.instantiate",environmentClass.getName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do the compile with the switches and files already supplied
|
||||
*/
|
||||
public boolean doCompile() {
|
||||
// Create batch environment
|
||||
BatchEnvironment env = getEnv();
|
||||
env.flags |= flags;
|
||||
|
||||
// Set the classfile version numbers
|
||||
// Compat and 1.1 stubs must retain the old version number.
|
||||
env.majorVersion = 45;
|
||||
env.minorVersion = 3;
|
||||
|
||||
// Preload the "out of memory" error string just in case we run
|
||||
// out of memory during the compile.
|
||||
String noMemoryErrorString = getText("rmic.no.memory");
|
||||
String stackOverflowErrorString = getText("rmic.stack.overflow");
|
||||
|
||||
try {
|
||||
/** Load the classes on the command line
|
||||
* Replace the entries in classes with the ClassDefinition for the class
|
||||
*/
|
||||
for (int i = classes.size()-1; i >= 0; i-- ) {
|
||||
Identifier implClassName =
|
||||
Identifier.lookup(classes.elementAt(i));
|
||||
|
||||
/*
|
||||
* Fix bugid 4049354: support using '.' as an inner class
|
||||
* qualifier on the command line (previously, only mangled
|
||||
* inner class names were understood, like "pkg.Outer$Inner").
|
||||
*
|
||||
* The following method, also used by "javap", resolves the
|
||||
* given unmangled inner class name to the appropriate
|
||||
* internal identifier. For example, it translates
|
||||
* "pkg.Outer.Inner" to "pkg.Outer. Inner".
|
||||
*/
|
||||
implClassName = env.resolvePackageQualifiedName(implClassName);
|
||||
/*
|
||||
* But if we use such an internal inner class name identifier
|
||||
* to load the class definition, the Java compiler will notice
|
||||
* if the impl class is a "private" inner class and then deny
|
||||
* skeletons (needed unless "-v1.2" is used) the ability to
|
||||
* cast to it. To work around this problem, we mangle inner
|
||||
* class name identifiers to their binary "outer" class name:
|
||||
* "pkg.Outer. Inner" becomes "pkg.Outer$Inner".
|
||||
*/
|
||||
implClassName = Names.mangleClass(implClassName);
|
||||
|
||||
ClassDeclaration decl = env.getClassDeclaration(implClassName);
|
||||
try {
|
||||
ClassDefinition def = decl.getClassDefinition(env);
|
||||
for (int j = 0; j < generators.size(); j++) {
|
||||
Generator gen = generators.elementAt(j);
|
||||
gen.generate(env, def, destDir);
|
||||
}
|
||||
} catch (ClassNotFound ex) {
|
||||
env.error(0, "rmic.class.not.found", implClassName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// compile all classes that need compilation
|
||||
if (!nocompile) {
|
||||
compileAllClasses(env);
|
||||
}
|
||||
} catch (OutOfMemoryError ee) {
|
||||
// The compiler has run out of memory. Use the error string
|
||||
// which we preloaded.
|
||||
env.output(noMemoryErrorString);
|
||||
return false;
|
||||
} catch (StackOverflowError ee) {
|
||||
env.output(stackOverflowErrorString);
|
||||
return false;
|
||||
} catch (Error ee) {
|
||||
// We allow the compiler to take an exception silently if a program
|
||||
// error has previously been detected. Presumably, this makes the
|
||||
// compiler more robust in the face of bad error recovery.
|
||||
if (env.nerrors == 0 || env.dump()) {
|
||||
env.error(0, "fatal.error");
|
||||
ee.printStackTrace(out instanceof PrintStream ?
|
||||
(PrintStream) out :
|
||||
new PrintStream(out, true));
|
||||
}
|
||||
} catch (Exception ee) {
|
||||
if (env.nerrors == 0 || env.dump()) {
|
||||
env.error(0, "fatal.exception");
|
||||
ee.printStackTrace(out instanceof PrintStream ?
|
||||
(PrintStream) out :
|
||||
new PrintStream(out, true));
|
||||
}
|
||||
}
|
||||
|
||||
env.flushErrors();
|
||||
|
||||
boolean status = true;
|
||||
if (env.nerrors > 0) {
|
||||
String msg = "";
|
||||
if (env.nerrors > 1) {
|
||||
msg = getText("rmic.errors", env.nerrors);
|
||||
} else {
|
||||
msg = getText("rmic.1error");
|
||||
}
|
||||
if (env.nwarnings > 0) {
|
||||
if (env.nwarnings > 1) {
|
||||
msg += ", " + getText("rmic.warnings", env.nwarnings);
|
||||
} else {
|
||||
msg += ", " + getText("rmic.1warning");
|
||||
}
|
||||
}
|
||||
output(msg);
|
||||
status = false;
|
||||
} else {
|
||||
if (env.nwarnings > 0) {
|
||||
if (env.nwarnings > 1) {
|
||||
output(getText("rmic.warnings", env.nwarnings));
|
||||
} else {
|
||||
output(getText("rmic.1warning"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// last step is to delete generated source files
|
||||
if (!keepGenerated) {
|
||||
env.deleteGeneratedFiles();
|
||||
}
|
||||
|
||||
// We're done
|
||||
if (env.verbose()) {
|
||||
tm = System.currentTimeMillis() - tm;
|
||||
output(getText("rmic.done_in", Long.toString(tm)));
|
||||
}
|
||||
|
||||
// Shutdown the environment object and release our resources.
|
||||
// Note that while this is unneccessary when rmic is invoked
|
||||
// the command line, there are environments in which rmic
|
||||
// from is invoked within a server process, so resource
|
||||
// reclamation is important...
|
||||
|
||||
env.shutdown();
|
||||
|
||||
sourcePathArg = null;
|
||||
sysClassPathArg = null;
|
||||
extDirsArg = null;
|
||||
classPathString = null;
|
||||
destDir = null;
|
||||
classes = null;
|
||||
generatorArgs = null;
|
||||
generators = null;
|
||||
environmentClass = null;
|
||||
program = null;
|
||||
out = null;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile all classes that need to be compiled.
|
||||
*/
|
||||
public void compileAllClasses (BatchEnvironment env)
|
||||
throws ClassNotFound,
|
||||
IOException,
|
||||
InterruptedException {
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream(4096);
|
||||
boolean done;
|
||||
|
||||
do {
|
||||
done = true;
|
||||
for (Enumeration<?> e = env.getClasses() ; e.hasMoreElements() ; ) {
|
||||
ClassDeclaration c = (ClassDeclaration)e.nextElement();
|
||||
done = compileClass(c,buf,env);
|
||||
}
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile a single class.
|
||||
* Fallthrough is intentional
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
public boolean compileClass (ClassDeclaration c,
|
||||
ByteArrayOutputStream buf,
|
||||
BatchEnvironment env)
|
||||
throws ClassNotFound,
|
||||
IOException,
|
||||
InterruptedException {
|
||||
boolean done = true;
|
||||
env.flushErrors();
|
||||
SourceClass src;
|
||||
|
||||
switch (c.getStatus()) {
|
||||
case CS_UNDEFINED:
|
||||
{
|
||||
if (!env.dependencies()) {
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
}
|
||||
|
||||
case CS_SOURCE:
|
||||
{
|
||||
done = false;
|
||||
env.loadDefinition(c);
|
||||
if (c.getStatus() != CS_PARSED) {
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
}
|
||||
|
||||
case CS_PARSED:
|
||||
{
|
||||
if (c.getClassDefinition().isInsideLocal()) {
|
||||
break;
|
||||
}
|
||||
// If we get to here, then compilation is going
|
||||
// to occur. If the -Xnocompile switch is set
|
||||
// then fail. Note that this check is required
|
||||
// here because this method is called from
|
||||
// generators, not just from within this class...
|
||||
|
||||
if (nocompile) {
|
||||
throw new IOException("Compilation required, but -Xnocompile option in effect");
|
||||
}
|
||||
|
||||
done = false;
|
||||
|
||||
src = (SourceClass)c.getClassDefinition(env);
|
||||
src.check(env);
|
||||
c.setDefinition(src, CS_CHECKED);
|
||||
// fall through
|
||||
}
|
||||
|
||||
case CS_CHECKED:
|
||||
{
|
||||
src = (SourceClass)c.getClassDefinition(env);
|
||||
// bail out if there were any errors
|
||||
if (src.getError()) {
|
||||
c.setDefinition(src, CS_COMPILED);
|
||||
break;
|
||||
}
|
||||
done = false;
|
||||
buf.reset();
|
||||
src.compile(buf);
|
||||
c.setDefinition(src, CS_COMPILED);
|
||||
src.cleanup(env);
|
||||
|
||||
if (src.getError() || nowrite) {
|
||||
break;
|
||||
}
|
||||
|
||||
String pkgName = c.getName().getQualifier().toString().replace('.', File.separatorChar);
|
||||
String className = c.getName().getFlatName().toString().replace('.', SIGC_INNERCLASS) + ".class";
|
||||
|
||||
File file;
|
||||
if (destDir != null) {
|
||||
if (pkgName.length() > 0) {
|
||||
file = new File(destDir, pkgName);
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
file = new File(file, className);
|
||||
} else {
|
||||
file = new File(destDir, className);
|
||||
}
|
||||
} else {
|
||||
ClassFile classfile = (ClassFile)src.getSource();
|
||||
if (classfile.isZipped()) {
|
||||
env.error(0, "cant.write", classfile.getPath());
|
||||
break;
|
||||
}
|
||||
file = new File(classfile.getPath());
|
||||
file = new File(file.getParent(), className);
|
||||
}
|
||||
|
||||
// Create the file
|
||||
try {
|
||||
FileOutputStream out = new FileOutputStream(file.getPath());
|
||||
buf.writeTo(out);
|
||||
out.close();
|
||||
if (env.verbose()) {
|
||||
output(getText("rmic.wrote", file.getPath()));
|
||||
}
|
||||
} catch (IOException ee) {
|
||||
env.error(0, "cant.write", file.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main program
|
||||
*/
|
||||
public static void main(String argv[]) {
|
||||
Main compiler = new Main(System.out, "rmic");
|
||||
System.exit(compiler.compile(argv) ? 0 : 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string value of a named resource in the rmic.properties
|
||||
* resource bundle. If the resource is not found, null is returned.
|
||||
*/
|
||||
public static String getString(String key) {
|
||||
if (!resourcesInitialized) {
|
||||
initResources();
|
||||
}
|
||||
|
||||
// To enable extensions, search the 'resourcesExt'
|
||||
// bundle first, followed by the 'resources' bundle...
|
||||
|
||||
if (resourcesExt != null) {
|
||||
try {
|
||||
return resourcesExt.getString(key);
|
||||
} catch (MissingResourceException e) {}
|
||||
}
|
||||
|
||||
try {
|
||||
return resources.getString(key);
|
||||
} catch (MissingResourceException ignore) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean resourcesInitialized = false;
|
||||
private static ResourceBundle resources;
|
||||
private static ResourceBundle resourcesExt = null;
|
||||
|
||||
private static void initResources() {
|
||||
try {
|
||||
resources =
|
||||
ResourceBundle.getBundle("sun.rmi.rmic.resources.rmic");
|
||||
resourcesInitialized = true;
|
||||
try {
|
||||
resourcesExt =
|
||||
ResourceBundle.getBundle("sun.rmi.rmic.resources.rmicext");
|
||||
} catch (MissingResourceException e) {}
|
||||
} catch (MissingResourceException e) {
|
||||
throw new Error("fatal: missing resource bundle: " +
|
||||
e.getClassName());
|
||||
}
|
||||
}
|
||||
|
||||
public static String getText(String key) {
|
||||
String message = getString(key);
|
||||
if (message == null) {
|
||||
message = "no text found: \"" + key + "\"";
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
public static String getText(String key, int num) {
|
||||
return getText(key, Integer.toString(num), null, null);
|
||||
}
|
||||
|
||||
public static String getText(String key, String arg0) {
|
||||
return getText(key, arg0, null, null);
|
||||
}
|
||||
|
||||
public static String getText(String key, String arg0, String arg1) {
|
||||
return getText(key, arg0, arg1, null);
|
||||
}
|
||||
|
||||
public static String getText(String key,
|
||||
String arg0, String arg1, String arg2)
|
||||
{
|
||||
String format = getString(key);
|
||||
if (format == null) {
|
||||
format = "no text found: key = \"" + key + "\", " +
|
||||
"arguments = \"{0}\", \"{1}\", \"{2}\"";
|
||||
}
|
||||
|
||||
String[] args = new String[3];
|
||||
args[0] = (arg0 != null ? arg0 : "null");
|
||||
args[1] = (arg1 != null ? arg1 : "null");
|
||||
args[2] = (arg2 != null ? arg2 : "null");
|
||||
|
||||
return java.text.MessageFormat.format(format, (Object[]) args);
|
||||
}
|
||||
}
|
||||
88
jdkSrc/jdk8/sun/rmi/rmic/Names.java
Normal file
88
jdkSrc/jdk8/sun/rmi/rmic/Names.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic;
|
||||
|
||||
import sun.tools.java.Identifier;
|
||||
|
||||
/**
|
||||
* Names provides static utility methods used by other rmic classes
|
||||
* for dealing with identifiers.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*/
|
||||
public class Names {
|
||||
|
||||
/**
|
||||
* Return stub class name for impl class name.
|
||||
*/
|
||||
static final public Identifier stubFor(Identifier name) {
|
||||
return Identifier.lookup(name + "_Stub");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return skeleton class name for impl class name.
|
||||
*/
|
||||
static final public Identifier skeletonFor(Identifier name) {
|
||||
return Identifier.lookup(name + "_Skel");
|
||||
}
|
||||
|
||||
/**
|
||||
* If necessary, convert a class name to its mangled form, i.e. the
|
||||
* non-inner class name used in the binary representation of
|
||||
* inner classes. This is necessary to be able to name inner
|
||||
* classes in the generated source code in places where the language
|
||||
* does not permit it, such as when synthetically defining an inner
|
||||
* class outside of its outer class, and for generating file names
|
||||
* corresponding to inner classes.
|
||||
*
|
||||
* Currently this mangling involves modifying the internal names of
|
||||
* inner classes by converting occurrences of ". " into "$".
|
||||
*
|
||||
* This code is taken from the "mangleInnerType" method of
|
||||
* the "sun.tools.java.Type" class; this method cannot be accessed
|
||||
* itself because it is package protected.
|
||||
*/
|
||||
static final public Identifier mangleClass(Identifier className) {
|
||||
if (!className.isInner())
|
||||
return className;
|
||||
|
||||
/*
|
||||
* Get '.' qualified inner class name (with outer class
|
||||
* qualification and no package qualification) and replace
|
||||
* each '.' with '$'.
|
||||
*/
|
||||
Identifier mangled = Identifier.lookup(
|
||||
className.getFlatName().toString()
|
||||
.replace('.', sun.tools.java.Constants.SIGC_INNERCLASS));
|
||||
if (mangled.isInner())
|
||||
throw new Error("failed to mangle inner class name");
|
||||
|
||||
// prepend package qualifier back for returned identifier
|
||||
return Identifier.lookup(className.getQualifier(), mangled);
|
||||
}
|
||||
}
|
||||
80
jdkSrc/jdk8/sun/rmi/rmic/RMIConstants.java
Normal file
80
jdkSrc/jdk8/sun/rmi/rmic/RMIConstants.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic;
|
||||
|
||||
import sun.tools.java.Identifier;
|
||||
|
||||
/**
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*/
|
||||
public interface RMIConstants extends sun.rmi.rmic.Constants {
|
||||
|
||||
/*
|
||||
* identifiers for RMI classes referenced by rmic
|
||||
*/
|
||||
public static final Identifier idRemoteObject =
|
||||
Identifier.lookup("java.rmi.server.RemoteObject");
|
||||
public static final Identifier idRemoteStub =
|
||||
Identifier.lookup("java.rmi.server.RemoteStub");
|
||||
public static final Identifier idRemoteRef =
|
||||
Identifier.lookup("java.rmi.server.RemoteRef");
|
||||
public static final Identifier idOperation =
|
||||
Identifier.lookup("java.rmi.server.Operation");
|
||||
public static final Identifier idSkeleton =
|
||||
Identifier.lookup("java.rmi.server.Skeleton");
|
||||
public static final Identifier idSkeletonMismatchException =
|
||||
Identifier.lookup("java.rmi.server.SkeletonMismatchException");
|
||||
public static final Identifier idRemoteCall =
|
||||
Identifier.lookup("java.rmi.server.RemoteCall");
|
||||
public static final Identifier idMarshalException =
|
||||
Identifier.lookup("java.rmi.MarshalException");
|
||||
public static final Identifier idUnmarshalException =
|
||||
Identifier.lookup("java.rmi.UnmarshalException");
|
||||
public static final Identifier idUnexpectedException =
|
||||
Identifier.lookup("java.rmi.UnexpectedException");
|
||||
|
||||
/*
|
||||
* stub protocol versions
|
||||
*/
|
||||
public static final int STUB_VERSION_1_1 = 1;
|
||||
public static final int STUB_VERSION_FAT = 2;
|
||||
public static final int STUB_VERSION_1_2 = 3;
|
||||
|
||||
/** serialVersionUID for all stubs that can use 1.2 protocol */
|
||||
public static final long STUB_SERIAL_VERSION_UID = 2;
|
||||
|
||||
/** version number used to seed interface hash computation */
|
||||
public static final int INTERFACE_HASH_STUB_VERSION = 1;
|
||||
}
|
||||
1302
jdkSrc/jdk8/sun/rmi/rmic/RMIGenerator.java
Normal file
1302
jdkSrc/jdk8/sun/rmi/rmic/RMIGenerator.java
Normal file
File diff suppressed because it is too large
Load Diff
876
jdkSrc/jdk8/sun/rmi/rmic/RemoteClass.java
Normal file
876
jdkSrc/jdk8/sun/rmi/rmic/RemoteClass.java
Normal file
@@ -0,0 +1,876 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import sun.tools.java.Type;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
import sun.tools.java.ClassDeclaration;
|
||||
import sun.tools.java.MemberDefinition;
|
||||
import sun.tools.java.Identifier;
|
||||
import sun.tools.java.ClassNotFound;
|
||||
|
||||
/**
|
||||
* A RemoteClass object encapsulates RMI-specific information about
|
||||
* a remote implementation class, i.e. a class that implements
|
||||
* one or more remote interfaces.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Peter Jones
|
||||
*/
|
||||
public class RemoteClass implements sun.rmi.rmic.RMIConstants {
|
||||
|
||||
/**
|
||||
* Create a RemoteClass object representing the remote meta-information
|
||||
* of the given class.
|
||||
*
|
||||
* Returns true if successful. If the class is not a properly formed
|
||||
* remote implementation class or if some other error occurs, the
|
||||
* return value will be null, and errors will have been reported to
|
||||
* the supplied BatchEnvironment.
|
||||
*/
|
||||
public static RemoteClass forClass(BatchEnvironment env,
|
||||
ClassDefinition implClassDef)
|
||||
{
|
||||
RemoteClass rc = new RemoteClass(env, implClassDef);
|
||||
if (rc.initialize()) {
|
||||
return rc;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ClassDefinition for this class.
|
||||
*/
|
||||
public ClassDefinition getClassDefinition() {
|
||||
return implClassDef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the class represented by this object.
|
||||
*/
|
||||
public Identifier getName() {
|
||||
return implClassDef.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of ClassDefinitions representing all of the remote
|
||||
* interfaces implemented by this class.
|
||||
*
|
||||
* A remote interface is any interface that extends Remote,
|
||||
* directly or indirectly. The remote interfaces of a class
|
||||
* are the interfaces directly listed in either the class's
|
||||
* "implements" clause, or the "implements" clause of any
|
||||
* of its superclasses, that are remote interfaces.
|
||||
*
|
||||
* The order of the array returned is arbitrary, and some elements
|
||||
* may be superfluous (i.e., superinterfaces of other interfaces
|
||||
* in the array).
|
||||
*/
|
||||
public ClassDefinition[] getRemoteInterfaces() {
|
||||
return remoteInterfaces.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of RemoteClass.Method objects representing all of
|
||||
* the remote methods implemented by this class, i.e. all of the
|
||||
* methods in the class's remote interfaces.
|
||||
*
|
||||
* The methods in the array are ordered according to the comparision
|
||||
* of the strings consisting of their method name followed by their
|
||||
* type signature, so each method's index in the array corresponds
|
||||
* to its "operation number" in the JDK 1.1 version of the
|
||||
* stub/skeleton protocol.
|
||||
*/
|
||||
public Method[] getRemoteMethods() {
|
||||
return remoteMethods.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "interface hash" used to match a stub/skeleton pair for
|
||||
* this class in the JDK 1.1 version of the stub/skeleton protocol.
|
||||
*/
|
||||
public long getInterfaceHash() {
|
||||
return interfaceHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string representation of this object, consisting of
|
||||
* the string "remote class " followed by the class name.
|
||||
*/
|
||||
public String toString() {
|
||||
return "remote class " + implClassDef.getName().toString();
|
||||
}
|
||||
|
||||
/** rmic environment for this object */
|
||||
private BatchEnvironment env;
|
||||
|
||||
/** the remote implementation class this object corresponds to */
|
||||
private ClassDefinition implClassDef;
|
||||
|
||||
/** remote interfaces implemented by this class */
|
||||
private ClassDefinition[] remoteInterfaces;
|
||||
|
||||
/** all the remote methods of this class */
|
||||
private Method[] remoteMethods;
|
||||
|
||||
/** stub/skeleton "interface hash" for this class */
|
||||
private long interfaceHash;
|
||||
|
||||
/** cached definition for certain classes used in this environment */
|
||||
private ClassDefinition defRemote;
|
||||
private ClassDefinition defException;
|
||||
private ClassDefinition defRemoteException;
|
||||
|
||||
/**
|
||||
* Create a RemoteClass instance for the given class. The resulting
|
||||
* object is not yet initialized.
|
||||
*/
|
||||
private RemoteClass(BatchEnvironment env, ClassDefinition implClassDef) {
|
||||
this.env = env;
|
||||
this.implClassDef = implClassDef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the remote implementation class is properly formed
|
||||
* and fill in the data structures required by the public interface.
|
||||
*/
|
||||
private boolean initialize() {
|
||||
/*
|
||||
* Verify that the "impl" is really a class, not an interface.
|
||||
*/
|
||||
if (implClassDef.isInterface()) {
|
||||
env.error(0, "rmic.cant.make.stubs.for.interface",
|
||||
implClassDef.getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize cached definitions for the Remote interface and
|
||||
* the RemoteException class.
|
||||
*/
|
||||
try {
|
||||
defRemote =
|
||||
env.getClassDeclaration(idRemote).getClassDefinition(env);
|
||||
defException =
|
||||
env.getClassDeclaration(idJavaLangException).
|
||||
getClassDefinition(env);
|
||||
defRemoteException =
|
||||
env.getClassDeclaration(idRemoteException).
|
||||
getClassDefinition(env);
|
||||
} catch (ClassNotFound e) {
|
||||
env.error(0, "rmic.class.not.found", e.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we find all of the remote interfaces of our remote
|
||||
* implementation class. For each class up the superclass
|
||||
* chain, add each directly-implemented interface that
|
||||
* somehow extends Remote to a list.
|
||||
*/
|
||||
Vector<ClassDefinition> remotesImplemented = // list of remote interfaces found
|
||||
new Vector<ClassDefinition>();
|
||||
for (ClassDefinition classDef = implClassDef;
|
||||
classDef != null;)
|
||||
{
|
||||
try {
|
||||
ClassDeclaration[] interfaces = classDef.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
ClassDefinition interfaceDef =
|
||||
interfaces[i].getClassDefinition(env);
|
||||
/*
|
||||
* Add interface to the list if it extends Remote and
|
||||
* it is not already there.
|
||||
*/
|
||||
if (!remotesImplemented.contains(interfaceDef) &&
|
||||
defRemote.implementedBy(env, interfaces[i]))
|
||||
{
|
||||
remotesImplemented.addElement(interfaceDef);
|
||||
/***** <DEBUG> */
|
||||
if (env.verbose()) {
|
||||
System.out.println("[found remote interface: " +
|
||||
interfaceDef.getName() + "]");
|
||||
/***** </DEBUG> */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that the candidate remote implementation class
|
||||
* implements at least one remote interface directly.
|
||||
*/
|
||||
if (classDef == implClassDef && remotesImplemented.isEmpty()) {
|
||||
if (defRemote.implementedBy(env,
|
||||
implClassDef.getClassDeclaration()))
|
||||
{
|
||||
/*
|
||||
* This error message is used if the class does
|
||||
* implement a remote interface through one of
|
||||
* its superclasses, but not directly.
|
||||
*/
|
||||
env.error(0, "rmic.must.implement.remote.directly",
|
||||
implClassDef.getName());
|
||||
} else {
|
||||
/*
|
||||
* This error message is used if the class never
|
||||
* implements a remote interface.
|
||||
*/
|
||||
env.error(0, "rmic.must.implement.remote",
|
||||
implClassDef.getName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get definition for next superclass.
|
||||
*/
|
||||
classDef = (classDef.getSuperClass() != null ?
|
||||
classDef.getSuperClass().getClassDefinition(env) :
|
||||
null);
|
||||
|
||||
} catch (ClassNotFound e) {
|
||||
env.error(0, "class.not.found", e.name, classDef.getName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The "remotesImplemented" vector now contains all of the remote
|
||||
* interfaces directly implemented by the remote class or by any
|
||||
* of its superclasses.
|
||||
*
|
||||
* At this point, we could optimize the list by removing superfluous
|
||||
* entries, i.e. any interfaces that are implemented by some other
|
||||
* interface in the list anyway.
|
||||
*
|
||||
* This should be correct; would it be worthwhile?
|
||||
*
|
||||
* for (int i = 0; i < remotesImplemented.size();) {
|
||||
* ClassDefinition interfaceDef =
|
||||
* (ClassDefinition) remotesImplemented.elementAt(i);
|
||||
* boolean isOtherwiseImplemented = false;
|
||||
* for (int j = 0; j < remotesImplemented.size; j++) {
|
||||
* if (j != i &&
|
||||
* interfaceDef.implementedBy(env, (ClassDefinition)
|
||||
* remotesImplemented.elementAt(j).
|
||||
* getClassDeclaration()))
|
||||
* {
|
||||
* isOtherwiseImplemented = true;
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
* if (isOtherwiseImplemented) {
|
||||
* remotesImplemented.removeElementAt(i);
|
||||
* } else {
|
||||
* ++i;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
/*
|
||||
* Now we collect the methods from all of the remote interfaces
|
||||
* into a hashtable.
|
||||
*/
|
||||
Hashtable<String, Method> methods = new Hashtable<String, Method>();
|
||||
boolean errors = false;
|
||||
for (Enumeration<ClassDefinition> enumeration
|
||||
= remotesImplemented.elements();
|
||||
enumeration.hasMoreElements();)
|
||||
{
|
||||
ClassDefinition interfaceDef = enumeration.nextElement();
|
||||
if (!collectRemoteMethods(interfaceDef, methods))
|
||||
errors = true;
|
||||
}
|
||||
if (errors)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Convert vector of remote interfaces to an array
|
||||
* (order is not important for this array).
|
||||
*/
|
||||
remoteInterfaces = new ClassDefinition[remotesImplemented.size()];
|
||||
remotesImplemented.copyInto(remoteInterfaces);
|
||||
|
||||
/*
|
||||
* Sort table of remote methods into an array. The elements are
|
||||
* sorted in ascending order of the string of the method's name
|
||||
* and type signature, so that each elements index is equal to
|
||||
* its operation number of the JDK 1.1 version of the stub/skeleton
|
||||
* protocol.
|
||||
*/
|
||||
String[] orderedKeys = new String[methods.size()];
|
||||
int count = 0;
|
||||
for (Enumeration<Method> enumeration = methods.elements();
|
||||
enumeration.hasMoreElements();)
|
||||
{
|
||||
Method m = enumeration.nextElement();
|
||||
String key = m.getNameAndDescriptor();
|
||||
int i;
|
||||
for (i = count; i > 0; --i) {
|
||||
if (key.compareTo(orderedKeys[i - 1]) >= 0) {
|
||||
break;
|
||||
}
|
||||
orderedKeys[i] = orderedKeys[i - 1];
|
||||
}
|
||||
orderedKeys[i] = key;
|
||||
++count;
|
||||
}
|
||||
remoteMethods = new Method[methods.size()];
|
||||
for (int i = 0; i < remoteMethods.length; i++) {
|
||||
remoteMethods[i] = methods.get(orderedKeys[i]);
|
||||
/***** <DEBUG> */
|
||||
if (env.verbose()) {
|
||||
System.out.print("[found remote method <" + i + ">: " +
|
||||
remoteMethods[i].getOperationString());
|
||||
ClassDeclaration[] exceptions =
|
||||
remoteMethods[i].getExceptions();
|
||||
if (exceptions.length > 0)
|
||||
System.out.print(" throws ");
|
||||
for (int j = 0; j < exceptions.length; j++) {
|
||||
if (j > 0)
|
||||
System.out.print(", ");
|
||||
System.out.print(exceptions[j].getName());
|
||||
}
|
||||
System.out.println("]");
|
||||
}
|
||||
/***** </DEBUG> */
|
||||
}
|
||||
|
||||
/**
|
||||
* Finally, pre-compute the interface hash to be used by
|
||||
* stubs/skeletons for this remote class.
|
||||
*/
|
||||
interfaceHash = computeInterfaceHash();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect and validate all methods from given interface and all of
|
||||
* its superinterfaces as remote methods. Remote methods are added
|
||||
* to the supplied hashtable. Returns true if successful,
|
||||
* or false if an error occurred.
|
||||
*/
|
||||
private boolean collectRemoteMethods(ClassDefinition interfaceDef,
|
||||
Hashtable<String, Method> table)
|
||||
{
|
||||
if (!interfaceDef.isInterface()) {
|
||||
throw new Error(
|
||||
"expected interface, not class: " + interfaceDef.getName());
|
||||
}
|
||||
|
||||
/*
|
||||
* rmic used to enforce that a remote interface could not extend
|
||||
* a non-remote interface, i.e. an interface that did not itself
|
||||
* extend from Remote. The current version of rmic does not have
|
||||
* this restriction, so the following code is now commented out.
|
||||
*
|
||||
* Verify that this interface extends Remote, since all interfaces
|
||||
* extended by a remote interface must implement Remote.
|
||||
*
|
||||
* try {
|
||||
* if (!defRemote.implementedBy(env,
|
||||
* interfaceDef.getClassDeclaration()))
|
||||
* {
|
||||
* env.error(0, "rmic.can.mix.remote.nonremote",
|
||||
* interfaceDef.getName());
|
||||
* return false;
|
||||
* }
|
||||
* } catch (ClassNotFound e) {
|
||||
* env.error(0, "class.not.found", e.name,
|
||||
* interfaceDef.getName());
|
||||
* return false;
|
||||
* }
|
||||
*/
|
||||
|
||||
boolean errors = false;
|
||||
|
||||
/*
|
||||
* Search interface's members for methods.
|
||||
*/
|
||||
nextMember:
|
||||
for (MemberDefinition member = interfaceDef.getFirstMember();
|
||||
member != null;
|
||||
member = member.getNextMember())
|
||||
{
|
||||
if (member.isMethod() &&
|
||||
!member.isConstructor() && !member.isInitializer())
|
||||
{
|
||||
/*
|
||||
* Verify that each method throws RemoteException.
|
||||
*/
|
||||
ClassDeclaration[] exceptions = member.getExceptions(env);
|
||||
boolean hasRemoteException = false;
|
||||
for (int i = 0; i < exceptions.length; i++) {
|
||||
/*
|
||||
* rmic used to enforce that a remote method had to
|
||||
* explicitly list RemoteException in its "throws"
|
||||
* clause; i.e., just throwing Exception was not
|
||||
* acceptable. The current version of rmic does not
|
||||
* have this restriction, so the following code is
|
||||
* now commented out. Instead, the method is
|
||||
* considered valid if RemoteException is a subclass
|
||||
* of any of the methods declared exceptions.
|
||||
*
|
||||
* if (exceptions[i].getName().equals(
|
||||
* idRemoteException))
|
||||
* {
|
||||
* hasRemoteException = true;
|
||||
* break;
|
||||
* }
|
||||
*/
|
||||
try {
|
||||
if (defRemoteException.subClassOf(
|
||||
env, exceptions[i]))
|
||||
{
|
||||
hasRemoteException = true;
|
||||
break;
|
||||
}
|
||||
} catch (ClassNotFound e) {
|
||||
env.error(0, "class.not.found", e.name,
|
||||
interfaceDef.getName());
|
||||
continue nextMember;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If this method did not throw RemoteException as required,
|
||||
* generate the error but continue, so that multiple such
|
||||
* errors can be reported.
|
||||
*/
|
||||
if (!hasRemoteException) {
|
||||
env.error(0, "rmic.must.throw.remoteexception",
|
||||
interfaceDef.getName(), member.toString());
|
||||
errors = true;
|
||||
continue nextMember;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that the implementation of this method throws only
|
||||
* java.lang.Exception or its subclasses (fix bugid 4092486).
|
||||
* JRMP does not support remote methods throwing
|
||||
* java.lang.Throwable or other subclasses.
|
||||
*/
|
||||
try {
|
||||
MemberDefinition implMethod = implClassDef.findMethod(
|
||||
env, member.getName(), member.getType());
|
||||
if (implMethod != null) { // should not be null
|
||||
exceptions = implMethod.getExceptions(env);
|
||||
for (int i = 0; i < exceptions.length; i++) {
|
||||
if (!defException.superClassOf(
|
||||
env, exceptions[i]))
|
||||
{
|
||||
env.error(0, "rmic.must.only.throw.exception",
|
||||
implMethod.toString(),
|
||||
exceptions[i].getName());
|
||||
errors = true;
|
||||
continue nextMember;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFound e) {
|
||||
env.error(0, "class.not.found", e.name,
|
||||
implClassDef.getName());
|
||||
continue nextMember;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create RemoteClass.Method object to represent this method
|
||||
* found in a remote interface.
|
||||
*/
|
||||
Method newMethod = new Method(member);
|
||||
/*
|
||||
* Store remote method's representation in the table of
|
||||
* remote methods found, keyed by its name and parameter
|
||||
* signature.
|
||||
*
|
||||
* If the table already contains an entry with the same
|
||||
* method name and parameter signature, then we must
|
||||
* replace the old entry with a Method object that
|
||||
* represents a legal combination of the old and the new
|
||||
* methods; specifically, the combined method must have
|
||||
* a throws list that contains (only) all of the checked
|
||||
* exceptions that can be thrown by both the old or
|
||||
* the new method (see bugid 4070653).
|
||||
*/
|
||||
String key = newMethod.getNameAndDescriptor();
|
||||
Method oldMethod = table.get(key);
|
||||
if (oldMethod != null) {
|
||||
newMethod = newMethod.mergeWith(oldMethod);
|
||||
if (newMethod == null) {
|
||||
errors = true;
|
||||
continue nextMember;
|
||||
}
|
||||
}
|
||||
table.put(key, newMethod);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursively collect methods for all superinterfaces.
|
||||
*/
|
||||
try {
|
||||
ClassDeclaration[] superDefs = interfaceDef.getInterfaces();
|
||||
for (int i = 0; i < superDefs.length; i++) {
|
||||
ClassDefinition superDef =
|
||||
superDefs[i].getClassDefinition(env);
|
||||
if (!collectRemoteMethods(superDef, table))
|
||||
errors = true;
|
||||
}
|
||||
} catch (ClassNotFound e) {
|
||||
env.error(0, "class.not.found", e.name, interfaceDef.getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
return !errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the "interface hash" of the stub/skeleton pair for this
|
||||
* remote implementation class. This is the 64-bit value used to
|
||||
* enforce compatibility between a stub and a skeleton using the
|
||||
* JDK 1.1 version of the stub/skeleton protocol.
|
||||
*
|
||||
* It is calculated using the first 64 bits of a SHA digest. The
|
||||
* digest is from a stream consisting of the following data:
|
||||
* (int) stub version number, always 1
|
||||
* for each remote method, in order of operation number:
|
||||
* (UTF) method name
|
||||
* (UTF) method type signature
|
||||
* for each declared exception, in alphabetical name order:
|
||||
* (UTF) name of exception class
|
||||
*
|
||||
*/
|
||||
private long computeInterfaceHash() {
|
||||
long hash = 0;
|
||||
ByteArrayOutputStream sink = new ByteArrayOutputStream(512);
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
DataOutputStream out = new DataOutputStream(
|
||||
new DigestOutputStream(sink, md));
|
||||
|
||||
out.writeInt(INTERFACE_HASH_STUB_VERSION);
|
||||
for (int i = 0; i < remoteMethods.length; i++) {
|
||||
MemberDefinition m = remoteMethods[i].getMemberDefinition();
|
||||
Identifier name = m.getName();
|
||||
Type type = m.getType();
|
||||
|
||||
out.writeUTF(name.toString());
|
||||
// type signatures already use mangled class names
|
||||
out.writeUTF(type.getTypeSignature());
|
||||
|
||||
ClassDeclaration exceptions[] = m.getExceptions(env);
|
||||
sortClassDeclarations(exceptions);
|
||||
for (int j = 0; j < exceptions.length; j++) {
|
||||
out.writeUTF(Names.mangleClass(
|
||||
exceptions[j].getName()).toString());
|
||||
}
|
||||
}
|
||||
out.flush();
|
||||
|
||||
// use only the first 64 bits of the digest for the hash
|
||||
byte hashArray[] = md.digest();
|
||||
for (int i = 0; i < Math.min(8, hashArray.length); i++) {
|
||||
hash += ((long) (hashArray[i] & 0xFF)) << (i * 8);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new Error(
|
||||
"unexpected exception computing intetrface hash: " + e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new Error(
|
||||
"unexpected exception computing intetrface hash: " + e);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort array of class declarations alphabetically by their mangled
|
||||
* fully-qualified class name. This is used to feed a method's exceptions
|
||||
* in a canonical order into the digest stream for the interface hash
|
||||
* computation.
|
||||
*/
|
||||
private void sortClassDeclarations(ClassDeclaration[] decl) {
|
||||
for (int i = 1; i < decl.length; i++) {
|
||||
ClassDeclaration curr = decl[i];
|
||||
String name = Names.mangleClass(curr.getName()).toString();
|
||||
int j;
|
||||
for (j = i; j > 0; j--) {
|
||||
if (name.compareTo(
|
||||
Names.mangleClass(decl[j - 1].getName()).toString()) >= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
decl[j] = decl[j - 1];
|
||||
}
|
||||
decl[j] = curr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A RemoteClass.Method object encapsulates RMI-specific information
|
||||
* about a particular remote method in the remote implementation class
|
||||
* represented by the outer instance.
|
||||
*/
|
||||
public class Method implements Cloneable {
|
||||
|
||||
/**
|
||||
* Return the definition of the actual class member corresponing
|
||||
* to this method of a remote interface.
|
||||
*
|
||||
* REMIND: Can this method be removed?
|
||||
*/
|
||||
public MemberDefinition getMemberDefinition() {
|
||||
return memberDef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of this method.
|
||||
*/
|
||||
public Identifier getName() {
|
||||
return memberDef.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of this method.
|
||||
*/
|
||||
public Type getType() {
|
||||
return memberDef.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of the exception classes declared to be
|
||||
* thrown by this remote method.
|
||||
*
|
||||
* For methods with the same name and type signature inherited
|
||||
* from multiple remote interfaces, the array will contain
|
||||
* the set of exceptions declared in all of the interfaces'
|
||||
* methods that can be legally thrown in each of them.
|
||||
*/
|
||||
public ClassDeclaration[] getExceptions() {
|
||||
return exceptions.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "method hash" used to identify this remote method
|
||||
* in the JDK 1.2 version of the stub protocol.
|
||||
*/
|
||||
public long getMethodHash() {
|
||||
return methodHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string representation of this method.
|
||||
*/
|
||||
public String toString() {
|
||||
return memberDef.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string representation of this method appropriate
|
||||
* for the construction of a java.rmi.server.Operation object.
|
||||
*/
|
||||
public String getOperationString() {
|
||||
return memberDef.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string consisting of this method's name followed by
|
||||
* its method descriptor, using the Java VM's notation for
|
||||
* method descriptors (see section 4.3.3 of The Java Virtual
|
||||
* Machine Specification).
|
||||
*/
|
||||
public String getNameAndDescriptor() {
|
||||
return memberDef.getName().toString() +
|
||||
memberDef.getType().getTypeSignature();
|
||||
}
|
||||
|
||||
/**
|
||||
* Member definition for this method, from one of the remote
|
||||
* interfaces that this method was found in.
|
||||
*
|
||||
* Note that this member definition may be only one of several
|
||||
* member defintions that correspond to this remote method object,
|
||||
* if several of this class's remote interfaces contain methods
|
||||
* with the same name and type signature. Therefore, this member
|
||||
* definition may declare more exceptions thrown that this remote
|
||||
* method does.
|
||||
*/
|
||||
private MemberDefinition memberDef;
|
||||
|
||||
/** stub "method hash" to identify this method */
|
||||
private long methodHash;
|
||||
|
||||
/**
|
||||
* Exceptions declared to be thrown by this remote method.
|
||||
*
|
||||
* This list can include superfluous entries, such as
|
||||
* unchecked exceptions and subclasses of other entries.
|
||||
*/
|
||||
private ClassDeclaration[] exceptions;
|
||||
|
||||
/**
|
||||
* Create a new Method object corresponding to the given
|
||||
* method definition.
|
||||
*/
|
||||
/*
|
||||
* Temporarily comment out the private modifier until
|
||||
* the VM allows outer class to access inner class's
|
||||
* private constructor
|
||||
*/
|
||||
/* private */ Method(MemberDefinition memberDef) {
|
||||
this.memberDef = memberDef;
|
||||
exceptions = memberDef.getExceptions(env);
|
||||
methodHash = computeMethodHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cloning is supported by returning a shallow copy of this object.
|
||||
*/
|
||||
protected Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new Error("clone failed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new Method object that is a legal combination of
|
||||
* this method object and another one.
|
||||
*
|
||||
* This requires determining the exceptions declared by the
|
||||
* combined method, which must be (only) all of the exceptions
|
||||
* declared in both old Methods that may thrown in either of
|
||||
* them.
|
||||
*/
|
||||
private Method mergeWith(Method other) {
|
||||
if (!getName().equals(other.getName()) ||
|
||||
!getType().equals(other.getType()))
|
||||
{
|
||||
throw new Error("attempt to merge method \"" +
|
||||
other.getNameAndDescriptor() + "\" with \"" +
|
||||
getNameAndDescriptor());
|
||||
}
|
||||
|
||||
Vector<ClassDeclaration> legalExceptions
|
||||
= new Vector<ClassDeclaration>();
|
||||
try {
|
||||
collectCompatibleExceptions(
|
||||
other.exceptions, exceptions, legalExceptions);
|
||||
collectCompatibleExceptions(
|
||||
exceptions, other.exceptions, legalExceptions);
|
||||
} catch (ClassNotFound e) {
|
||||
env.error(0, "class.not.found", e.name,
|
||||
getClassDefinition().getName());
|
||||
return null;
|
||||
}
|
||||
|
||||
Method merged = (Method) clone();
|
||||
merged.exceptions = new ClassDeclaration[legalExceptions.size()];
|
||||
legalExceptions.copyInto(merged.exceptions);
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the supplied list all exceptions in the "from" array
|
||||
* that are subclasses of an exception in the "with" array.
|
||||
*/
|
||||
private void collectCompatibleExceptions(ClassDeclaration[] from,
|
||||
ClassDeclaration[] with,
|
||||
Vector<ClassDeclaration> list)
|
||||
throws ClassNotFound
|
||||
{
|
||||
for (int i = 0; i < from.length; i++) {
|
||||
ClassDefinition exceptionDef = from[i].getClassDefinition(env);
|
||||
if (!list.contains(from[i])) {
|
||||
for (int j = 0; j < with.length; j++) {
|
||||
if (exceptionDef.subClassOf(env, with[j])) {
|
||||
list.addElement(from[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the "method hash" of this remote method. The method
|
||||
* hash is a long containing the first 64 bits of the SHA digest
|
||||
* from the UTF encoded string of the method name and descriptor.
|
||||
*
|
||||
* REMIND: Should this method share implementation code with
|
||||
* the outer class's computeInterfaceHash() method?
|
||||
*/
|
||||
private long computeMethodHash() {
|
||||
long hash = 0;
|
||||
ByteArrayOutputStream sink = new ByteArrayOutputStream(512);
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
DataOutputStream out = new DataOutputStream(
|
||||
new DigestOutputStream(sink, md));
|
||||
|
||||
String methodString = getNameAndDescriptor();
|
||||
/***** <DEBUG> */
|
||||
if (env.verbose()) {
|
||||
System.out.println("[string used for method hash: \"" +
|
||||
methodString + "\"]");
|
||||
}
|
||||
/***** </DEBUG> */
|
||||
out.writeUTF(methodString);
|
||||
|
||||
// use only the first 64 bits of the digest for the hash
|
||||
out.flush();
|
||||
byte hashArray[] = md.digest();
|
||||
for (int i = 0; i < Math.min(8, hashArray.length); i++) {
|
||||
hash += ((long) (hashArray[i] & 0xFF)) << (i * 8);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new Error(
|
||||
"unexpected exception computing intetrface hash: " + e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new Error(
|
||||
"unexpected exception computing intetrface hash: " + e);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
136
jdkSrc/jdk8/sun/rmi/rmic/Util.java
Normal file
136
jdkSrc/jdk8/sun/rmi/rmic/Util.java
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic;
|
||||
|
||||
import java.io.File;
|
||||
import sun.tools.java.Identifier;
|
||||
|
||||
/**
|
||||
* Util provides static utility methods used by other rmic classes.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
|
||||
public class Util implements sun.rmi.rmic.Constants {
|
||||
|
||||
/**
|
||||
* Return the directory that should be used for output for a given
|
||||
* class.
|
||||
* @param theClass The fully qualified name of the class.
|
||||
* @param rootDir The directory to use as the root of the
|
||||
* package hierarchy. May be null, in which case the current
|
||||
* working directory is used as the root.
|
||||
*/
|
||||
public static File getOutputDirectoryFor(Identifier theClass,
|
||||
File rootDir,
|
||||
BatchEnvironment env) {
|
||||
|
||||
File outputDir = null;
|
||||
String className = theClass.getFlatName().toString().replace('.', SIGC_INNERCLASS);
|
||||
String qualifiedClassName = className;
|
||||
String packagePath = null;
|
||||
String packageName = theClass.getQualifier().toString();
|
||||
|
||||
if (packageName.length() > 0) {
|
||||
qualifiedClassName = packageName + "." + className;
|
||||
packagePath = packageName.replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
// Do we have a root directory?
|
||||
|
||||
if (rootDir != null) {
|
||||
|
||||
// Yes, do we have a package name?
|
||||
|
||||
if (packagePath != null) {
|
||||
|
||||
// Yes, so use it as the root. Open the directory...
|
||||
|
||||
outputDir = new File(rootDir, packagePath);
|
||||
|
||||
// Make sure the directory exists...
|
||||
|
||||
ensureDirectory(outputDir,env);
|
||||
|
||||
} else {
|
||||
|
||||
// Default package, so use root as output dir...
|
||||
|
||||
outputDir = rootDir;
|
||||
}
|
||||
} else {
|
||||
|
||||
// No root directory. Get the current working directory...
|
||||
|
||||
String workingDirPath = System.getProperty("user.dir");
|
||||
File workingDir = new File(workingDirPath);
|
||||
|
||||
// Do we have a package name?
|
||||
|
||||
if (packagePath == null) {
|
||||
|
||||
// No, so use working directory...
|
||||
|
||||
outputDir = workingDir;
|
||||
|
||||
} else {
|
||||
|
||||
// Yes, so use working directory as the root...
|
||||
|
||||
outputDir = new File(workingDir, packagePath);
|
||||
|
||||
// Make sure the directory exists...
|
||||
|
||||
ensureDirectory(outputDir,env);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, return the directory...
|
||||
|
||||
return outputDir;
|
||||
}
|
||||
|
||||
private static void ensureDirectory (File dir, BatchEnvironment env) {
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
if (!dir.exists()) {
|
||||
env.error(0,"rmic.cannot.create.dir",dir.getAbsolutePath());
|
||||
throw new InternalError();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
205
jdkSrc/jdk8/sun/rmi/rmic/iiop/AbstractType.java
Normal file
205
jdkSrc/jdk8/sun/rmi/rmic/iiop/AbstractType.java
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.util.Vector;
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.ClassNotFound;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
|
||||
/**
|
||||
* AbstractType represents any non-special interface which does not
|
||||
* inherit from java.rmi.Remote, for which all methods throw RemoteException.
|
||||
* <p>
|
||||
* The static forAbstract(...) method must be used to obtain an instance, and will
|
||||
* return null if the ClassDefinition is non-conforming.
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class AbstractType extends RemoteType {
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create an AbstractType for the given class.
|
||||
*
|
||||
* If the class is not a properly formed or if some other error occurs, the
|
||||
* return value will be null, and errors will have been reported to the
|
||||
* supplied BatchEnvironment.
|
||||
*/
|
||||
public static AbstractType forAbstract(ClassDefinition classDef,
|
||||
ContextStack stack,
|
||||
boolean quiet)
|
||||
{
|
||||
boolean doPop = false;
|
||||
AbstractType result = null;
|
||||
|
||||
try {
|
||||
|
||||
// Do we already have it?
|
||||
|
||||
sun.tools.java.Type theType = classDef.getType();
|
||||
Type existing = getType(theType,stack);
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
if (!(existing instanceof AbstractType)) return null; // False hit.
|
||||
|
||||
// Yep, so return it...
|
||||
|
||||
return (AbstractType) existing;
|
||||
|
||||
}
|
||||
|
||||
// Could this be an abstract?
|
||||
|
||||
if (couldBeAbstract(stack,classDef,quiet)) {
|
||||
|
||||
// Yes, so try it...
|
||||
|
||||
AbstractType it = new AbstractType(stack, classDef);
|
||||
putType(theType,it,stack);
|
||||
stack.push(it);
|
||||
doPop = true;
|
||||
|
||||
if (it.initialize(quiet,stack)) {
|
||||
stack.pop(true);
|
||||
result = it;
|
||||
} else {
|
||||
removeType(theType,stack);
|
||||
stack.pop(false);
|
||||
}
|
||||
}
|
||||
} catch (CompilerError e) {
|
||||
if (doPop) stack.pop(false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string describing this type.
|
||||
*/
|
||||
public String getTypeDescription () {
|
||||
return "Abstract interface";
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Internal/Subclass Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create a AbstractType instance for the given class. The resulting
|
||||
* object is not yet completely initialized.
|
||||
*/
|
||||
private AbstractType(ContextStack stack, ClassDefinition classDef) {
|
||||
super(stack,classDef,TYPE_ABSTRACT | TM_INTERFACE | TM_COMPOUND);
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
|
||||
private static boolean couldBeAbstract(ContextStack stack, ClassDefinition classDef,
|
||||
boolean quiet) {
|
||||
|
||||
// Return true if interface and not remote...
|
||||
|
||||
boolean result = false;
|
||||
|
||||
if (classDef.isInterface()) {
|
||||
BatchEnvironment env = stack.getEnv();
|
||||
|
||||
try {
|
||||
result = ! env.defRemote.implementedBy(env, classDef.getClassDeclaration());
|
||||
if (!result) failedConstraint(15,quiet,stack,classDef.getName());
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
}
|
||||
} else {
|
||||
failedConstraint(14,quiet,stack,classDef.getName());
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize this instance.
|
||||
*/
|
||||
private boolean initialize (boolean quiet,ContextStack stack) {
|
||||
|
||||
boolean result = false;
|
||||
ClassDefinition self = getClassDefinition();
|
||||
|
||||
try {
|
||||
|
||||
// Get methods...
|
||||
|
||||
Vector directMethods = new Vector();
|
||||
|
||||
if (addAllMethods(self,directMethods,true,quiet,stack) != null) {
|
||||
|
||||
// Do we have any methods?
|
||||
|
||||
boolean validMethods = true;
|
||||
|
||||
if (directMethods.size() > 0) {
|
||||
|
||||
// Yes. Walk 'em, ensuring each is a valid remote method...
|
||||
|
||||
for (int i = 0; i < directMethods.size(); i++) {
|
||||
|
||||
if (! isConformingRemoteMethod((Method) directMethods.elementAt(i),true)) {
|
||||
validMethods = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (validMethods) {
|
||||
|
||||
// We're ok, so pass 'em up...
|
||||
|
||||
result = initialize(null,directMethods,null,stack,quiet);
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
270
jdkSrc/jdk8/sun/rmi/rmic/iiop/ArrayType.java
Normal file
270
jdkSrc/jdk8/sun/rmi/rmic/iiop/ArrayType.java
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.HashSet;
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.Identifier;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
/**
|
||||
* ArrayType is a wrapper for any of the other types. The getElementType()
|
||||
* method can be used to get the array element type. The getArrayDimension()
|
||||
* method can be used to get the array dimension.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class ArrayType extends Type {
|
||||
|
||||
private Type type;
|
||||
private int arrayDimension;
|
||||
private String brackets;
|
||||
private String bracketsSig;
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create an ArrayType object for the given type.
|
||||
*
|
||||
* If the class is not a properly formed or if some other error occurs, the
|
||||
* return value will be null, and errors will have been reported to the
|
||||
* supplied BatchEnvironment.
|
||||
*/
|
||||
public static ArrayType forArray( sun.tools.java.Type theType,
|
||||
ContextStack stack) {
|
||||
|
||||
|
||||
ArrayType result = null;
|
||||
sun.tools.java.Type arrayType = theType;
|
||||
|
||||
if (arrayType.getTypeCode() == TC_ARRAY) {
|
||||
|
||||
// Find real type...
|
||||
|
||||
while (arrayType.getTypeCode() == TC_ARRAY) {
|
||||
arrayType = arrayType.getElementType();
|
||||
}
|
||||
|
||||
// Do we already have it?
|
||||
|
||||
Type existing = getType(theType,stack);
|
||||
if (existing != null) {
|
||||
|
||||
if (!(existing instanceof ArrayType)) return null; // False hit.
|
||||
|
||||
// Yep, so return it...
|
||||
|
||||
return (ArrayType) existing;
|
||||
}
|
||||
|
||||
// Now try to make a Type from it...
|
||||
|
||||
Type temp = CompoundType.makeType(arrayType,null,stack);
|
||||
|
||||
if (temp != null) {
|
||||
|
||||
// Got a valid one. Make an array type...
|
||||
|
||||
result = new ArrayType(stack,temp,theType.getArrayDimension());
|
||||
|
||||
// Add it...
|
||||
|
||||
putType(theType,result,stack);
|
||||
|
||||
// Do the stack thing in case tracing on...
|
||||
|
||||
stack.push(result);
|
||||
stack.pop(true);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return signature for this type (e.g. com.acme.Dynamite
|
||||
* would return "com.acme.Dynamite", byte = "B")
|
||||
*/
|
||||
public String getSignature() {
|
||||
return bracketsSig + type.getSignature();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get element type. Returns null if not an array.
|
||||
*/
|
||||
public Type getElementType () {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array dimension. Returns zero if not an array.
|
||||
*/
|
||||
public int getArrayDimension () {
|
||||
return arrayDimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get brackets string. Returns "" if not an array.
|
||||
*/
|
||||
public String getArrayBrackets () {
|
||||
return brackets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of this type.
|
||||
*/
|
||||
public String toString () {
|
||||
return getQualifiedName() + brackets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string describing this type.
|
||||
*/
|
||||
public String getTypeDescription () {
|
||||
return "Array of " + type.getTypeDescription();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of this type. For arrays, will include "[]" if useIDLNames == false.
|
||||
* @param useQualifiedNames If true, print qualified names; otherwise, print unqualified names.
|
||||
* @param useIDLNames If true, print IDL names; otherwise, print java names.
|
||||
* @param globalIDLNames If true and useIDLNames true, prepends "::".
|
||||
*/
|
||||
public String getTypeName ( boolean useQualifiedNames,
|
||||
boolean useIDLNames,
|
||||
boolean globalIDLNames) {
|
||||
if (useIDLNames) {
|
||||
return super.getTypeName(useQualifiedNames,useIDLNames,globalIDLNames);
|
||||
} else {
|
||||
return super.getTypeName(useQualifiedNames,useIDLNames,globalIDLNames) + brackets;
|
||||
}
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Subclass/Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
|
||||
/**
|
||||
* Convert all invalid types to valid ones.
|
||||
*/
|
||||
protected void swapInvalidTypes () {
|
||||
if (type.getStatus() != STATUS_VALID) {
|
||||
type = getValidType(type);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add matching types to list. Return true if this type has not
|
||||
* been previously checked, false otherwise.
|
||||
*/
|
||||
protected boolean addTypes (int typeCodeFilter,
|
||||
HashSet checked,
|
||||
Vector matching) {
|
||||
|
||||
// Check self.
|
||||
|
||||
boolean result = super.addTypes(typeCodeFilter,checked,matching);
|
||||
|
||||
// Have we been checked before?
|
||||
|
||||
if (result) {
|
||||
|
||||
// No, so add element type...
|
||||
|
||||
getElementType().addTypes(typeCodeFilter,checked,matching);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ArrayType instance for the given type. The resulting
|
||||
* object is not yet completely initialized.
|
||||
*/
|
||||
private ArrayType(ContextStack stack, Type type, int arrayDimension) {
|
||||
super(stack,TYPE_ARRAY);
|
||||
this.type = type;
|
||||
this.arrayDimension = arrayDimension;
|
||||
|
||||
// Create our brackets string...
|
||||
|
||||
brackets = "";
|
||||
bracketsSig = "";
|
||||
for (int i = 0; i < arrayDimension; i ++) {
|
||||
brackets += "[]";
|
||||
bracketsSig += "[";
|
||||
}
|
||||
|
||||
// Now set our names...
|
||||
|
||||
String idlName = IDLNames.getArrayName(type,arrayDimension);
|
||||
String[] module = IDLNames.getArrayModuleNames(type);
|
||||
setNames(type.getIdentifier(),module,idlName);
|
||||
|
||||
// Set our repositoryID...
|
||||
|
||||
setRepositoryID();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Load a Class instance. Return null if fail.
|
||||
*/
|
||||
protected Class loadClass() {
|
||||
Class result = null;
|
||||
Class elementClass = type.getClassInstance();
|
||||
if (elementClass != null) {
|
||||
result = Array.newInstance(elementClass, new int[arrayDimension]).getClass();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release all resources
|
||||
*/
|
||||
protected void destroy () {
|
||||
super.destroy();
|
||||
if (type != null) {
|
||||
type.destroy();
|
||||
type = null;
|
||||
}
|
||||
brackets = null;
|
||||
bracketsSig = null;
|
||||
}
|
||||
}
|
||||
260
jdkSrc/jdk8/sun/rmi/rmic/iiop/BatchEnvironment.java
Normal file
260
jdkSrc/jdk8/sun/rmi/rmic/iiop/BatchEnvironment.java
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import sun.rmi.rmic.Main;
|
||||
import sun.tools.java.ClassPath;
|
||||
import java.io.OutputStream;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
import sun.tools.java.ClassDeclaration;
|
||||
import sun.tools.java.Identifier;
|
||||
import sun.tools.java.ClassNotFound;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* BatchEnvironment for iiop extends rmic's version to add
|
||||
* parse state.
|
||||
*/
|
||||
public class BatchEnvironment extends sun.rmi.rmic.BatchEnvironment implements Constants {
|
||||
|
||||
/*
|
||||
* If the following flag is true, then the IDL generator can map
|
||||
* the methods and constants of non-conforming types. However,
|
||||
* this is very expensive, so the default should be false.
|
||||
*/
|
||||
private boolean parseNonConforming = false;
|
||||
|
||||
/**
|
||||
* This flag indicates that the stubs and ties need to be generated without
|
||||
* the package prefix (org.omg.stub).
|
||||
*/
|
||||
private boolean standardPackage;
|
||||
|
||||
/* Common objects used within package */
|
||||
|
||||
HashSet alreadyChecked = new HashSet();
|
||||
Hashtable allTypes = new Hashtable(3001, 0.5f);
|
||||
Hashtable invalidTypes = new Hashtable(256, 0.5f);
|
||||
DirectoryLoader loader = null;
|
||||
ClassPathLoader classPathLoader = null;
|
||||
Hashtable nameContexts = null;
|
||||
Hashtable namesCache = new Hashtable();
|
||||
NameContext modulesContext = new NameContext(false);
|
||||
|
||||
ClassDefinition defRemote = null;
|
||||
ClassDefinition defError = null;
|
||||
ClassDefinition defException = null;
|
||||
ClassDefinition defRemoteException = null;
|
||||
ClassDefinition defCorbaObject = null;
|
||||
ClassDefinition defSerializable = null;
|
||||
ClassDefinition defExternalizable = null;
|
||||
ClassDefinition defThrowable = null;
|
||||
ClassDefinition defRuntimeException = null;
|
||||
ClassDefinition defIDLEntity = null;
|
||||
ClassDefinition defValueBase = null;
|
||||
|
||||
sun.tools.java.Type typeRemoteException = null;
|
||||
sun.tools.java.Type typeIOException = null;
|
||||
sun.tools.java.Type typeException = null;
|
||||
sun.tools.java.Type typeThrowable = null;
|
||||
|
||||
ContextStack contextStack = null;
|
||||
|
||||
/**
|
||||
* Create a BatchEnvironment for rmic with the given class path,
|
||||
* stream for messages and Main.
|
||||
*/
|
||||
public BatchEnvironment(OutputStream out, ClassPath path, Main main) {
|
||||
|
||||
super(out,path,main);
|
||||
|
||||
// Make sure we have our definitions...
|
||||
|
||||
try {
|
||||
defRemote =
|
||||
getClassDeclaration(idRemote).getClassDefinition(this);
|
||||
defError =
|
||||
getClassDeclaration(idJavaLangError).getClassDefinition(this);
|
||||
defException =
|
||||
getClassDeclaration(idJavaLangException).getClassDefinition(this);
|
||||
defRemoteException =
|
||||
getClassDeclaration(idRemoteException).getClassDefinition(this);
|
||||
defCorbaObject =
|
||||
getClassDeclaration(idCorbaObject).getClassDefinition(this);
|
||||
defSerializable =
|
||||
getClassDeclaration(idJavaIoSerializable).getClassDefinition(this);
|
||||
defRuntimeException =
|
||||
getClassDeclaration(idJavaLangRuntimeException).getClassDefinition(this);
|
||||
defExternalizable =
|
||||
getClassDeclaration(idJavaIoExternalizable).getClassDefinition(this);
|
||||
defThrowable=
|
||||
getClassDeclaration(idJavaLangThrowable).getClassDefinition(this);
|
||||
defIDLEntity=
|
||||
getClassDeclaration(idIDLEntity).getClassDefinition(this);
|
||||
defValueBase=
|
||||
getClassDeclaration(idValueBase).getClassDefinition(this);
|
||||
typeRemoteException = defRemoteException.getClassDeclaration().getType();
|
||||
typeException = defException.getClassDeclaration().getType();
|
||||
typeIOException = getClassDeclaration(idJavaIoIOException).getType();
|
||||
typeThrowable = getClassDeclaration(idJavaLangThrowable).getType();
|
||||
|
||||
classPathLoader = new ClassPathLoader(path);
|
||||
|
||||
} catch (ClassNotFound e) {
|
||||
error(0, "rmic.class.not.found", e.name);
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not to parse non-conforming types.
|
||||
*/
|
||||
public boolean getParseNonConforming () {
|
||||
return parseNonConforming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not to parse non-conforming types.
|
||||
*/
|
||||
public void setParseNonConforming (boolean parseEm) {
|
||||
|
||||
// If we are transitioning from not parsing to
|
||||
// parsing, we need to throw out any previously
|
||||
// parsed types...
|
||||
|
||||
if (parseEm && !parseNonConforming) {
|
||||
reset();
|
||||
}
|
||||
|
||||
parseNonConforming = parseEm;
|
||||
}
|
||||
|
||||
void setStandardPackage(boolean standardPackage) {
|
||||
this.standardPackage = standardPackage;
|
||||
}
|
||||
|
||||
boolean getStandardPackage() {
|
||||
return standardPackage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear out any data from previous executions.
|
||||
*/
|
||||
public void reset () {
|
||||
|
||||
// First, find all Type instances and call destroy()
|
||||
// on them...
|
||||
|
||||
for (Enumeration e = allTypes.elements() ; e.hasMoreElements() ;) {
|
||||
Type type = (Type) e.nextElement();
|
||||
type.destroy();
|
||||
}
|
||||
|
||||
for (Enumeration e = invalidTypes.keys() ; e.hasMoreElements() ;) {
|
||||
Type type = (Type) e.nextElement();
|
||||
type.destroy();
|
||||
}
|
||||
|
||||
for (Iterator e = alreadyChecked.iterator() ; e.hasNext() ;) {
|
||||
Type type = (Type) e.next();
|
||||
type.destroy();
|
||||
}
|
||||
|
||||
if (contextStack != null) contextStack.clear();
|
||||
|
||||
// Remove and clear all NameContexts in the
|
||||
// nameContexts cache...
|
||||
|
||||
if (nameContexts != null) {
|
||||
for (Enumeration e = nameContexts.elements() ; e.hasMoreElements() ;) {
|
||||
NameContext context = (NameContext) e.nextElement();
|
||||
context.clear();
|
||||
}
|
||||
nameContexts.clear();
|
||||
}
|
||||
|
||||
// Now remove all table entries...
|
||||
|
||||
allTypes.clear();
|
||||
invalidTypes.clear();
|
||||
alreadyChecked.clear();
|
||||
namesCache.clear();
|
||||
modulesContext.clear();
|
||||
|
||||
// Clean up remaining...
|
||||
loader = null;
|
||||
parseNonConforming = false;
|
||||
|
||||
// REVISIT - can't clean up classPathLoader here
|
||||
}
|
||||
|
||||
/**
|
||||
* Release resources, if any.
|
||||
*/
|
||||
public void shutdown() {
|
||||
if (alreadyChecked != null) {
|
||||
//System.out.println();
|
||||
//System.out.println("allTypes.size() = "+ allTypes.size());
|
||||
//System.out.println(" InstanceCount before reset = "+Type.instanceCount);
|
||||
reset();
|
||||
//System.out.println(" InstanceCount AFTER reset = "+Type.instanceCount);
|
||||
|
||||
alreadyChecked = null;
|
||||
allTypes = null;
|
||||
invalidTypes = null;
|
||||
nameContexts = null;
|
||||
namesCache = null;
|
||||
modulesContext = null;
|
||||
defRemote = null;
|
||||
defError = null;
|
||||
defException = null;
|
||||
defRemoteException = null;
|
||||
defCorbaObject = null;
|
||||
defSerializable = null;
|
||||
defExternalizable = null;
|
||||
defThrowable = null;
|
||||
defRuntimeException = null;
|
||||
defIDLEntity = null;
|
||||
defValueBase = null;
|
||||
typeRemoteException = null;
|
||||
typeIOException = null;
|
||||
typeException = null;
|
||||
typeThrowable = null;
|
||||
|
||||
super.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
117
jdkSrc/jdk8/sun/rmi/rmic/iiop/ClassPathLoader.java
Normal file
117
jdkSrc/jdk8/sun/rmi/rmic/iiop/ClassPathLoader.java
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.io.*;
|
||||
import sun.tools.java.ClassPath ;
|
||||
import sun.tools.java.ClassFile ;
|
||||
|
||||
/**
|
||||
* A ClassLoader that will ultimately use a given sun.tools.java.ClassPath to
|
||||
* find the desired file. This works for any JAR files specified in the given
|
||||
* ClassPath as well -- reusing all of that wonderful sun.tools.java code.
|
||||
*
|
||||
*@author Everett Anderson
|
||||
*/
|
||||
public class ClassPathLoader extends ClassLoader
|
||||
{
|
||||
private ClassPath classPath;
|
||||
|
||||
public ClassPathLoader(ClassPath classPath) {
|
||||
this.classPath = classPath;
|
||||
}
|
||||
|
||||
// Called by the super class
|
||||
protected Class findClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
byte[] b = loadClassData(name);
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the class with the given fully qualified name from the ClassPath.
|
||||
*/
|
||||
private byte[] loadClassData(String className)
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
// Build the file name and subdirectory from the
|
||||
// class name
|
||||
String filename = className.replace('.', File.separatorChar)
|
||||
+ ".class";
|
||||
|
||||
// Have ClassPath find the file for us, and wrap it in a
|
||||
// ClassFile. Note: This is where it looks inside jar files that
|
||||
// are specified in the path.
|
||||
ClassFile classFile = classPath.getFile(filename);
|
||||
|
||||
if (classFile != null) {
|
||||
|
||||
// Provide the most specific reason for failure in addition
|
||||
// to ClassNotFound
|
||||
Exception reportedError = null;
|
||||
byte data[] = null;
|
||||
|
||||
try {
|
||||
// ClassFile is beautiful because it shields us from
|
||||
// knowing if it's a separate file or an entry in a
|
||||
// jar file.
|
||||
DataInputStream input
|
||||
= new DataInputStream(classFile.getInputStream());
|
||||
|
||||
// Can't rely on input available() since it will be
|
||||
// something unusual if it's a jar file! May need
|
||||
// to worry about a possible problem if someone
|
||||
// makes a jar file entry with a size greater than
|
||||
// max int.
|
||||
data = new byte[(int)classFile.length()];
|
||||
|
||||
try {
|
||||
input.readFully(data);
|
||||
} catch (IOException ex) {
|
||||
// Something actually went wrong reading the file. This
|
||||
// is a real error so save it to report it.
|
||||
data = null;
|
||||
reportedError = ex;
|
||||
} finally {
|
||||
// Just don't care if there's an exception on close!
|
||||
// I hate that close can throw an IOException!
|
||||
try { input.close(); } catch (IOException ex) {}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
// Couldn't get the input stream for the file. This is
|
||||
// probably also a real error.
|
||||
reportedError = ex;
|
||||
}
|
||||
|
||||
if (data == null)
|
||||
throw new ClassNotFoundException(className, reportedError);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Couldn't find the file in the class path.
|
||||
throw new ClassNotFoundException(className);
|
||||
}
|
||||
}
|
||||
215
jdkSrc/jdk8/sun/rmi/rmic/iiop/ClassType.java
Normal file
215
jdkSrc/jdk8/sun/rmi/rmic/iiop/ClassType.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.ClassNotFound;
|
||||
import sun.tools.java.ClassDeclaration;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
import sun.rmi.rmic.IndentingWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* ClassType is an abstract base representing any non-special class
|
||||
* type.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public abstract class ClassType extends CompoundType {
|
||||
|
||||
private ClassType parent;
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Return the parent class of this type. Returns null if this
|
||||
* type is an interface or if there is no parent.
|
||||
*/
|
||||
public ClassType getSuperclass() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Print this type.
|
||||
* @param writer The stream to print to.
|
||||
* @param useQualifiedNames If true, print qualified names; otherwise, print unqualified names.
|
||||
* @param useIDLNames If true, print IDL names; otherwise, print java names.
|
||||
* @param globalIDLNames If true and useIDLNames true, prepends "::".
|
||||
*/
|
||||
public void print ( IndentingWriter writer,
|
||||
boolean useQualifiedNames,
|
||||
boolean useIDLNames,
|
||||
boolean globalIDLNames) throws IOException {
|
||||
|
||||
if (isInner()) {
|
||||
writer.p("// " + getTypeDescription() + " (INNER)");
|
||||
} else {
|
||||
writer.p("// " + getTypeDescription());
|
||||
}
|
||||
writer.pln(" (" + getRepositoryID() + ")\n");
|
||||
|
||||
printPackageOpen(writer,useIDLNames);
|
||||
|
||||
if (!useIDLNames) {
|
||||
writer.p("public ");
|
||||
}
|
||||
|
||||
String prefix = "";
|
||||
writer.p("class " + getTypeName(false,useIDLNames,false));
|
||||
if (printExtends(writer,useQualifiedNames,useIDLNames,globalIDLNames)) {
|
||||
prefix = ",";
|
||||
}
|
||||
printImplements(writer,prefix,useQualifiedNames,useIDLNames,globalIDLNames);
|
||||
writer.plnI(" {");
|
||||
printMembers(writer,useQualifiedNames,useIDLNames,globalIDLNames);
|
||||
writer.pln();
|
||||
printMethods(writer,useQualifiedNames,useIDLNames,globalIDLNames);
|
||||
|
||||
if (useIDLNames) {
|
||||
writer.pOln("};");
|
||||
} else {
|
||||
writer.pOln("}");
|
||||
}
|
||||
|
||||
printPackageClose(writer,useIDLNames);
|
||||
}
|
||||
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Subclass/Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
protected void destroy () {
|
||||
if (!destroyed) {
|
||||
super.destroy();
|
||||
if (parent != null) {
|
||||
parent.destroy();
|
||||
parent = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ClassType instance for the given class. NOTE: This constructor
|
||||
* is ONLY for SpecialClassType.
|
||||
*/
|
||||
protected ClassType(ContextStack stack, int typeCode, ClassDefinition classDef) {
|
||||
super(stack,typeCode,classDef); // Call special parent constructor.
|
||||
if ((typeCode & TM_CLASS) == 0 && classDef.isInterface()) {
|
||||
throw new CompilerError("Not a class");
|
||||
}
|
||||
parent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ClassType instance for the given class. NOTE: This constructor
|
||||
* is ONLY for ImplementationType. It does not walk the parent chain.
|
||||
*/
|
||||
protected ClassType(int typeCode, ClassDefinition classDef,ContextStack stack) {
|
||||
super(stack,classDef,typeCode);
|
||||
|
||||
if ((typeCode & TM_CLASS) == 0 && classDef.isInterface()) {
|
||||
throw new CompilerError("Not a class");
|
||||
}
|
||||
parent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ClassType instance for the given class. The resulting
|
||||
* object is not yet completely initialized. Subclasses must call
|
||||
* initialize(directInterfaces,directInterfaces,directConstants);
|
||||
*/
|
||||
protected ClassType(ContextStack stack,
|
||||
ClassDefinition classDef,
|
||||
int typeCode) {
|
||||
super(stack,classDef,typeCode);
|
||||
if ((typeCode & TM_CLASS) == 0 && classDef.isInterface()) {
|
||||
throw new CompilerError("Not a class");
|
||||
}
|
||||
parent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert all invalid types to valid ones.
|
||||
*/
|
||||
protected void swapInvalidTypes () {
|
||||
super.swapInvalidTypes();
|
||||
if (parent != null && parent.getStatus() != STATUS_VALID) {
|
||||
parent = (ClassType) getValidType(parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the type description with exception info.
|
||||
*/
|
||||
public String addExceptionDescription (String typeDesc) {
|
||||
if (isException) {
|
||||
if (isCheckedException) {
|
||||
typeDesc = typeDesc + " - Checked Exception";
|
||||
} else {
|
||||
typeDesc = typeDesc + " - Unchecked Exception";
|
||||
}
|
||||
}
|
||||
return typeDesc;
|
||||
}
|
||||
|
||||
|
||||
protected boolean initParents(ContextStack stack) {
|
||||
|
||||
stack.setNewContextCode(ContextStack.EXTENDS);
|
||||
BatchEnvironment env = stack.getEnv();
|
||||
|
||||
// Init parent...
|
||||
|
||||
boolean result = true;
|
||||
|
||||
try {
|
||||
ClassDeclaration parentDecl = getClassDefinition().getSuperClass(env);
|
||||
if (parentDecl != null) {
|
||||
ClassDefinition parentDef = parentDecl.getClassDefinition(env);
|
||||
parent = (ClassType) makeType(parentDef.getType(),parentDef,stack);
|
||||
if (parent == null) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
throw new CompilerError("ClassType constructor");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
2703
jdkSrc/jdk8/sun/rmi/rmic/iiop/CompoundType.java
Normal file
2703
jdkSrc/jdk8/sun/rmi/rmic/iiop/CompoundType.java
Normal file
File diff suppressed because it is too large
Load Diff
297
jdkSrc/jdk8/sun/rmi/rmic/iiop/Constants.java
Normal file
297
jdkSrc/jdk8/sun/rmi/rmic/iiop/Constants.java
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import sun.tools.java.Identifier;
|
||||
|
||||
public interface Constants extends sun.rmi.rmic.Constants {
|
||||
|
||||
// Identifiers for referenced classes:
|
||||
|
||||
public static final Identifier idReplyHandler =
|
||||
Identifier.lookup("org.omg.CORBA.portable.ResponseHandler");
|
||||
public static final Identifier idStubBase =
|
||||
Identifier.lookup("javax.rmi.CORBA.Stub");
|
||||
public static final Identifier idTieBase =
|
||||
Identifier.lookup("org.omg.CORBA.portable.ObjectImpl");
|
||||
public static final Identifier idTieInterface =
|
||||
Identifier.lookup("javax.rmi.CORBA.Tie");
|
||||
public static final Identifier idPOAServantType =
|
||||
Identifier.lookup( "org.omg.PortableServer.Servant" ) ;
|
||||
public static final Identifier idDelegate =
|
||||
Identifier.lookup("org.omg.CORBA.portable.Delegate");
|
||||
public static final Identifier idOutputStream =
|
||||
Identifier.lookup("org.omg.CORBA.portable.OutputStream");
|
||||
public static final Identifier idExtOutputStream =
|
||||
Identifier.lookup("org.omg.CORBA_2_3.portable.OutputStream");
|
||||
public static final Identifier idInputStream =
|
||||
Identifier.lookup("org.omg.CORBA.portable.InputStream");
|
||||
public static final Identifier idExtInputStream =
|
||||
Identifier.lookup("org.omg.CORBA_2_3.portable.InputStream");
|
||||
public static final Identifier idSystemException =
|
||||
Identifier.lookup("org.omg.CORBA.SystemException");
|
||||
public static final Identifier idBadMethodException =
|
||||
Identifier.lookup("org.omg.CORBA.BAD_OPERATION");
|
||||
public static final Identifier idPortableUnknownException =
|
||||
Identifier.lookup("org.omg.CORBA.portable.UnknownException");
|
||||
public static final Identifier idApplicationException =
|
||||
Identifier.lookup("org.omg.CORBA.portable.ApplicationException");
|
||||
public static final Identifier idRemarshalException =
|
||||
Identifier.lookup("org.omg.CORBA.portable.RemarshalException");
|
||||
public static final Identifier idJavaIoExternalizable =
|
||||
Identifier.lookup("java.io.Externalizable");
|
||||
public static final Identifier idCorbaObject =
|
||||
Identifier.lookup("org.omg.CORBA.Object");
|
||||
public static final Identifier idCorbaORB =
|
||||
Identifier.lookup("org.omg.CORBA.ORB");
|
||||
public static final Identifier idClassDesc =
|
||||
Identifier.lookup("javax.rmi.CORBA.ClassDesc");
|
||||
public static final Identifier idJavaIoIOException =
|
||||
Identifier.lookup("java.io.IOException");
|
||||
public static final Identifier idIDLEntity =
|
||||
Identifier.lookup("org.omg.CORBA.portable.IDLEntity");
|
||||
public static final Identifier idValueBase =
|
||||
Identifier.lookup("org.omg.CORBA.portable.ValueBase");
|
||||
public static final Identifier idBoxedRMI =
|
||||
Identifier.lookup("org.omg.boxedRMI");
|
||||
public static final Identifier idBoxedIDL =
|
||||
Identifier.lookup("org.omg.boxedIDL");
|
||||
public static final Identifier idCorbaUserException =
|
||||
Identifier.lookup("org.omg.CORBA.UserException");
|
||||
|
||||
|
||||
// Identifiers for primitive types:
|
||||
|
||||
public static final Identifier idBoolean =
|
||||
Identifier.lookup("boolean");
|
||||
public static final Identifier idByte =
|
||||
Identifier.lookup("byte");
|
||||
public static final Identifier idChar =
|
||||
Identifier.lookup("char");
|
||||
public static final Identifier idShort =
|
||||
Identifier.lookup("short");
|
||||
public static final Identifier idInt =
|
||||
Identifier.lookup("int");
|
||||
public static final Identifier idLong =
|
||||
Identifier.lookup("long");
|
||||
public static final Identifier idFloat =
|
||||
Identifier.lookup("float");
|
||||
public static final Identifier idDouble =
|
||||
Identifier.lookup("double");
|
||||
public static final Identifier idVoid =
|
||||
Identifier.lookup("void");
|
||||
|
||||
// IndentingWriter constructor args:
|
||||
|
||||
public static final int INDENT_STEP = 4;
|
||||
public static final int TAB_SIZE = Integer.MAX_VALUE; // No tabs.
|
||||
|
||||
// Type status codes:
|
||||
|
||||
public static final int STATUS_PENDING = 0;
|
||||
public static final int STATUS_VALID = 1;
|
||||
public static final int STATUS_INVALID = 2;
|
||||
|
||||
// Java Names:
|
||||
|
||||
public static final String NAME_SEPARATOR = ".";
|
||||
public static final String SERIAL_VERSION_UID = "serialVersionUID";
|
||||
|
||||
// IDL Names:
|
||||
|
||||
public static final String[] IDL_KEYWORDS = {
|
||||
"abstract",
|
||||
"any",
|
||||
"attribute",
|
||||
"boolean",
|
||||
"case",
|
||||
"char",
|
||||
"const",
|
||||
"context",
|
||||
"custom",
|
||||
"default",
|
||||
"double",
|
||||
"enum",
|
||||
"exception",
|
||||
"factory",
|
||||
"FALSE",
|
||||
"fixed",
|
||||
"float",
|
||||
"in",
|
||||
"inout",
|
||||
"interface",
|
||||
"long",
|
||||
"module",
|
||||
"native",
|
||||
"Object",
|
||||
"octet",
|
||||
"oneway",
|
||||
"out",
|
||||
"private",
|
||||
"public",
|
||||
"raises",
|
||||
"readonly",
|
||||
"sequence",
|
||||
"short",
|
||||
"string",
|
||||
"struct",
|
||||
"supports",
|
||||
"switch",
|
||||
"TRUE",
|
||||
"truncatable",
|
||||
"typedef",
|
||||
"unsigned",
|
||||
"union",
|
||||
"ValueBase",
|
||||
"valuetype",
|
||||
"void",
|
||||
"wchar",
|
||||
"wstring",
|
||||
};
|
||||
|
||||
|
||||
public static final String EXCEPTION_SUFFIX = "Exception";
|
||||
public static final String ERROR_SUFFIX = "Error";
|
||||
public static final String EX_SUFFIX = "Ex";
|
||||
|
||||
public static final String IDL_REPOSITORY_ID_PREFIX = "IDL:";
|
||||
public static final String IDL_REPOSITORY_ID_VERSION = ":1.0";
|
||||
|
||||
public static final String[] IDL_CORBA_MODULE = {"CORBA"};
|
||||
public static final String[] IDL_SEQUENCE_MODULE = {"org","omg","boxedRMI"};
|
||||
public static final String[] IDL_BOXEDIDL_MODULE = {"org","omg","boxedIDL"};
|
||||
|
||||
public static final String IDL_CLASS = "ClassDesc";
|
||||
public static final String[] IDL_CLASS_MODULE = {"javax","rmi","CORBA"};
|
||||
|
||||
public static final String IDL_IDLENTITY = "IDLEntity";
|
||||
public static final String IDL_SERIALIZABLE = "Serializable";
|
||||
public static final String IDL_EXTERNALIZABLE = "Externalizable";
|
||||
public static final String[] IDL_JAVA_IO_MODULE = {"java","io"};
|
||||
public static final String[] IDL_ORG_OMG_CORBA_MODULE = {"org","omg","CORBA"};
|
||||
public static final String[] IDL_ORG_OMG_CORBA_PORTABLE_MODULE = {"org","omg","CORBA","portable"};
|
||||
|
||||
public static final String IDL_JAVA_LANG_OBJECT = "_Object";
|
||||
public static final String[] IDL_JAVA_LANG_MODULE = {"java","lang"};
|
||||
|
||||
public static final String IDL_JAVA_RMI_REMOTE = "Remote";
|
||||
public static final String[] IDL_JAVA_RMI_MODULE = {"java","rmi"};
|
||||
|
||||
public static final String IDL_SEQUENCE = "seq";
|
||||
|
||||
public static final String IDL_CONSTRUCTOR = "create";
|
||||
|
||||
public static final String IDL_NAME_SEPARATOR = "::";
|
||||
public static final String IDL_BOOLEAN = "boolean";
|
||||
public static final String IDL_BYTE = "octet";
|
||||
public static final String IDL_CHAR = "wchar";
|
||||
public static final String IDL_SHORT = "short";
|
||||
public static final String IDL_INT = "long";
|
||||
public static final String IDL_LONG = "long long";
|
||||
public static final String IDL_FLOAT = "float";
|
||||
public static final String IDL_DOUBLE = "double";
|
||||
public static final String IDL_VOID = "void";
|
||||
|
||||
public static final String IDL_STRING = "WStringValue";
|
||||
public static final String IDL_CONSTANT_STRING = "wstring";
|
||||
public static final String IDL_CORBA_OBJECT = "Object";
|
||||
public static final String IDL_ANY = "any";
|
||||
|
||||
// File names:
|
||||
|
||||
public static final String SOURCE_FILE_EXTENSION = ".java";
|
||||
public static final String IDL_FILE_EXTENSION = ".idl";
|
||||
|
||||
// Type Codes:
|
||||
|
||||
public static final int TYPE_VOID = 0x00000001; // In PrimitiveType
|
||||
public static final int TYPE_BOOLEAN = 0x00000002; // In PrimitiveType
|
||||
public static final int TYPE_BYTE = 0x00000004; // In PrimitiveType
|
||||
public static final int TYPE_CHAR = 0x00000008; // In PrimitiveType
|
||||
public static final int TYPE_SHORT = 0x00000010; // In PrimitiveType
|
||||
public static final int TYPE_INT = 0x00000020; // In PrimitiveType
|
||||
public static final int TYPE_LONG = 0x00000040; // In PrimitiveType
|
||||
public static final int TYPE_FLOAT = 0x00000080; // In PrimitiveType
|
||||
public static final int TYPE_DOUBLE = 0x00000100; // In PrimitiveType
|
||||
|
||||
public static final int TYPE_STRING = 0x00000200; // In SpecialClassType (String)
|
||||
public static final int TYPE_ANY = 0x00000400; // In SpecialInterfaceType (Serializable,Externalizable)
|
||||
public static final int TYPE_CORBA_OBJECT = 0x00000800; // In SpecialInterfaceType (CORBA.Object,Remote)
|
||||
|
||||
public static final int TYPE_REMOTE = 0x00001000; // In RemoteType
|
||||
public static final int TYPE_ABSTRACT = 0x00002000; // In AbstractType
|
||||
public static final int TYPE_NC_INTERFACE = 0x00004000; // In NCInterfaceType
|
||||
|
||||
public static final int TYPE_VALUE = 0x00008000; // In ValueType
|
||||
public static final int TYPE_IMPLEMENTATION = 0x00010000; // In ImplementationType
|
||||
public static final int TYPE_NC_CLASS = 0x00020000; // In NCClassType
|
||||
|
||||
public static final int TYPE_ARRAY = 0x00040000; // In ArrayType
|
||||
public static final int TYPE_JAVA_RMI_REMOTE = 0x00080000; // In SpecialInterfaceType
|
||||
|
||||
// Type code masks:
|
||||
|
||||
public static final int TYPE_NONE = 0x00000000;
|
||||
public static final int TYPE_ALL = 0xFFFFFFFF;
|
||||
public static final int TYPE_MASK = 0x00FFFFFF;
|
||||
public static final int TM_MASK = 0xFF000000;
|
||||
|
||||
// Type code modifiers:
|
||||
|
||||
public static final int TM_PRIMITIVE = 0x01000000;
|
||||
public static final int TM_COMPOUND = 0x02000000;
|
||||
public static final int TM_CLASS = 0x04000000;
|
||||
public static final int TM_INTERFACE = 0x08000000;
|
||||
public static final int TM_SPECIAL_CLASS = 0x10000000;
|
||||
public static final int TM_SPECIAL_INTERFACE= 0x20000000;
|
||||
public static final int TM_NON_CONFORMING = 0x40000000;
|
||||
public static final int TM_INNER = 0x80000000;
|
||||
|
||||
// Attribute kinds...
|
||||
|
||||
public static final int ATTRIBUTE_NONE = 0; // Not an attribute.
|
||||
public static final int ATTRIBUTE_IS = 1; // read-only, had "is" prefix.
|
||||
public static final int ATTRIBUTE_GET = 2; // read-only, had "get" prefix.
|
||||
public static final int ATTRIBUTE_IS_RW = 3; // read-write, had "is" prefix.
|
||||
public static final int ATTRIBUTE_GET_RW = 4; // read-write, had "get" prefix.
|
||||
public static final int ATTRIBUTE_SET = 5; // had "set" prefix.
|
||||
|
||||
public static final String[] ATTRIBUTE_WIRE_PREFIX = {
|
||||
"",
|
||||
"_get_",
|
||||
"_get_",
|
||||
"_get_",
|
||||
"_get_",
|
||||
"_set_",
|
||||
};
|
||||
}
|
||||
41
jdkSrc/jdk8/sun/rmi/rmic/iiop/ContextElement.java
Normal file
41
jdkSrc/jdk8/sun/rmi/rmic/iiop/ContextElement.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
/**
|
||||
* ContextElement provides a common interface for elements of a ContextStack.
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public interface ContextElement {
|
||||
public String getElementName();
|
||||
}
|
||||
447
jdkSrc/jdk8/sun/rmi/rmic/iiop/ContextStack.java
Normal file
447
jdkSrc/jdk8/sun/rmi/rmic/iiop/ContextStack.java
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import sun.tools.java.CompilerError;
|
||||
|
||||
/**
|
||||
* ContextStack provides a mechanism to record parsing state.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class ContextStack {
|
||||
|
||||
// Context codes.
|
||||
|
||||
public static final int TOP = 1;
|
||||
|
||||
public static final int METHOD = 2;
|
||||
public static final int METHOD_RETURN = 3;
|
||||
public static final int METHOD_ARGUMENT = 4;
|
||||
public static final int METHOD_EXCEPTION = 5;
|
||||
|
||||
public static final int MEMBER = 6;
|
||||
public static final int MEMBER_CONSTANT = 7;
|
||||
public static final int MEMBER_STATIC = 8;
|
||||
public static final int MEMBER_TRANSIENT = 9;
|
||||
|
||||
public static final int IMPLEMENTS = 10;
|
||||
public static final int EXTENDS = 11;
|
||||
|
||||
// String versions of context codes.
|
||||
|
||||
private static final String[] CODE_NAMES = {
|
||||
"UNKNOWN ",
|
||||
"Top level type ",
|
||||
"Method ",
|
||||
"Return parameter ",
|
||||
"Parameter ",
|
||||
"Exception ",
|
||||
"Member ",
|
||||
"Constant member ",
|
||||
"Static member ",
|
||||
"Transient member ",
|
||||
"Implements ",
|
||||
"Extends ",
|
||||
};
|
||||
// Member data.
|
||||
|
||||
private int currentIndex = -1;
|
||||
private int maxIndex = 100;
|
||||
private TypeContext[] stack = new TypeContext[maxIndex];
|
||||
private int newCode = TOP;
|
||||
private BatchEnvironment env = null;
|
||||
private boolean trace = false;
|
||||
private TypeContext tempContext = new TypeContext();
|
||||
|
||||
private static final String TRACE_INDENT = " ";
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public ContextStack (BatchEnvironment env) {
|
||||
this.env = env;
|
||||
env.contextStack = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if env.nerrors > 0.
|
||||
*/
|
||||
public boolean anyErrors () {
|
||||
return env.nerrors > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable tracing.
|
||||
*/
|
||||
public void setTrace(boolean trace) {
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check trace flag.
|
||||
*/
|
||||
public boolean isTraceOn() {
|
||||
return trace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the environment.
|
||||
*/
|
||||
public BatchEnvironment getEnv() {
|
||||
return env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new context.
|
||||
*/
|
||||
public void setNewContextCode(int code) {
|
||||
newCode = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current context code.
|
||||
*/
|
||||
public int getCurrentContextCode() {
|
||||
return newCode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If tracing on, write the current call stack (not the context stack) to
|
||||
* System.out.
|
||||
*/
|
||||
final void traceCallStack () {
|
||||
if (trace) dumpCallStack();
|
||||
}
|
||||
|
||||
public final static void dumpCallStack() {
|
||||
new Error().printStackTrace(System.out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a line indented by stack depth.
|
||||
*/
|
||||
final private void tracePrint (String text, boolean line) {
|
||||
int length = text.length() + (currentIndex * TRACE_INDENT.length());
|
||||
StringBuffer buffer = new StringBuffer(length);
|
||||
for (int i = 0; i < currentIndex; i++) {
|
||||
buffer.append(TRACE_INDENT);
|
||||
}
|
||||
buffer.append(text);
|
||||
if (line) {
|
||||
buffer.append("\n");
|
||||
}
|
||||
System.out.print(buffer.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* If tracing on, print a line.
|
||||
*/
|
||||
final void trace (String text) {
|
||||
if (trace) {
|
||||
tracePrint(text,false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If tracing on, print a line followed by a '\n'.
|
||||
*/
|
||||
final void traceln (String text) {
|
||||
if (trace) {
|
||||
tracePrint(text,true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If tracing on, print a pre-mapped ContextElement.
|
||||
*/
|
||||
final void traceExistingType (Type type) {
|
||||
if (trace) {
|
||||
tempContext.set(newCode,type);
|
||||
traceln(toResultString(tempContext,true,true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a new element on the stack.
|
||||
* @return the new element.
|
||||
*/
|
||||
public TypeContext push (ContextElement element) {
|
||||
|
||||
currentIndex++;
|
||||
|
||||
// Grow array if need to...
|
||||
|
||||
if (currentIndex == maxIndex) {
|
||||
int newMax = maxIndex * 2;
|
||||
TypeContext[] newStack = new TypeContext[newMax];
|
||||
System.arraycopy(stack,0,newStack,0,maxIndex);
|
||||
maxIndex = newMax;
|
||||
stack = newStack;
|
||||
}
|
||||
|
||||
// Make sure we have a context object to use at this position...
|
||||
|
||||
TypeContext it = stack[currentIndex];
|
||||
|
||||
if (it == null) {
|
||||
it = new TypeContext();
|
||||
stack[currentIndex] = it;
|
||||
}
|
||||
|
||||
// Set the context object...
|
||||
|
||||
it.set(newCode,element);
|
||||
|
||||
// Trace...
|
||||
|
||||
traceln(toTrialString(it));
|
||||
|
||||
// Return...
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop an element from the stack.
|
||||
* @return the new current element or null if top.
|
||||
*/
|
||||
public TypeContext pop (boolean wasValid) {
|
||||
|
||||
if (currentIndex < 0) {
|
||||
throw new CompilerError("Nothing on stack!");
|
||||
}
|
||||
|
||||
newCode = stack[currentIndex].getCode();
|
||||
traceln(toResultString(stack[currentIndex],wasValid,false));
|
||||
|
||||
Type last = stack[currentIndex].getCandidateType();
|
||||
if (last != null) {
|
||||
|
||||
// Set status...
|
||||
|
||||
if (wasValid) {
|
||||
last.setStatus(Constants.STATUS_VALID);
|
||||
} else {
|
||||
last.setStatus(Constants.STATUS_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
currentIndex--;
|
||||
|
||||
if (currentIndex < 0) {
|
||||
|
||||
// Done parsing, so update the invalid types
|
||||
// if this type was valid...
|
||||
|
||||
if (wasValid) {
|
||||
Type.updateAllInvalidTypes(this);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return stack[currentIndex];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current size.
|
||||
*/
|
||||
public int size () {
|
||||
return currentIndex + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific context.
|
||||
*/
|
||||
public TypeContext getContext (int index) {
|
||||
|
||||
if (currentIndex < index) {
|
||||
throw new Error("Index out of range");
|
||||
}
|
||||
return stack[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current top context.
|
||||
*/
|
||||
public TypeContext getContext () {
|
||||
|
||||
if (currentIndex < 0) {
|
||||
throw new Error("Nothing on stack!");
|
||||
}
|
||||
return stack[currentIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Is parent context a value type?
|
||||
*/
|
||||
public boolean isParentAValue () {
|
||||
|
||||
if (currentIndex > 0) {
|
||||
return stack[currentIndex - 1].isValue();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parent context. Null if none.
|
||||
*/
|
||||
public TypeContext getParentContext () {
|
||||
|
||||
if (currentIndex > 0) {
|
||||
return stack[currentIndex - 1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string for the context name...
|
||||
*/
|
||||
public String getContextCodeString () {
|
||||
|
||||
if (currentIndex >= 0) {
|
||||
return CODE_NAMES[newCode];
|
||||
} else {
|
||||
return CODE_NAMES[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string for the given context code...
|
||||
*/
|
||||
public static String getContextCodeString (int contextCode) {
|
||||
return CODE_NAMES[contextCode];
|
||||
}
|
||||
|
||||
private String toTrialString(TypeContext it) {
|
||||
int code = it.getCode();
|
||||
if (code != METHOD && code != MEMBER) {
|
||||
return it.toString() + " (trying " + it.getTypeDescription() + ")";
|
||||
} else {
|
||||
return it.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private String toResultString (TypeContext it, boolean result, boolean preExisting) {
|
||||
int code = it.getCode();
|
||||
if (code != METHOD && code != MEMBER) {
|
||||
if (result) {
|
||||
String str = it.toString() + " --> " + it.getTypeDescription();
|
||||
if (preExisting) {
|
||||
return str + " [Previously mapped]";
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (result) {
|
||||
return it.toString() + " --> [Mapped]";
|
||||
}
|
||||
}
|
||||
return it.toString() + " [Did not map]";
|
||||
}
|
||||
|
||||
public void clear () {
|
||||
for (int i = 0; i < stack.length; i++) {
|
||||
if (stack[i] != null) stack[i].destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TypeContext {
|
||||
|
||||
public void set(int code, ContextElement element) {
|
||||
this.code = code;
|
||||
this.element = element;
|
||||
if (element instanceof ValueType) {
|
||||
isValue = true;
|
||||
} else {
|
||||
isValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return element.getElementName();
|
||||
}
|
||||
|
||||
public Type getCandidateType() {
|
||||
if (element instanceof Type) {
|
||||
return (Type) element;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getTypeDescription() {
|
||||
if (element instanceof Type) {
|
||||
return ((Type) element).getTypeDescription();
|
||||
} else {
|
||||
return "[unknown type]";
|
||||
}
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
if (element != null) {
|
||||
return ContextStack.getContextCodeString(code) + element.getElementName();
|
||||
} else {
|
||||
return ContextStack.getContextCodeString(code) + "null";
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValue () {
|
||||
return isValue;
|
||||
}
|
||||
|
||||
public boolean isConstant () {
|
||||
return code == ContextStack.MEMBER_CONSTANT;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (element instanceof Type) {
|
||||
((Type)element).destroy();
|
||||
}
|
||||
element = null;
|
||||
}
|
||||
|
||||
private int code = 0;
|
||||
private ContextElement element = null;
|
||||
private boolean isValue = false;
|
||||
}
|
||||
160
jdkSrc/jdk8/sun/rmi/rmic/iiop/DirectoryLoader.java
Normal file
160
jdkSrc/jdk8/sun/rmi/rmic/iiop/DirectoryLoader.java
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
/**
|
||||
* DirectoryLoader is a simple ClassLoader which loads from a specified
|
||||
* file system directory.
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
|
||||
public class DirectoryLoader extends ClassLoader {
|
||||
|
||||
private Hashtable cache;
|
||||
private File root;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public DirectoryLoader (File rootDir) {
|
||||
cache = new Hashtable();
|
||||
if (rootDir == null || !rootDir.isDirectory()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
root = rootDir;
|
||||
}
|
||||
|
||||
private DirectoryLoader () {}
|
||||
|
||||
/**
|
||||
* Convenience version of loadClass which sets 'resolve' == true.
|
||||
*/
|
||||
public Class loadClass(String className) throws ClassNotFoundException {
|
||||
return loadClass(className, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the required version of loadClass which is called
|
||||
* both from loadClass above and from the internal function
|
||||
* FindClassFromClass.
|
||||
*/
|
||||
public synchronized Class loadClass(String className, boolean resolve)
|
||||
throws ClassNotFoundException {
|
||||
Class result;
|
||||
byte classData[];
|
||||
|
||||
// Do we already have it in the cache?
|
||||
|
||||
result = (Class) cache.get(className);
|
||||
|
||||
if (result == null) {
|
||||
|
||||
// Nope, can we get if from the system class loader?
|
||||
|
||||
try {
|
||||
|
||||
result = super.findSystemClass(className);
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
||||
// No, so try loading it...
|
||||
|
||||
classData = getClassFileData(className);
|
||||
|
||||
if (classData == null) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
|
||||
// Parse the class file data...
|
||||
|
||||
result = defineClass(classData, 0, classData.length);
|
||||
|
||||
if (result == null) {
|
||||
throw new ClassFormatError();
|
||||
}
|
||||
|
||||
// Resolve it...
|
||||
|
||||
if (resolve) resolveClass(result);
|
||||
|
||||
// Add to cache...
|
||||
|
||||
cache.put(className, result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reurn a byte array containing the contents of the class file. Returns null
|
||||
* if an exception occurs.
|
||||
*/
|
||||
private byte[] getClassFileData (String className) {
|
||||
|
||||
byte result[] = null;
|
||||
FileInputStream stream = null;
|
||||
|
||||
// Get the file...
|
||||
|
||||
File classFile = new File(root,className.replace('.',File.separatorChar) + ".class");
|
||||
|
||||
// Now get the bits...
|
||||
|
||||
try {
|
||||
stream = new FileInputStream(classFile);
|
||||
result = new byte[stream.available()];
|
||||
stream.read(result);
|
||||
} catch(ThreadDeath death) {
|
||||
throw death;
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
|
||||
finally {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch(ThreadDeath death) {
|
||||
throw death;
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
436
jdkSrc/jdk8/sun/rmi/rmic/iiop/Generator.java
Normal file
436
jdkSrc/jdk8/sun/rmi/rmic/iiop/Generator.java
Normal file
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.IOException;
|
||||
import sun.tools.java.Identifier;
|
||||
import sun.tools.java.ClassPath;
|
||||
import sun.tools.java.ClassFile;
|
||||
import sun.tools.java.ClassNotFound;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
import sun.tools.java.ClassDeclaration;
|
||||
import sun.rmi.rmic.IndentingWriter;
|
||||
import sun.rmi.rmic.Main;
|
||||
import sun.rmi.rmic.iiop.Util;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Generator provides a small framework from which IIOP-specific
|
||||
* generators can inherit. Common logic is implemented here which uses
|
||||
* both abstract methods as well as concrete methods which subclasses may
|
||||
* want to override. The following methods must be present in any subclass:
|
||||
* <pre>
|
||||
* Default constructor
|
||||
* CompoundType getTopType(BatchEnvironment env, ClassDefinition cdef);
|
||||
* int parseArgs(String argv[], int currentIndex);
|
||||
* boolean requireNewInstance();
|
||||
* OutputType[] getOutputTypesFor(CompoundType topType,
|
||||
* HashSet alreadyChecked);
|
||||
* String getFileNameExtensionFor(OutputType outputType);
|
||||
* void writeOutputFor ( OutputType outputType,
|
||||
* HashSet alreadyChecked,
|
||||
* IndentingWriter writer) throws IOException;
|
||||
* </pre>
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public abstract class Generator implements sun.rmi.rmic.Generator,
|
||||
sun.rmi.rmic.iiop.Constants {
|
||||
|
||||
protected boolean alwaysGenerate = false;
|
||||
protected BatchEnvironment env = null;
|
||||
protected ContextStack contextStack = null;
|
||||
private boolean trace = false;
|
||||
protected boolean idl = false;
|
||||
|
||||
/**
|
||||
* Examine and consume command line arguments.
|
||||
* @param argv The command line arguments. Ignore null
|
||||
* and unknown arguments. Set each consumed argument to null.
|
||||
* @param error Report any errors using the main.error() methods.
|
||||
* @return true if no errors, false otherwise.
|
||||
*/
|
||||
public boolean parseArgs(String argv[], Main main) {
|
||||
for (int i = 0; i < argv.length; i++) {
|
||||
if (argv[i] != null) {
|
||||
if (argv[i].equalsIgnoreCase("-always") ||
|
||||
argv[i].equalsIgnoreCase("-alwaysGenerate")) {
|
||||
alwaysGenerate = true;
|
||||
argv[i] = null;
|
||||
} else if (argv[i].equalsIgnoreCase("-xtrace")) {
|
||||
trace = true;
|
||||
argv[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if non-conforming types should be parsed.
|
||||
* @param stack The context stack.
|
||||
*/
|
||||
protected abstract boolean parseNonConforming(ContextStack stack);
|
||||
|
||||
/**
|
||||
* Create and return a top-level type.
|
||||
* @param cdef The top-level class definition.
|
||||
* @param stack The context stack.
|
||||
* @return The compound type or null if is non-conforming.
|
||||
*/
|
||||
protected abstract CompoundType getTopType(ClassDefinition cdef, ContextStack stack);
|
||||
|
||||
/**
|
||||
* Return an array containing all the file names and types that need to be
|
||||
* generated for the given top-level type. The file names must NOT have an
|
||||
* extension (e.g. ".java").
|
||||
* @param topType The type returned by getTopType().
|
||||
* @param alreadyChecked A set of Types which have already been checked.
|
||||
* Intended to be passed to Type.collectMatching(filter,alreadyChecked).
|
||||
*/
|
||||
protected abstract OutputType[] getOutputTypesFor(CompoundType topType,
|
||||
HashSet alreadyChecked);
|
||||
|
||||
/**
|
||||
* Return the file name extension for the given file name (e.g. ".java").
|
||||
* All files generated with the ".java" extension will be compiled. To
|
||||
* change this behavior for ".java" files, override the compileJavaSourceFile
|
||||
* method to return false.
|
||||
* @param outputType One of the items returned by getOutputTypesFor(...)
|
||||
*/
|
||||
protected abstract String getFileNameExtensionFor(OutputType outputType);
|
||||
|
||||
/**
|
||||
* Write the output for the given OutputFileName into the output stream.
|
||||
* @param name One of the items returned by getOutputTypesFor(...)
|
||||
* @param alreadyChecked A set of Types which have already been checked.
|
||||
* Intended to be passed to Type.collectMatching(filter,alreadyChecked).
|
||||
* @param writer The output stream.
|
||||
*/
|
||||
protected abstract void writeOutputFor(OutputType outputType,
|
||||
HashSet alreadyChecked,
|
||||
IndentingWriter writer) throws IOException;
|
||||
|
||||
/**
|
||||
* Return true if a new instance should be created for each
|
||||
* class on the command line. Subclasses which return true
|
||||
* should override newInstance() to return an appropriately
|
||||
* constructed instance.
|
||||
*/
|
||||
protected abstract boolean requireNewInstance();
|
||||
|
||||
/**
|
||||
* Return true if the specified file needs generation.
|
||||
*/
|
||||
public boolean requiresGeneration (File target, Type theType) {
|
||||
|
||||
boolean result = alwaysGenerate;
|
||||
|
||||
if (!result) {
|
||||
|
||||
// Get a ClassFile instance for base source or class
|
||||
// file. We use ClassFile so that if the base is in
|
||||
// a zip file, we can still get at it's mod time...
|
||||
|
||||
ClassFile baseFile;
|
||||
ClassPath path = env.getClassPath();
|
||||
String className = theType.getQualifiedName().replace('.',File.separatorChar);
|
||||
|
||||
// First try the source file...
|
||||
|
||||
baseFile = path.getFile(className + ".source");
|
||||
|
||||
if (baseFile == null) {
|
||||
|
||||
// Then try class file...
|
||||
|
||||
baseFile = path.getFile(className + ".class");
|
||||
}
|
||||
|
||||
// Do we have a baseFile?
|
||||
|
||||
if (baseFile != null) {
|
||||
|
||||
// Yes, grab baseFile's mod time...
|
||||
|
||||
long baseFileMod = baseFile.lastModified();
|
||||
|
||||
// Get a File instance for the target. If it is a source
|
||||
// file, create a class file instead since the source file
|
||||
// will frequently be deleted...
|
||||
|
||||
String targetName = IDLNames.replace(target.getName(),".java",".class");
|
||||
String parentPath = target.getParent();
|
||||
File targetFile = new File(parentPath,targetName);
|
||||
|
||||
// Does the target file exist?
|
||||
|
||||
if (targetFile.exists()) {
|
||||
|
||||
// Yes, so grab it's mod time...
|
||||
|
||||
long targetFileMod = targetFile.lastModified();
|
||||
|
||||
// Set result...
|
||||
|
||||
result = targetFileMod < baseFileMod;
|
||||
|
||||
} else {
|
||||
|
||||
// No, so we must generate...
|
||||
|
||||
result = true;
|
||||
}
|
||||
} else {
|
||||
|
||||
// No, so we must generate...
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new instance of self. Subclasses
|
||||
* which need to do something other than default construction
|
||||
* must override this method.
|
||||
*/
|
||||
protected Generator newInstance() {
|
||||
Generator result = null;
|
||||
try {
|
||||
result = (Generator) getClass().newInstance();
|
||||
}
|
||||
catch (Exception e){} // Should ALWAYS work!
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor for subclasses to use.
|
||||
*/
|
||||
protected Generator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate output. Any source files created which need compilation should
|
||||
* be added to the compiler environment using the addGeneratedFile(File)
|
||||
* method.
|
||||
*
|
||||
* @param env The compiler environment
|
||||
* @param cdef The definition for the implementation class or interface from
|
||||
* which to generate output
|
||||
* @param destDir The directory for the root of the package hierarchy
|
||||
* for generated files. May be null.
|
||||
*/
|
||||
public void generate(sun.rmi.rmic.BatchEnvironment env, ClassDefinition cdef, File destDir) {
|
||||
|
||||
this.env = (BatchEnvironment) env;
|
||||
contextStack = new ContextStack(this.env);
|
||||
contextStack.setTrace(trace);
|
||||
|
||||
// Make sure the environment knows whether or not to parse
|
||||
// non-conforming types. This will clear out any previously
|
||||
// parsed types if necessary...
|
||||
|
||||
this.env.setParseNonConforming(parseNonConforming(contextStack));
|
||||
|
||||
// Get our top level type...
|
||||
|
||||
CompoundType topType = getTopType(cdef,contextStack);
|
||||
if (topType != null) {
|
||||
|
||||
Generator generator = this;
|
||||
|
||||
// Do we need to make a new instance?
|
||||
|
||||
if (requireNewInstance()) {
|
||||
|
||||
// Yes, so make one. 'this' instance is the one instantiated by Main
|
||||
// and which knows any needed command line args...
|
||||
|
||||
generator = newInstance();
|
||||
}
|
||||
|
||||
// Now generate all output files...
|
||||
|
||||
generator.generateOutputFiles(topType, this.env, destDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new instance of self. Subclasses
|
||||
* which need to do something other than default construction
|
||||
* must override this method.
|
||||
*/
|
||||
protected void generateOutputFiles (CompoundType topType,
|
||||
BatchEnvironment env,
|
||||
File destDir) {
|
||||
|
||||
// Grab the 'alreadyChecked' HashSet from the environment...
|
||||
|
||||
HashSet alreadyChecked = env.alreadyChecked;
|
||||
|
||||
// Ask subclass for a list of output types...
|
||||
|
||||
OutputType[] types = getOutputTypesFor(topType,alreadyChecked);
|
||||
|
||||
// Process each file...
|
||||
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
OutputType current = types[i];
|
||||
String className = current.getName();
|
||||
File file = getFileFor(current,destDir);
|
||||
boolean sourceFile = false;
|
||||
|
||||
// Do we need to generate this file?
|
||||
|
||||
if (requiresGeneration(file,current.getType())) {
|
||||
|
||||
// Yes. If java source file, add to environment so will be compiled...
|
||||
|
||||
if (file.getName().endsWith(".java")) {
|
||||
sourceFile = compileJavaSourceFile(current);
|
||||
|
||||
// Are we supposeded to compile this one?
|
||||
|
||||
if (sourceFile) {
|
||||
env.addGeneratedFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
// Now create an output stream and ask subclass to fill it up...
|
||||
|
||||
try {
|
||||
IndentingWriter out = new IndentingWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(file)),INDENT_STEP,TAB_SIZE);
|
||||
|
||||
long startTime = 0;
|
||||
if (env.verbose()) {
|
||||
startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
writeOutputFor(types[i],alreadyChecked,out);
|
||||
out.close();
|
||||
|
||||
if (env.verbose()) {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
env.output(Main.getText("rmic.generated", file.getPath(), Long.toString(duration)));
|
||||
}
|
||||
if (sourceFile) {
|
||||
env.parseFile(new ClassFile(file));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
env.error(0, "cant.write", file.toString());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
||||
// No, say so if we need to...
|
||||
|
||||
if (env.verbose()) {
|
||||
env.output(Main.getText("rmic.previously.generated", file.getPath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the File object that should be used as the output file
|
||||
* for the given OutputType.
|
||||
* @param outputType The type to create a file for.
|
||||
* @param destinationDir The directory to use as the root of the
|
||||
* package heirarchy. May be null, in which case the current
|
||||
* classpath is searched to find the directory in which to create
|
||||
* the output file. If that search fails (most likely because the
|
||||
* package directory lives in a zip or jar file rather than the
|
||||
* file system), the current user directory is used.
|
||||
*/
|
||||
protected File getFileFor(OutputType outputType, File destinationDir) {
|
||||
// Calling this method does some crucial initialization
|
||||
// in a subclass implementation. Don't skip it.
|
||||
Identifier id = getOutputId(outputType);
|
||||
File packageDir = null;
|
||||
if(idl){
|
||||
packageDir = Util.getOutputDirectoryForIDL(id,destinationDir,env);
|
||||
} else {
|
||||
packageDir = Util.getOutputDirectoryForStub(id,destinationDir,env);
|
||||
}
|
||||
String classFileName = outputType.getName() + getFileNameExtensionFor(outputType);
|
||||
return new File(packageDir, classFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an identifier to use for output.
|
||||
* @param outputType the type for which output is to be generated.
|
||||
* @return the new identifier. This implementation returns the input parameter.
|
||||
*/
|
||||
protected Identifier getOutputId (OutputType outputType) {
|
||||
return outputType.getType().getIdentifier();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given file should be compiled.
|
||||
* @param outputType One of the items returned by getOutputTypesFor(...) for
|
||||
* which getFileNameExtensionFor(OutputType) returned ".java".
|
||||
*/
|
||||
protected boolean compileJavaSourceFile (OutputType outputType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// OutputType is a simple wrapper for a name and a Type
|
||||
//_____________________________________________________________________
|
||||
|
||||
public class OutputType {
|
||||
private String name;
|
||||
private Type type;
|
||||
|
||||
public OutputType (String name, Type type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
2084
jdkSrc/jdk8/sun/rmi/rmic/iiop/IDLGenerator.java
Normal file
2084
jdkSrc/jdk8/sun/rmi/rmic/iiop/IDLGenerator.java
Normal file
File diff suppressed because it is too large
Load Diff
1227
jdkSrc/jdk8/sun/rmi/rmic/iiop/IDLNames.java
Normal file
1227
jdkSrc/jdk8/sun/rmi/rmic/iiop/IDLNames.java
Normal file
File diff suppressed because it is too large
Load Diff
292
jdkSrc/jdk8/sun/rmi/rmic/iiop/ImplementationType.java
Normal file
292
jdkSrc/jdk8/sun/rmi/rmic/iiop/ImplementationType.java
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.util.Vector;
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.ClassNotFound;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
import sun.tools.java.MemberDefinition;
|
||||
|
||||
/**
|
||||
* ImplementationType represents any non-special class which implements
|
||||
* one or more interfaces which inherit from java.rmi.Remote.
|
||||
* <p>
|
||||
* The static forImplementation(...) method must be used to obtain an instance,
|
||||
* and will return null if the ClassDefinition is non-conforming.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class ImplementationType extends ClassType {
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create an ImplementationType for the given class.
|
||||
*
|
||||
* If the class is not a properly formed or if some other error occurs, the
|
||||
* return value will be null, and errors will have been reported to the
|
||||
* supplied BatchEnvironment.
|
||||
*/
|
||||
public static ImplementationType forImplementation(ClassDefinition classDef,
|
||||
ContextStack stack,
|
||||
boolean quiet) {
|
||||
if (stack.anyErrors()) return null;
|
||||
|
||||
boolean doPop = false;
|
||||
ImplementationType result = null;
|
||||
|
||||
try {
|
||||
// Do we already have it?
|
||||
|
||||
sun.tools.java.Type theType = classDef.getType();
|
||||
Type existing = getType(theType,stack);
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
if (!(existing instanceof ImplementationType)) return null; // False hit.
|
||||
|
||||
// Yep, so return it...
|
||||
|
||||
return (ImplementationType) existing;
|
||||
|
||||
}
|
||||
|
||||
// Could this be an implementation?
|
||||
|
||||
if (couldBeImplementation(quiet,stack,classDef)) {
|
||||
|
||||
// Yes, so check it...
|
||||
|
||||
ImplementationType it = new ImplementationType(stack, classDef);
|
||||
putType(theType,it,stack);
|
||||
stack.push(it);
|
||||
doPop = true;
|
||||
|
||||
if (it.initialize(stack,quiet)) {
|
||||
stack.pop(true);
|
||||
result = it;
|
||||
} else {
|
||||
removeType(theType,stack);
|
||||
stack.pop(false);
|
||||
}
|
||||
}
|
||||
} catch (CompilerError e) {
|
||||
if (doPop) stack.pop(false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string describing this type.
|
||||
*/
|
||||
public String getTypeDescription () {
|
||||
return "Implementation";
|
||||
}
|
||||
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create a ImplementationType instance for the given class. The resulting
|
||||
* object is not yet completely initialized.
|
||||
*/
|
||||
private ImplementationType(ContextStack stack, ClassDefinition classDef) {
|
||||
super(TYPE_IMPLEMENTATION | TM_CLASS | TM_COMPOUND,classDef,stack); // Use special constructor.
|
||||
}
|
||||
|
||||
|
||||
private static boolean couldBeImplementation(boolean quiet, ContextStack stack,
|
||||
ClassDefinition classDef) {
|
||||
boolean result = false;
|
||||
BatchEnvironment env = stack.getEnv();
|
||||
|
||||
try {
|
||||
if (!classDef.isClass()) {
|
||||
failedConstraint(17,quiet,stack,classDef.getName());
|
||||
} else {
|
||||
result = env.defRemote.implementedBy(env, classDef.getClassDeclaration());
|
||||
if (!result) failedConstraint(8,quiet,stack,classDef.getName());
|
||||
}
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize this instance.
|
||||
*/
|
||||
private boolean initialize (ContextStack stack, boolean quiet) {
|
||||
|
||||
boolean result = false;
|
||||
ClassDefinition theClass = getClassDefinition();
|
||||
|
||||
if (initParents(stack)) {
|
||||
|
||||
// Make up our collections...
|
||||
|
||||
Vector directInterfaces = new Vector();
|
||||
Vector directMethods = new Vector();
|
||||
|
||||
// Check interfaces...
|
||||
|
||||
try {
|
||||
if (addRemoteInterfaces(directInterfaces,true,stack) != null) {
|
||||
|
||||
boolean haveRemote = false;
|
||||
|
||||
// Get methods from all interfaces...
|
||||
|
||||
for (int i = 0; i < directInterfaces.size(); i++) {
|
||||
InterfaceType theInt = (InterfaceType) directInterfaces.elementAt(i);
|
||||
if (theInt.isType(TYPE_REMOTE) ||
|
||||
theInt.isType(TYPE_JAVA_RMI_REMOTE)) {
|
||||
haveRemote = true;
|
||||
}
|
||||
|
||||
copyRemoteMethods(theInt,directMethods);
|
||||
}
|
||||
|
||||
// Make sure we have at least one remote interface...
|
||||
|
||||
if (!haveRemote) {
|
||||
failedConstraint(8,quiet,stack,getQualifiedName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now check the methods to ensure we have the
|
||||
// correct throws clauses...
|
||||
|
||||
if (checkMethods(theClass,directMethods,stack,quiet)) {
|
||||
|
||||
// We're ok, so pass 'em up...
|
||||
|
||||
result = initialize(directInterfaces,directMethods,null,stack,quiet);
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void copyRemoteMethods(InterfaceType type, Vector list) {
|
||||
|
||||
if (type.isType(TYPE_REMOTE)) {
|
||||
|
||||
// Copy all the unique methods from type...
|
||||
|
||||
Method[] allMethods = type.getMethods();
|
||||
|
||||
for (int i = 0; i < allMethods.length; i++) {
|
||||
Method theMethod = allMethods[i];
|
||||
|
||||
if (!list.contains(theMethod)) {
|
||||
list.addElement(theMethod);
|
||||
}
|
||||
}
|
||||
|
||||
// Now recurse thru all inherited interfaces...
|
||||
|
||||
InterfaceType[] allInterfaces = type.getInterfaces();
|
||||
|
||||
for (int i = 0; i < allInterfaces.length; i++) {
|
||||
copyRemoteMethods(allInterfaces[i],list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Walk all methods of the class, and for each that is already in
|
||||
// the list, call setImplExceptions()...
|
||||
|
||||
private boolean checkMethods(ClassDefinition theClass, Vector list,
|
||||
ContextStack stack, boolean quiet) {
|
||||
|
||||
// Convert vector to array...
|
||||
|
||||
Method[] methods = new Method[list.size()];
|
||||
list.copyInto(methods);
|
||||
|
||||
for (MemberDefinition member = theClass.getFirstMember();
|
||||
member != null;
|
||||
member = member.getNextMember()) {
|
||||
|
||||
if (member.isMethod() && !member.isConstructor()
|
||||
&& !member.isInitializer()) {
|
||||
|
||||
// It's a method...
|
||||
|
||||
if (!updateExceptions(member,methods,stack,quiet)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean updateExceptions (MemberDefinition implMethod, Method[] list,
|
||||
ContextStack stack, boolean quiet) {
|
||||
int length = list.length;
|
||||
String implMethodSig = implMethod.toString();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
Method existingMethod = list[i];
|
||||
MemberDefinition existing = existingMethod.getMemberDefinition();
|
||||
|
||||
// Do we have a matching method?
|
||||
|
||||
if (implMethodSig.equals(existing.toString())) {
|
||||
|
||||
// Yes, so create exception list...
|
||||
|
||||
try {
|
||||
ValueType[] implExcept = getMethodExceptions(implMethod,quiet,stack);
|
||||
existingMethod.setImplExceptions(implExcept);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
122
jdkSrc/jdk8/sun/rmi/rmic/iiop/InterfaceType.java
Normal file
122
jdkSrc/jdk8/sun/rmi/rmic/iiop/InterfaceType.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.io.IOException;
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
import sun.rmi.rmic.IndentingWriter;
|
||||
|
||||
/**
|
||||
* InterfaceType is an abstract base representing any non-special
|
||||
* interface type.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public abstract class InterfaceType extends CompoundType {
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Print this type.
|
||||
* @param writer The stream to print to.
|
||||
* @param useQualifiedNames If true, print qualified names; otherwise, print unqualified names.
|
||||
* @param useIDLNames If true, print IDL names; otherwise, print java names.
|
||||
* @param globalIDLNames If true and useIDLNames true, prepends "::".
|
||||
*/
|
||||
public void print ( IndentingWriter writer,
|
||||
boolean useQualifiedNames,
|
||||
boolean useIDLNames,
|
||||
boolean globalIDLNames) throws IOException {
|
||||
|
||||
if (isInner()) {
|
||||
writer.p("// " + getTypeDescription() + " (INNER)");
|
||||
} else {
|
||||
writer.p("// " + getTypeDescription() + "");
|
||||
}
|
||||
writer.pln(" (" + getRepositoryID() + ")\n");
|
||||
printPackageOpen(writer,useIDLNames);
|
||||
|
||||
if (!useIDLNames) {
|
||||
writer.p("public ");
|
||||
}
|
||||
|
||||
writer.p("interface " + getTypeName(false,useIDLNames,false));
|
||||
printImplements(writer,"",useQualifiedNames,useIDLNames,globalIDLNames);
|
||||
writer.plnI(" {");
|
||||
printMembers(writer,useQualifiedNames,useIDLNames,globalIDLNames);
|
||||
writer.pln();
|
||||
printMethods(writer,useQualifiedNames,useIDLNames,globalIDLNames);
|
||||
writer.pln();
|
||||
|
||||
if (useIDLNames) {
|
||||
writer.pOln("};");
|
||||
} else {
|
||||
writer.pOln("}");
|
||||
}
|
||||
printPackageClose(writer,useIDLNames);
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Subclass/Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create a InterfaceType instance for the given class. NOTE: This constructor
|
||||
* is ONLY for SpecialInterfaceType.
|
||||
*/
|
||||
protected InterfaceType(ContextStack stack, int typeCode, ClassDefinition classDef) {
|
||||
super(stack,typeCode,classDef); // Call special parent constructor.
|
||||
|
||||
if ((typeCode & TM_INTERFACE) == 0 || ! classDef.isInterface()) {
|
||||
throw new CompilerError("Not an interface");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a InterfaceType instance for the given class. The resulting
|
||||
* object is not yet completely initialized. Subclasses must call
|
||||
* initialize(directInterfaces,directInterfaces,directConstants);
|
||||
*/
|
||||
protected InterfaceType(ContextStack stack,
|
||||
ClassDefinition classDef,
|
||||
int typeCode) {
|
||||
super(stack,classDef,typeCode);
|
||||
|
||||
if ((typeCode & TM_INTERFACE) == 0 || ! classDef.isInterface()) {
|
||||
throw new CompilerError("Not an interface");
|
||||
}
|
||||
}
|
||||
}
|
||||
172
jdkSrc/jdk8/sun/rmi/rmic/iiop/NCClassType.java
Normal file
172
jdkSrc/jdk8/sun/rmi/rmic/iiop/NCClassType.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.util.Vector;
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.ClassNotFound;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
|
||||
/**
|
||||
* NCClassType represents any non-special class which does not
|
||||
* extends one or more interfaces which inherit from java.rmi.Remote.
|
||||
* <p>
|
||||
* The static forImplementation(...) method must be used to obtain an instance,
|
||||
* and will return null if the ClassDefinition is non-conforming.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class NCClassType extends ClassType {
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create an NCClassType for the given class.
|
||||
*
|
||||
* If the class is not a properly formed or if some other error occurs, the
|
||||
* return value will be null, and errors will have been reported to the
|
||||
* supplied BatchEnvironment.
|
||||
*/
|
||||
public static NCClassType forNCClass(ClassDefinition classDef,
|
||||
ContextStack stack) {
|
||||
|
||||
if (stack.anyErrors()) return null;
|
||||
|
||||
boolean doPop = false;
|
||||
try {
|
||||
// Do we already have it?
|
||||
|
||||
sun.tools.java.Type theType = classDef.getType();
|
||||
Type existing = getType(theType,stack);
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
if (!(existing instanceof NCClassType)) return null; // False hit.
|
||||
|
||||
// Yep, so return it...
|
||||
|
||||
return (NCClassType) existing;
|
||||
|
||||
}
|
||||
|
||||
NCClassType it = new NCClassType(stack, classDef);
|
||||
putType(theType,it,stack);
|
||||
stack.push(it);
|
||||
doPop = true;
|
||||
|
||||
if (it.initialize(stack)) {
|
||||
stack.pop(true);
|
||||
return it;
|
||||
} else {
|
||||
removeType(theType,stack);
|
||||
stack.pop(false);
|
||||
return null;
|
||||
}
|
||||
} catch (CompilerError e) {
|
||||
if (doPop) stack.pop(false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string describing this type.
|
||||
*/
|
||||
public String getTypeDescription () {
|
||||
return addExceptionDescription("Non-conforming class");
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Internal/Subclass Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create a NCClassType instance for the given class. The resulting
|
||||
* object is not yet completely initialized.
|
||||
*/
|
||||
private NCClassType(ContextStack stack, ClassDefinition classDef) {
|
||||
super(stack,classDef,TYPE_NC_CLASS | TM_CLASS | TM_COMPOUND);
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Initialize this instance.
|
||||
*/
|
||||
private boolean initialize (ContextStack stack) {
|
||||
if (!initParents(stack)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stack.getEnv().getParseNonConforming()) {
|
||||
|
||||
Vector directInterfaces = new Vector();
|
||||
Vector directMethods = new Vector();
|
||||
Vector directMembers = new Vector();
|
||||
|
||||
try {
|
||||
|
||||
// Get methods...
|
||||
|
||||
if (addAllMethods(getClassDefinition(),directMethods,false,false,stack) != null) {
|
||||
|
||||
// Update parent class methods...
|
||||
|
||||
if (updateParentClassMethods(getClassDefinition(),directMethods,false,stack) != null) {
|
||||
|
||||
// Get conforming constants...
|
||||
|
||||
if (addConformingConstants(directMembers,false,stack)) {
|
||||
|
||||
// We're ok, so pass 'em up...
|
||||
|
||||
if (!initialize(directInterfaces,directMethods,directMembers,stack,false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return initialize(null,null,null,stack,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
162
jdkSrc/jdk8/sun/rmi/rmic/iiop/NCInterfaceType.java
Normal file
162
jdkSrc/jdk8/sun/rmi/rmic/iiop/NCInterfaceType.java
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.util.Vector;
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.ClassNotFound;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
|
||||
/**
|
||||
* NCInterfaceType represents any non-special, non-conforming interface.
|
||||
* <p>
|
||||
* The static forNCInterface(...) method must be used to obtain an instance.
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class NCInterfaceType extends InterfaceType {
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create an NCInterfaceType for the given class.
|
||||
*
|
||||
* If the class is not a properly formed or if some other error occurs, the
|
||||
* return value will be null, and errors will have been reported to the
|
||||
* supplied BatchEnvironment.
|
||||
*/
|
||||
public static NCInterfaceType forNCInterface( ClassDefinition classDef,
|
||||
ContextStack stack) {
|
||||
if (stack.anyErrors()) return null;
|
||||
|
||||
boolean doPop = false;
|
||||
try {
|
||||
// Do we already have it?
|
||||
|
||||
sun.tools.java.Type theType = classDef.getType();
|
||||
Type existing = getType(theType,stack);
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
if (!(existing instanceof NCInterfaceType)) return null; // False hit.
|
||||
|
||||
// Yep, so return it...
|
||||
|
||||
return (NCInterfaceType) existing;
|
||||
}
|
||||
|
||||
NCInterfaceType it = new NCInterfaceType(stack, classDef);
|
||||
putType(theType,it,stack);
|
||||
stack.push(it);
|
||||
doPop = true;
|
||||
|
||||
if (it.initialize(stack)) {
|
||||
stack.pop(true);
|
||||
return it;
|
||||
} else {
|
||||
removeType(theType,stack);
|
||||
stack.pop(false);
|
||||
return null;
|
||||
}
|
||||
} catch (CompilerError e) {
|
||||
if (doPop) stack.pop(false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string describing this type.
|
||||
*/
|
||||
public String getTypeDescription () {
|
||||
return "Non-conforming interface";
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Internal/Subclass Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create a NCInterfaceType instance for the given class. The resulting
|
||||
* object is not yet completely initialized.
|
||||
*/
|
||||
private NCInterfaceType(ContextStack stack, ClassDefinition classDef) {
|
||||
super(stack,classDef,TYPE_NC_INTERFACE | TM_INTERFACE | TM_COMPOUND);
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Initialize this instance.
|
||||
*/
|
||||
private boolean initialize (ContextStack stack) {
|
||||
|
||||
if (stack.getEnv().getParseNonConforming()) {
|
||||
|
||||
Vector directInterfaces = new Vector();
|
||||
Vector directMethods = new Vector();
|
||||
Vector directMembers = new Vector();
|
||||
|
||||
try {
|
||||
|
||||
// need to include parent interfaces in IDL generation...
|
||||
addNonRemoteInterfaces( directInterfaces,stack );
|
||||
|
||||
// Get methods...
|
||||
|
||||
if (addAllMethods(getClassDefinition(),directMethods,false,false,stack) != null) {
|
||||
|
||||
// Get conforming constants...
|
||||
|
||||
if (addConformingConstants(directMembers,false,stack)) {
|
||||
|
||||
// We're ok, so pass 'em up...
|
||||
|
||||
if (!initialize(directInterfaces,directMethods,directMembers,stack,false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return initialize(null,null,null,stack,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
232
jdkSrc/jdk8/sun/rmi/rmic/iiop/NameContext.java
Normal file
232
jdkSrc/jdk8/sun/rmi/rmic/iiop/NameContext.java
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* A NameContext enables detection of strings which differ only
|
||||
* in case.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
class NameContext {
|
||||
|
||||
private Hashtable table;
|
||||
private boolean allowCollisions;
|
||||
|
||||
/**
|
||||
* Get a context for the given name. Name may be null, in
|
||||
* which case this method will return the default context.
|
||||
*/
|
||||
public static synchronized NameContext forName (String name,
|
||||
boolean allowCollisions,
|
||||
BatchEnvironment env) {
|
||||
|
||||
NameContext result = null;
|
||||
|
||||
// Do we need to use the default context?
|
||||
|
||||
if (name == null) {
|
||||
|
||||
// Yes.
|
||||
|
||||
name = "null";
|
||||
}
|
||||
|
||||
// Have we initialized our hashtable?
|
||||
|
||||
if (env.nameContexts == null) {
|
||||
|
||||
// Nope, so do it...
|
||||
|
||||
env.nameContexts = new Hashtable();
|
||||
|
||||
} else {
|
||||
|
||||
// Yes, see if we already have the requested
|
||||
// context...
|
||||
|
||||
result = (NameContext) env.nameContexts.get(name);
|
||||
}
|
||||
|
||||
// Do we have the requested context?
|
||||
|
||||
if (result == null) {
|
||||
|
||||
// Nope, so create and add it...
|
||||
|
||||
result = new NameContext(allowCollisions);
|
||||
|
||||
env.nameContexts.put(name,result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a context.
|
||||
* @param allowCollisions true if case-sensitive name collisions
|
||||
* are allowed, false if not.
|
||||
*/
|
||||
public NameContext (boolean allowCollisions) {
|
||||
this.allowCollisions = allowCollisions;
|
||||
table = new Hashtable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a name to this context. If constructed with allowCollisions
|
||||
* false and a collision occurs, this method will throw an exception
|
||||
* in which the message contains the string: "name" and "collision".
|
||||
*/
|
||||
public void assertPut (String name) throws Exception {
|
||||
|
||||
String message = add(name);
|
||||
|
||||
if (message != null) {
|
||||
throw new Exception(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a name to this context..
|
||||
*/
|
||||
public void put (String name) {
|
||||
|
||||
if (allowCollisions == false) {
|
||||
throw new Error("Must use assertPut(name)");
|
||||
}
|
||||
|
||||
add(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a name to this context. If constructed with allowCollisions
|
||||
* false and a collision occurs, this method will return a message
|
||||
* string, otherwise returns null.
|
||||
*/
|
||||
private String add (String name) {
|
||||
|
||||
// First, create a key by converting name to lowercase...
|
||||
|
||||
String key = name.toLowerCase();
|
||||
|
||||
// Does this key exist in the context?
|
||||
|
||||
Name value = (Name) table.get(key);
|
||||
|
||||
if (value != null) {
|
||||
|
||||
// Yes, so they match if we ignore case. Do they match if
|
||||
// we don't ignore case?
|
||||
|
||||
if (!name.equals(value.name)) {
|
||||
|
||||
// No, so this is a case-sensitive match. Are we
|
||||
// supposed to allow this?
|
||||
|
||||
if (allowCollisions) {
|
||||
|
||||
// Yes, make sure it knows that it collides...
|
||||
|
||||
value.collisions = true;
|
||||
|
||||
} else {
|
||||
|
||||
// No, so return a message string...
|
||||
|
||||
return new String("\"" + name + "\" and \"" + value.name + "\"");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// No, so add it...
|
||||
|
||||
table.put(key,new Name(name,false));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a name from the context. If it has collisions, the name
|
||||
* will be converted as specified in section 5.2.7.
|
||||
*/
|
||||
public String get (String name) {
|
||||
|
||||
Name it = (Name) table.get(name.toLowerCase());
|
||||
String result = name;
|
||||
|
||||
// Do we need to mangle it?
|
||||
|
||||
if (it.collisions) {
|
||||
|
||||
// Yep, so do it...
|
||||
|
||||
int length = name.length();
|
||||
boolean allLower = true;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
||||
if (Character.isUpperCase(name.charAt(i))) {
|
||||
result += "_";
|
||||
result += i;
|
||||
allLower = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allLower) {
|
||||
result += "_";
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all entries.
|
||||
*/
|
||||
public void clear () {
|
||||
table.clear();
|
||||
}
|
||||
|
||||
public class Name {
|
||||
public String name;
|
||||
public boolean collisions;
|
||||
|
||||
public Name (String name, boolean collisions) {
|
||||
this.name = name;
|
||||
this.collisions = collisions;
|
||||
}
|
||||
}
|
||||
}
|
||||
195
jdkSrc/jdk8/sun/rmi/rmic/iiop/PrimitiveType.java
Normal file
195
jdkSrc/jdk8/sun/rmi/rmic/iiop/PrimitiveType.java
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.Identifier;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
|
||||
/**
|
||||
* PrimitiveType wraps primitive types and void.
|
||||
* <p>
|
||||
* The static forPrimitive(...) method must be used to obtain an instance, and
|
||||
* will return null if the type is non-conforming.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class PrimitiveType extends Type {
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create a PrimitiveType object for the given type.
|
||||
*
|
||||
* If the type is not a properly formed or if some other error occurs, the
|
||||
* return value will be null, and errors will have been reported to the
|
||||
* supplied BatchEnvironment.
|
||||
*/
|
||||
public static PrimitiveType forPrimitive(sun.tools.java.Type type,
|
||||
ContextStack stack) {
|
||||
|
||||
if (stack.anyErrors()) return null;
|
||||
|
||||
// Do we already have it?
|
||||
|
||||
Type existing = getType(type,stack);
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
if (!(existing instanceof PrimitiveType)) return null; // False hit.
|
||||
|
||||
// Yep, so return it...
|
||||
|
||||
return (PrimitiveType) existing;
|
||||
}
|
||||
|
||||
int typeCode;
|
||||
|
||||
switch (type.getTypeCode()) {
|
||||
case TC_VOID: typeCode = TYPE_VOID; break;
|
||||
case TC_BOOLEAN: typeCode = TYPE_BOOLEAN; break;
|
||||
case TC_BYTE: typeCode = TYPE_BYTE; break;
|
||||
case TC_CHAR: typeCode = TYPE_CHAR; break;
|
||||
case TC_SHORT: typeCode = TYPE_SHORT; break;
|
||||
case TC_INT: typeCode = TYPE_INT; break;
|
||||
case TC_LONG: typeCode = TYPE_LONG; break;
|
||||
case TC_FLOAT: typeCode = TYPE_FLOAT; break;
|
||||
case TC_DOUBLE: typeCode = TYPE_DOUBLE; break;
|
||||
default: return null;
|
||||
}
|
||||
|
||||
PrimitiveType it = new PrimitiveType(stack,typeCode);
|
||||
|
||||
// Add it...
|
||||
|
||||
putType(type,it,stack);
|
||||
|
||||
// Do the stack thing in case tracing on...
|
||||
|
||||
stack.push(it);
|
||||
stack.pop(true);
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return signature for this type (e.g. com.acme.Dynamite
|
||||
* would return "com.acme.Dynamite", byte = "B")
|
||||
*/
|
||||
public String getSignature() {
|
||||
switch (getTypeCode()) {
|
||||
case TYPE_VOID: return SIG_VOID;
|
||||
case TYPE_BOOLEAN: return SIG_BOOLEAN;
|
||||
case TYPE_BYTE: return SIG_BYTE;
|
||||
case TYPE_CHAR: return SIG_CHAR;
|
||||
case TYPE_SHORT: return SIG_SHORT;
|
||||
case TYPE_INT: return SIG_INT;
|
||||
case TYPE_LONG: return SIG_LONG;
|
||||
case TYPE_FLOAT: return SIG_FLOAT;
|
||||
case TYPE_DOUBLE: return SIG_DOUBLE;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string describing this type.
|
||||
*/
|
||||
public String getTypeDescription () {
|
||||
return "Primitive";
|
||||
}
|
||||
|
||||
/**
|
||||
* IDL_Naming
|
||||
* Return the fully qualified IDL name for this type (e.g. com.acme.Dynamite would
|
||||
* return "com::acme::Dynamite").
|
||||
* @param global If true, prepends "::".
|
||||
*/
|
||||
public String getQualifiedIDLName(boolean global) {
|
||||
return super.getQualifiedIDLName(false);
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Subclass/Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/*
|
||||
* Load a Class instance. Return null if fail.
|
||||
*/
|
||||
protected Class loadClass() {
|
||||
switch (getTypeCode()) {
|
||||
case TYPE_VOID: return Null.class;
|
||||
case TYPE_BOOLEAN: return boolean.class;
|
||||
case TYPE_BYTE: return byte.class;
|
||||
case TYPE_CHAR: return char.class;
|
||||
case TYPE_SHORT: return short.class;
|
||||
case TYPE_INT: return int.class;
|
||||
case TYPE_LONG: return long.class;
|
||||
case TYPE_FLOAT: return float.class;
|
||||
case TYPE_DOUBLE: return double.class;
|
||||
default: throw new CompilerError("Not a primitive type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IDL_Naming
|
||||
* Create an PrimitiveType instance for the given class.
|
||||
*/
|
||||
private PrimitiveType(ContextStack stack, int typeCode) {
|
||||
super(stack,typeCode | TM_PRIMITIVE);
|
||||
|
||||
// Validate type and set names...
|
||||
|
||||
String idlName = IDLNames.getTypeName(typeCode,false);
|
||||
Identifier id = null;
|
||||
|
||||
switch (typeCode) {
|
||||
case TYPE_VOID: id = idVoid; break;
|
||||
case TYPE_BOOLEAN: id = idBoolean; break;
|
||||
case TYPE_BYTE: id = idByte; break;
|
||||
case TYPE_CHAR: id = idChar; break;
|
||||
case TYPE_SHORT: id = idShort; break;
|
||||
case TYPE_INT: id = idInt; break;
|
||||
case TYPE_LONG: id = idLong; break;
|
||||
case TYPE_FLOAT: id = idFloat; break;
|
||||
case TYPE_DOUBLE: id = idDouble; break;
|
||||
default: throw new CompilerError("Not a primitive type");
|
||||
}
|
||||
|
||||
setNames(id,null,idlName);
|
||||
setRepositoryID();
|
||||
}
|
||||
}
|
||||
|
||||
class Null {}
|
||||
171
jdkSrc/jdk8/sun/rmi/rmic/iiop/PrintGenerator.java
Normal file
171
jdkSrc/jdk8/sun/rmi/rmic/iiop/PrintGenerator.java
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
import sun.rmi.rmic.IndentingWriter;
|
||||
import sun.rmi.rmic.Main;
|
||||
|
||||
/**
|
||||
* An IDL generator for rmic.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class PrintGenerator implements sun.rmi.rmic.Generator,
|
||||
sun.rmi.rmic.iiop.Constants {
|
||||
|
||||
private static final int JAVA = 0;
|
||||
private static final int IDL = 1;
|
||||
private static final int BOTH = 2;
|
||||
|
||||
private int whatToPrint; // Initialized in parseArgs.
|
||||
private boolean global = false;
|
||||
private boolean qualified = false;
|
||||
private boolean trace = false;
|
||||
private boolean valueMethods = false;
|
||||
|
||||
private IndentingWriter out;
|
||||
|
||||
/**
|
||||
* Default constructor for Main to use.
|
||||
*/
|
||||
public PrintGenerator() {
|
||||
OutputStreamWriter writer = new OutputStreamWriter(System.out);
|
||||
out = new IndentingWriter (writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Examine and consume command line arguments.
|
||||
* @param argv The command line arguments. Ignore null
|
||||
* @param error Report any errors using the main.error() methods.
|
||||
* @return true if no errors, false otherwise.
|
||||
*/
|
||||
public boolean parseArgs(String argv[], Main main) {
|
||||
for (int i = 0; i < argv.length; i++) {
|
||||
if (argv[i] != null) {
|
||||
String arg = argv[i].toLowerCase();
|
||||
if (arg.equals("-xprint")) {
|
||||
whatToPrint = JAVA;
|
||||
argv[i] = null;
|
||||
if (i+1 < argv.length) {
|
||||
if (argv[i+1].equalsIgnoreCase("idl")) {
|
||||
argv[++i] = null;
|
||||
whatToPrint = IDL;
|
||||
} else if (argv[i+1].equalsIgnoreCase("both")) {
|
||||
argv[++i] = null;
|
||||
whatToPrint = BOTH;
|
||||
}
|
||||
}
|
||||
} else if (arg.equals("-xglobal")) {
|
||||
global = true;
|
||||
argv[i] = null;
|
||||
} else if (arg.equals("-xqualified")) {
|
||||
qualified = true;
|
||||
argv[i] = null;
|
||||
} else if (arg.equals("-xtrace")) {
|
||||
trace = true;
|
||||
argv[i] = null;
|
||||
} else if (arg.equals("-xvaluemethods")) {
|
||||
valueMethods = true;
|
||||
argv[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate output. Any source files created which need compilation should
|
||||
* be added to the compiler environment using the addGeneratedFile(File)
|
||||
* method.
|
||||
*
|
||||
* @param env The compiler environment
|
||||
* @param cdef The definition for the implementation class or interface from
|
||||
* which to generate output
|
||||
* @param destDir The directory for the root of the package hierarchy
|
||||
* for generated files. May be null.
|
||||
*/
|
||||
public void generate(sun.rmi.rmic.BatchEnvironment env, ClassDefinition cdef, File destDir) {
|
||||
|
||||
BatchEnvironment ourEnv = (BatchEnvironment) env;
|
||||
ContextStack stack = new ContextStack(ourEnv);
|
||||
stack.setTrace(trace);
|
||||
|
||||
if (valueMethods) {
|
||||
ourEnv.setParseNonConforming(true);
|
||||
}
|
||||
|
||||
// Get our top level type...
|
||||
|
||||
CompoundType topType = CompoundType.forCompound(cdef,stack);
|
||||
|
||||
if (topType != null) {
|
||||
|
||||
try {
|
||||
|
||||
// Collect up all the compound types...
|
||||
|
||||
Type[] theTypes = topType.collectMatching(TM_COMPOUND);
|
||||
|
||||
for (int i = 0; i < theTypes.length; i++) {
|
||||
|
||||
out.pln("\n-----------------------------------------------------------\n");
|
||||
|
||||
Type theType = theTypes[i];
|
||||
|
||||
switch (whatToPrint) {
|
||||
case JAVA: theType.println(out,qualified,false,false);
|
||||
break;
|
||||
|
||||
case IDL: theType.println(out,qualified,true,global);
|
||||
break;
|
||||
|
||||
case BOTH: theType.println(out,qualified,false,false);
|
||||
theType.println(out,qualified,true,global);
|
||||
break;
|
||||
|
||||
default: throw new CompilerError("Unknown type!");
|
||||
}
|
||||
}
|
||||
|
||||
out.flush();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new CompilerError("PrintGenerator caught " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
251
jdkSrc/jdk8/sun/rmi/rmic/iiop/RemoteType.java
Normal file
251
jdkSrc/jdk8/sun/rmi/rmic/iiop/RemoteType.java
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.util.Vector;
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
import sun.tools.java.ClassNotFound;
|
||||
|
||||
/**
|
||||
* RemoteType represents any non-special interface which inherits
|
||||
* from java.rmi.Remote.
|
||||
* <p>
|
||||
* The static forRemote(...) method must be used to obtain an instance, and will
|
||||
* return null if the ClassDefinition is non-conforming.
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class RemoteType extends InterfaceType {
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create an RemoteType for the given class.
|
||||
*
|
||||
* If the class is not a properly formed or if some other error occurs, the
|
||||
* return value will be null, and errors will have been reported to the
|
||||
* supplied BatchEnvironment.
|
||||
*/
|
||||
public static RemoteType forRemote(ClassDefinition classDef,
|
||||
ContextStack stack,
|
||||
boolean quiet) {
|
||||
|
||||
if (stack.anyErrors()) return null;
|
||||
|
||||
boolean doPop = false;
|
||||
RemoteType result = null;
|
||||
|
||||
try {
|
||||
// Do we already have it?
|
||||
|
||||
sun.tools.java.Type theType = classDef.getType();
|
||||
Type existing = getType(theType,stack);
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
if (!(existing instanceof RemoteType)) return null; // False hit.
|
||||
|
||||
// Yep, so return it...
|
||||
|
||||
return (RemoteType) existing;
|
||||
}
|
||||
|
||||
// Could this be a remote type?
|
||||
|
||||
if (couldBeRemote(quiet,stack,classDef)) {
|
||||
|
||||
// Yes, so check it...
|
||||
|
||||
RemoteType it = new RemoteType(stack,classDef);
|
||||
putType(theType,it,stack);
|
||||
stack.push(it);
|
||||
doPop = true;
|
||||
|
||||
if (it.initialize(quiet,stack)) {
|
||||
stack.pop(true);
|
||||
result = it;
|
||||
} else {
|
||||
removeType(theType,stack);
|
||||
stack.pop(false);
|
||||
}
|
||||
}
|
||||
} catch (CompilerError e) {
|
||||
if (doPop) stack.pop(false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string describing this type.
|
||||
*/
|
||||
public String getTypeDescription () {
|
||||
return "Remote interface";
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Internal/Subclass Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create a RemoteType instance for the given class. The resulting
|
||||
* object is not yet completely initialized.
|
||||
*/
|
||||
protected RemoteType(ContextStack stack, ClassDefinition classDef) {
|
||||
super(stack,classDef,TYPE_REMOTE | TM_INTERFACE | TM_COMPOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a RemoteType instance for the given class. The resulting
|
||||
* object is not yet completely initialized.
|
||||
*/
|
||||
protected RemoteType(ContextStack stack, ClassDefinition classDef, int typeCode) {
|
||||
super(stack,classDef,typeCode);
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
|
||||
private static boolean couldBeRemote (boolean quiet, ContextStack stack,
|
||||
ClassDefinition classDef) {
|
||||
|
||||
boolean result = false;
|
||||
BatchEnvironment env = stack.getEnv();
|
||||
|
||||
try {
|
||||
if (!classDef.isInterface()) {
|
||||
failedConstraint(16,quiet,stack,classDef.getName());
|
||||
} else {
|
||||
result = env.defRemote.implementedBy(env,classDef.getClassDeclaration());
|
||||
if (!result) failedConstraint(1,quiet,stack,classDef.getName());
|
||||
}
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize this instance.
|
||||
*/
|
||||
private boolean initialize (boolean quiet,ContextStack stack) {
|
||||
|
||||
boolean result = false;
|
||||
|
||||
// Go check it out and gather up the info we need...
|
||||
|
||||
Vector directInterfaces = new Vector();
|
||||
Vector directMethods = new Vector();
|
||||
Vector directConstants = new Vector();
|
||||
|
||||
if (isConformingRemoteInterface(directInterfaces,
|
||||
directMethods,
|
||||
directConstants,
|
||||
quiet,
|
||||
stack)){
|
||||
|
||||
// We're ok, so pass 'em up...
|
||||
|
||||
result = initialize(directInterfaces,directMethods,directConstants,stack,quiet);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to ensure that the interface and all it's methods and arguments
|
||||
* conforms to the RMI/IDL java subset for remote interfaces as defined
|
||||
* by the "Java to IDL Mapping" specification, section 4.
|
||||
* @param directInterfaces All directly implmented interfaces will be
|
||||
* added to this list.
|
||||
* @param directMethods All directly implemented methods (other than
|
||||
* constructors and initializers) will be added to this list.
|
||||
* @param directConstants All constants defined by theInterface will be
|
||||
* added to this list.
|
||||
* @param quiet True if should not report constraint failures.
|
||||
* @return true if constraints satisfied, false otherwise.
|
||||
*/
|
||||
private boolean isConformingRemoteInterface ( Vector directInterfaces,
|
||||
Vector directMethods,
|
||||
Vector directConstants,
|
||||
boolean quiet,
|
||||
ContextStack stack) {
|
||||
|
||||
ClassDefinition theInterface = getClassDefinition();
|
||||
|
||||
try {
|
||||
|
||||
// Get all remote interfaces...
|
||||
|
||||
if (addRemoteInterfaces(directInterfaces,false,stack) == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure all constants are conforming...
|
||||
|
||||
if (!addAllMembers(directConstants,true,quiet,stack)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now, collect up all methods...
|
||||
|
||||
if (addAllMethods(theInterface,directMethods,true,quiet,stack) == null) {
|
||||
// Failed a constraint check...
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now walk 'em, ensuring each is a valid remote method...
|
||||
|
||||
boolean methodsConform = true;
|
||||
for (int i = 0; i < directMethods.size(); i++) {
|
||||
if (! isConformingRemoteMethod((Method) directMethods.elementAt(i),quiet)) {
|
||||
methodsConform = false;
|
||||
}
|
||||
}
|
||||
if (!methodsConform) {
|
||||
return false;
|
||||
}
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
171
jdkSrc/jdk8/sun/rmi/rmic/iiop/SpecialClassType.java
Normal file
171
jdkSrc/jdk8/sun/rmi/rmic/iiop/SpecialClassType.java
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import sun.tools.java.ClassNotFound;
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.Identifier;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
|
||||
/**
|
||||
* SpecialClassType represents any one of the following types:
|
||||
* <pre>
|
||||
* java.lang.Object
|
||||
* java.lang.String
|
||||
* </pre>
|
||||
* all of which are treated as special cases.
|
||||
* <p>
|
||||
* The static forSpecial(...) method must be used to obtain an instance, and
|
||||
* will return null if the type is non-conforming.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class SpecialClassType extends ClassType {
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create a SpecialClassType object for the given class.
|
||||
*
|
||||
* If the class is not a properly formed or if some other error occurs, the
|
||||
* return value will be null, and errors will have been reported to the
|
||||
* supplied BatchEnvironment.
|
||||
*/
|
||||
public static SpecialClassType forSpecial (ClassDefinition theClass,
|
||||
ContextStack stack) {
|
||||
if (stack.anyErrors()) return null;
|
||||
|
||||
sun.tools.java.Type type = theClass.getType();
|
||||
|
||||
// Do we already have it?
|
||||
|
||||
String typeKey = type.toString() + stack.getContextCodeString();
|
||||
|
||||
Type existing = getType(typeKey,stack);
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
if (!(existing instanceof SpecialClassType)) return null; // False hit.
|
||||
|
||||
// Yep, so return it...
|
||||
|
||||
return (SpecialClassType) existing;
|
||||
}
|
||||
|
||||
// Is it a special type?
|
||||
|
||||
int typeCode = getTypeCode(type,theClass,stack);
|
||||
|
||||
if (typeCode != TYPE_NONE) {
|
||||
|
||||
// Yes...
|
||||
|
||||
SpecialClassType result = new SpecialClassType(stack,typeCode,theClass);
|
||||
putType(typeKey,result,stack);
|
||||
stack.push(result);
|
||||
stack.pop(true);
|
||||
return result;
|
||||
|
||||
} else {
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string describing this type.
|
||||
*/
|
||||
public String getTypeDescription () {
|
||||
return "Special class";
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Subclass/Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create an SpecialClassType instance for the given class.
|
||||
*/
|
||||
private SpecialClassType(ContextStack stack, int typeCode,
|
||||
ClassDefinition theClass) {
|
||||
super(stack,typeCode | TM_SPECIAL_CLASS | TM_CLASS | TM_COMPOUND, theClass);
|
||||
Identifier id = theClass.getName();
|
||||
String idlName = null;
|
||||
String[] idlModuleName = null;
|
||||
boolean constant = stack.size() > 0 && stack.getContext().isConstant();
|
||||
|
||||
// Set names...
|
||||
|
||||
switch (typeCode) {
|
||||
case TYPE_STRING: {
|
||||
idlName = IDLNames.getTypeName(typeCode,constant);
|
||||
if (!constant) {
|
||||
idlModuleName = IDL_CORBA_MODULE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_ANY: {
|
||||
idlName = IDL_JAVA_LANG_OBJECT;
|
||||
idlModuleName = IDL_JAVA_LANG_MODULE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setNames(id,idlModuleName,idlName);
|
||||
|
||||
// Init parents...
|
||||
|
||||
if (!initParents(stack)) {
|
||||
|
||||
// Should not be possible!
|
||||
|
||||
throw new CompilerError("SpecialClassType found invalid parent.");
|
||||
}
|
||||
|
||||
// Initialize CompoundType...
|
||||
|
||||
initialize(null,null,null,stack,false);
|
||||
}
|
||||
|
||||
private static int getTypeCode(sun.tools.java.Type type, ClassDefinition theClass, ContextStack stack) {
|
||||
if (type.isType(TC_CLASS)) {
|
||||
Identifier id = type.getClassName();
|
||||
if (id == idJavaLangString) return TYPE_STRING;
|
||||
if (id == idJavaLangObject) return TYPE_ANY;
|
||||
}
|
||||
return TYPE_NONE;
|
||||
}
|
||||
}
|
||||
233
jdkSrc/jdk8/sun/rmi/rmic/iiop/SpecialInterfaceType.java
Normal file
233
jdkSrc/jdk8/sun/rmi/rmic/iiop/SpecialInterfaceType.java
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import sun.tools.java.ClassNotFound;
|
||||
import sun.tools.java.CompilerError;
|
||||
import sun.tools.java.Identifier;
|
||||
import sun.tools.java.ClassDeclaration;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
|
||||
/**
|
||||
* SpecialInterfaceType represents any one of the following types:
|
||||
* <pre>
|
||||
* java.rmi.Remote
|
||||
* java.io.Serializable
|
||||
* java.io.Externalizable
|
||||
* org.omg.CORBA.Object
|
||||
* org.omg.CORBA.portable.IDLEntity
|
||||
* </pre>
|
||||
* all of which are treated as special cases. For all but CORBA.Object,
|
||||
* the type must match exactly. For CORBA.Object, the type must either be
|
||||
* CORBA.Object or inherit from it.
|
||||
* <p>
|
||||
* The static forSpecial(...) method must be used to obtain an instance, and
|
||||
* will return null if the type is non-conforming.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class SpecialInterfaceType extends InterfaceType {
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create a SpecialInterfaceType object for the given class.
|
||||
*
|
||||
* If the class is not a properly formed or if some other error occurs, the
|
||||
* return value will be null, and errors will have been reported to the
|
||||
* supplied BatchEnvironment.
|
||||
*/
|
||||
public static SpecialInterfaceType forSpecial ( ClassDefinition theClass,
|
||||
ContextStack stack) {
|
||||
|
||||
if (stack.anyErrors()) return null;
|
||||
|
||||
// Do we already have it?
|
||||
|
||||
sun.tools.java.Type type = theClass.getType();
|
||||
Type existing = getType(type,stack);
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
if (!(existing instanceof SpecialInterfaceType)) return null; // False hit.
|
||||
|
||||
// Yep, so return it...
|
||||
|
||||
return (SpecialInterfaceType) existing;
|
||||
}
|
||||
|
||||
// Is it special?
|
||||
|
||||
if (isSpecial(type,theClass,stack)) {
|
||||
|
||||
// Yes...
|
||||
|
||||
SpecialInterfaceType result = new SpecialInterfaceType(stack,0,theClass);
|
||||
putType(type,result,stack);
|
||||
stack.push(result);
|
||||
|
||||
if (result.initialize(type,stack)) {
|
||||
stack.pop(true);
|
||||
return result;
|
||||
} else {
|
||||
removeType(type,stack);
|
||||
stack.pop(false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string describing this type.
|
||||
*/
|
||||
public String getTypeDescription () {
|
||||
return "Special interface";
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Subclass/Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create an SpecialInterfaceType instance for the given class.
|
||||
*/
|
||||
private SpecialInterfaceType(ContextStack stack, int typeCode,
|
||||
ClassDefinition theClass) {
|
||||
super(stack,typeCode | TM_SPECIAL_INTERFACE | TM_INTERFACE | TM_COMPOUND, theClass);
|
||||
setNames(theClass.getName(),null,null); // Fixed in initialize.
|
||||
}
|
||||
|
||||
private static boolean isSpecial(sun.tools.java.Type type,
|
||||
ClassDefinition theClass,
|
||||
ContextStack stack) {
|
||||
if (type.isType(TC_CLASS)) {
|
||||
Identifier id = type.getClassName();
|
||||
|
||||
if (id.equals(idRemote)) return true;
|
||||
if (id == idJavaIoSerializable) return true;
|
||||
if (id == idJavaIoExternalizable) return true;
|
||||
if (id == idCorbaObject) return true;
|
||||
if (id == idIDLEntity) return true;
|
||||
BatchEnvironment env = stack.getEnv();
|
||||
try {
|
||||
if (env.defCorbaObject.implementedBy(env,theClass.getClassDeclaration())) return true;
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean initialize(sun.tools.java.Type type, ContextStack stack) {
|
||||
|
||||
int typeCode = TYPE_NONE;
|
||||
Identifier id = null;
|
||||
String idlName = null;
|
||||
String[] idlModuleName = null;
|
||||
boolean constant = stack.size() > 0 && stack.getContext().isConstant();
|
||||
|
||||
if (type.isType(TC_CLASS)) {
|
||||
id = type.getClassName();
|
||||
|
||||
if (id.equals(idRemote)) {
|
||||
typeCode = TYPE_JAVA_RMI_REMOTE;
|
||||
idlName = IDL_JAVA_RMI_REMOTE;
|
||||
idlModuleName = IDL_JAVA_RMI_MODULE;
|
||||
} else if (id == idJavaIoSerializable) {
|
||||
typeCode = TYPE_ANY;
|
||||
idlName = IDL_SERIALIZABLE;
|
||||
idlModuleName = IDL_JAVA_IO_MODULE;
|
||||
} else if (id == idJavaIoExternalizable) {
|
||||
typeCode = TYPE_ANY;
|
||||
idlName = IDL_EXTERNALIZABLE;
|
||||
idlModuleName = IDL_JAVA_IO_MODULE;
|
||||
} else if (id == idIDLEntity) {
|
||||
typeCode = TYPE_ANY;
|
||||
idlName = IDL_IDLENTITY;
|
||||
idlModuleName = IDL_ORG_OMG_CORBA_PORTABLE_MODULE;
|
||||
} else {
|
||||
|
||||
typeCode = TYPE_CORBA_OBJECT;
|
||||
|
||||
// Is it exactly org.omg.CORBA.Object?
|
||||
|
||||
if (id == idCorbaObject) {
|
||||
|
||||
// Yes, so special case...
|
||||
|
||||
idlName = IDLNames.getTypeName(typeCode,constant);
|
||||
idlModuleName = null;
|
||||
|
||||
} else {
|
||||
|
||||
// No, so get the correct names...
|
||||
|
||||
try {
|
||||
|
||||
// These can fail if we get case-sensitive name matches...
|
||||
|
||||
idlName = IDLNames.getClassOrInterfaceName(id,env);
|
||||
idlModuleName = IDLNames.getModuleNames(id,isBoxed(),env);
|
||||
|
||||
} catch (Exception e) {
|
||||
failedConstraint(7,false,stack,id.toString(),e.getMessage());
|
||||
throw new CompilerError("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeCode == TYPE_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset type code...
|
||||
|
||||
setTypeCode(typeCode | TM_SPECIAL_INTERFACE | TM_INTERFACE | TM_COMPOUND);
|
||||
|
||||
// Set names
|
||||
|
||||
if (idlName == null) {
|
||||
throw new CompilerError("Not a special type");
|
||||
}
|
||||
|
||||
setNames(id,idlModuleName,idlName);
|
||||
|
||||
// Initialize CompoundType...
|
||||
|
||||
return initialize(null,null,null,stack,false);
|
||||
}
|
||||
}
|
||||
372
jdkSrc/jdk8/sun/rmi/rmic/iiop/StaticStringsHash.java
Normal file
372
jdkSrc/jdk8/sun/rmi/rmic/iiop/StaticStringsHash.java
Normal file
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
/**
|
||||
* StaticStringsHash takes an array of constant strings and
|
||||
* uses several different hash methods to try to find the
|
||||
* 'best' one for that set. The set of methods is currently
|
||||
* fixed, but with a little work could be made extensible thru
|
||||
* subclassing.
|
||||
* <p>
|
||||
* The current set of methods is:
|
||||
* <ol>
|
||||
* <li> length() - works well when all strings are different length.</li>
|
||||
* <li> charAt(n) - works well when one offset into all strings is different.</li>
|
||||
* <li> hashCode() - works well with larger arrays.</li>
|
||||
* </ol>
|
||||
* After constructing an instance over the set of strings, the
|
||||
* <code>getKey(String)</code> method can be used to use the selected hash
|
||||
* method to produce a key. The <code>method</code> string will contain
|
||||
* "length()", "charAt(n)", or "hashCode()", and is intended for use by
|
||||
* code generators.
|
||||
* <p>
|
||||
* The <code>keys</code> array will contain the full set of unique keys.
|
||||
* <p>
|
||||
* The <code>buckets</code> array will contain a set of arrays, one for
|
||||
* each key in the <code>keys</code>, where <code>buckets[x][y]</code>
|
||||
* is an index into the <code>strings</code> array.
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class StaticStringsHash {
|
||||
|
||||
/** The set of strings upon which the hash info is created */
|
||||
public String[] strings = null;
|
||||
|
||||
/** Unique hash keys */
|
||||
public int[] keys = null;
|
||||
|
||||
/** Buckets for each key, where buckets[x][y] is an index
|
||||
* into the strings[] array. */
|
||||
public int[][] buckets = null;
|
||||
|
||||
/** The method to invoke on String to produce the hash key */
|
||||
public String method = null;
|
||||
|
||||
/** Get a key for the given string using the
|
||||
* selected hash method.
|
||||
* @param str the string to return a key for.
|
||||
* @return the key.
|
||||
*/
|
||||
public int getKey(String str) {
|
||||
switch (keyKind) {
|
||||
case LENGTH: return str.length();
|
||||
case CHAR_AT: return str.charAt(charAt);
|
||||
case HASH_CODE: return str.hashCode();
|
||||
}
|
||||
throw new Error("Bad keyKind");
|
||||
}
|
||||
|
||||
/** Constructor
|
||||
* @param strings the set of strings upon which to
|
||||
* find an optimal hash method. Must not contain
|
||||
* duplicates.
|
||||
*/
|
||||
public StaticStringsHash(String[] strings) {
|
||||
this.strings = strings;
|
||||
length = strings.length;
|
||||
tempKeys = new int[length];
|
||||
bucketSizes = new int[length];
|
||||
setMinStringLength();
|
||||
|
||||
// Decide on the best algorithm based on
|
||||
// which one has the smallest maximum
|
||||
// bucket depth. First, try length()...
|
||||
|
||||
int currentMaxDepth = getKeys(LENGTH);
|
||||
int useCharAt = -1;
|
||||
boolean useHashCode = false;
|
||||
|
||||
if (currentMaxDepth > 1) {
|
||||
|
||||
// At least one bucket had more than one
|
||||
// entry, so try charAt(i). If there
|
||||
// are a lot of strings in the array,
|
||||
// and minStringLength is large, limit
|
||||
// the search to a smaller number of
|
||||
// characters to avoid spending a lot
|
||||
// of time here that is most likely to
|
||||
// be pointless...
|
||||
|
||||
int minLength = minStringLength;
|
||||
if (length > CHAR_AT_MAX_LINES &&
|
||||
length * minLength > CHAR_AT_MAX_CHARS) {
|
||||
minLength = length/CHAR_AT_MAX_CHARS;
|
||||
}
|
||||
|
||||
charAt = 0;
|
||||
for (int i = 0; i < minLength; i++) {
|
||||
int charAtDepth = getKeys(CHAR_AT);
|
||||
if (charAtDepth < currentMaxDepth) {
|
||||
currentMaxDepth = charAtDepth;
|
||||
useCharAt = i;
|
||||
if (currentMaxDepth == 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
charAt++;
|
||||
}
|
||||
charAt = useCharAt;
|
||||
|
||||
|
||||
if (currentMaxDepth > 1) {
|
||||
|
||||
// At least one bucket had more than one
|
||||
// entry, try hashCode().
|
||||
//
|
||||
// Since the cost of computing a full hashCode
|
||||
// (for the runtime target string) is much higher
|
||||
// than the previous methods, use it only if it is
|
||||
// substantially better. The definition of 'substantial'
|
||||
// here is not very well founded, and could be improved
|
||||
// with some further analysis ;^)
|
||||
|
||||
int hashCodeDepth = getKeys(HASH_CODE);
|
||||
if (hashCodeDepth < currentMaxDepth-3) {
|
||||
|
||||
// Using the full hashCode results in at least
|
||||
// 3 fewer entries in the worst bucket, so will
|
||||
// therefore avoid at least 3 calls to equals()
|
||||
// in the worst case.
|
||||
//
|
||||
// Note that using a number smaller than 3 could
|
||||
// result in using a hashCode when there are only
|
||||
// 2 strings in the array, and that would surely
|
||||
// be a poor performance choice.
|
||||
|
||||
useHashCode = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset keys if needed...
|
||||
|
||||
if (!useHashCode) {
|
||||
if (useCharAt >= 0) {
|
||||
|
||||
// Use the charAt(i) method...
|
||||
|
||||
getKeys(CHAR_AT);
|
||||
|
||||
} else {
|
||||
|
||||
// Use length method...
|
||||
|
||||
getKeys(LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now allocate and fill our real hashKeys array...
|
||||
|
||||
keys = new int[bucketCount];
|
||||
System.arraycopy(tempKeys,0,keys,0,bucketCount);
|
||||
|
||||
// Sort keys and bucketSizes arrays...
|
||||
|
||||
boolean didSwap;
|
||||
do {
|
||||
didSwap = false;
|
||||
for (int i = 0; i < bucketCount - 1; i++) {
|
||||
if (keys[i] > keys[i+1]) {
|
||||
int temp = keys[i];
|
||||
keys[i] = keys[i+1];
|
||||
keys[i+1] = temp;
|
||||
temp = bucketSizes[i];
|
||||
bucketSizes[i] = bucketSizes[i+1];
|
||||
bucketSizes[i+1] = temp;
|
||||
didSwap = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (didSwap == true);
|
||||
|
||||
// Allocate our buckets array. Fill the string
|
||||
// index slot with an unused key so we can
|
||||
// determine which are free...
|
||||
|
||||
int unused = findUnusedKey();
|
||||
buckets = new int[bucketCount][];
|
||||
for (int i = 0; i < bucketCount; i++) {
|
||||
buckets[i] = new int[bucketSizes[i]];
|
||||
for (int j = 0; j < bucketSizes[i]; j++) {
|
||||
buckets[i][j] = unused;
|
||||
}
|
||||
}
|
||||
|
||||
// And fill it in...
|
||||
|
||||
for(int i = 0; i < strings.length; i++) {
|
||||
int key = getKey(strings[i]);
|
||||
for (int j = 0; j < bucketCount; j++) {
|
||||
if (keys[j] == key) {
|
||||
int k = 0;
|
||||
while (buckets[j][k] != unused) {
|
||||
k++;
|
||||
}
|
||||
buckets[j][k] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Print an optimized 'contains' method for the
|
||||
* argument strings
|
||||
*/
|
||||
public static void main (String[] args) {
|
||||
StaticStringsHash hash = new StaticStringsHash(args);
|
||||
System.out.println();
|
||||
System.out.println(" public boolean contains(String key) {");
|
||||
System.out.println(" switch (key."+hash.method+") {");
|
||||
for (int i = 0; i < hash.buckets.length; i++) {
|
||||
System.out.println(" case "+hash.keys[i]+": ");
|
||||
for (int j = 0; j < hash.buckets[i].length; j++) {
|
||||
if (j > 0) {
|
||||
System.out.print(" } else ");
|
||||
} else {
|
||||
System.out.print(" ");
|
||||
}
|
||||
System.out.println("if (key.equals(\""+ hash.strings[hash.buckets[i][j]] +"\")) {");
|
||||
System.out.println(" return true;");
|
||||
}
|
||||
System.out.println(" }");
|
||||
}
|
||||
System.out.println(" }");
|
||||
System.out.println(" return false;");
|
||||
System.out.println(" }");
|
||||
}
|
||||
|
||||
private int length;
|
||||
private int[] tempKeys;
|
||||
private int[] bucketSizes;
|
||||
private int bucketCount;
|
||||
private int maxDepth;
|
||||
private int minStringLength = Integer.MAX_VALUE;
|
||||
private int keyKind;
|
||||
private int charAt;
|
||||
|
||||
private static final int LENGTH = 0;
|
||||
private static final int CHAR_AT = 1;
|
||||
private static final int HASH_CODE = 2;
|
||||
|
||||
/* Determines the maximum number of charAt(i)
|
||||
* tests that will be done. The search is
|
||||
* limited because if the number of characters
|
||||
* is large enough, the likelyhood of finding
|
||||
* a good hash key based on this method is
|
||||
* low. The CHAR_AT_MAX_CHARS limit only
|
||||
* applies f there are more strings than
|
||||
* CHAR_AT_MAX_LINES.
|
||||
*/
|
||||
private static final int CHAR_AT_MAX_LINES = 50;
|
||||
private static final int CHAR_AT_MAX_CHARS = 1000;
|
||||
|
||||
private void resetKeys(int keyKind) {
|
||||
this.keyKind = keyKind;
|
||||
switch (keyKind) {
|
||||
case LENGTH: method = "length()"; break;
|
||||
case CHAR_AT: method = "charAt("+charAt+")"; break;
|
||||
case HASH_CODE: method = "hashCode()"; break;
|
||||
}
|
||||
maxDepth = 1;
|
||||
bucketCount = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
tempKeys[i] = 0;
|
||||
bucketSizes[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void setMinStringLength() {
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (strings[i].length() < minStringLength) {
|
||||
minStringLength = strings[i].length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int findUnusedKey() {
|
||||
int unused = 0;
|
||||
int keysLength = keys.length;
|
||||
|
||||
// Note that we just assume that resource
|
||||
// exhaustion will occur rather than an
|
||||
// infinite loop here if the set of keys
|
||||
// is very large.
|
||||
|
||||
while (true) {
|
||||
boolean match = false;
|
||||
for (int i = 0; i < keysLength; i++) {
|
||||
if (keys[i] == unused) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
unused--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return unused;
|
||||
}
|
||||
|
||||
private int getKeys(int methodKind) {
|
||||
resetKeys(methodKind);
|
||||
for(int i = 0; i < strings.length; i++) {
|
||||
addKey(getKey(strings[i]));
|
||||
}
|
||||
return maxDepth;
|
||||
}
|
||||
|
||||
private void addKey(int key) {
|
||||
|
||||
// Have we seen this one before?
|
||||
|
||||
boolean addIt = true;
|
||||
for (int j = 0; j < bucketCount; j++) {
|
||||
if (tempKeys[j] == key) {
|
||||
addIt = false;
|
||||
bucketSizes[j]++;
|
||||
if (bucketSizes[j] > maxDepth) {
|
||||
maxDepth = bucketSizes[j];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (addIt) {
|
||||
tempKeys[bucketCount] = key;
|
||||
bucketSizes[bucketCount] = 1;
|
||||
bucketCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
2380
jdkSrc/jdk8/sun/rmi/rmic/iiop/StubGenerator.java
Normal file
2380
jdkSrc/jdk8/sun/rmi/rmic/iiop/StubGenerator.java
Normal file
File diff suppressed because it is too large
Load Diff
1009
jdkSrc/jdk8/sun/rmi/rmic/iiop/Type.java
Normal file
1009
jdkSrc/jdk8/sun/rmi/rmic/iiop/Type.java
Normal file
File diff suppressed because it is too large
Load Diff
174
jdkSrc/jdk8/sun/rmi/rmic/iiop/Util.java
Normal file
174
jdkSrc/jdk8/sun/rmi/rmic/iiop/Util.java
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.io.File;
|
||||
import sun.tools.java.Identifier;
|
||||
|
||||
import com.sun.corba.se.impl.util.PackagePrefixChecker;
|
||||
|
||||
/**
|
||||
* Util provides static utility methods used by other rmic classes.
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
|
||||
public final class Util implements sun.rmi.rmic.Constants {
|
||||
|
||||
|
||||
public static String packagePrefix(){ return PackagePrefixChecker.packagePrefix();}
|
||||
|
||||
|
||||
/**
|
||||
* Return the directory that should be used for output for a given
|
||||
* class.
|
||||
* @param theClass The fully qualified name of the class.
|
||||
* @param rootDir The directory to use as the root of the
|
||||
* package heirarchy. May be null, in which case the current
|
||||
* working directory is used as the root.
|
||||
*/
|
||||
private static File getOutputDirectoryFor(Identifier theClass,
|
||||
File rootDir,
|
||||
BatchEnvironment env,
|
||||
boolean idl ) {
|
||||
File outputDir = null;
|
||||
String className = theClass.getFlatName().toString().replace('.', SIGC_INNERCLASS);
|
||||
String qualifiedClassName = className;
|
||||
String packagePath = null;
|
||||
String packageName = theClass.getQualifier().toString();
|
||||
//Shift package names for stubs generated for interfaces.
|
||||
/*if(type.isInterface())*/
|
||||
packageName = correctPackageName(packageName, idl, env.getStandardPackage());
|
||||
//Done.
|
||||
if (packageName.length() > 0) {
|
||||
qualifiedClassName = packageName + "." + className;
|
||||
packagePath = packageName.replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
// Do we have a root directory?
|
||||
|
||||
if (rootDir != null) {
|
||||
|
||||
// Yes, do we have a package name?
|
||||
|
||||
if (packagePath != null) {
|
||||
|
||||
// Yes, so use it as the root. Open the directory...
|
||||
|
||||
outputDir = new File(rootDir, packagePath);
|
||||
|
||||
// Make sure the directory exists...
|
||||
|
||||
ensureDirectory(outputDir,env);
|
||||
|
||||
} else {
|
||||
|
||||
// Default package, so use root as output dir...
|
||||
|
||||
outputDir = rootDir;
|
||||
}
|
||||
} else {
|
||||
|
||||
// No root directory. Get the current working directory...
|
||||
|
||||
String workingDirPath = System.getProperty("user.dir");
|
||||
File workingDir = new File(workingDirPath);
|
||||
|
||||
// Do we have a package name?
|
||||
|
||||
if (packagePath == null) {
|
||||
|
||||
// No, so use working directory...
|
||||
|
||||
outputDir = workingDir;
|
||||
|
||||
} else {
|
||||
|
||||
// Yes, so use working directory as the root...
|
||||
|
||||
outputDir = new File(workingDir, packagePath);
|
||||
|
||||
// Make sure the directory exists...
|
||||
|
||||
ensureDirectory(outputDir,env);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, return the directory...
|
||||
|
||||
return outputDir;
|
||||
}
|
||||
|
||||
public static File getOutputDirectoryForIDL(Identifier theClass,
|
||||
File rootDir,
|
||||
BatchEnvironment env) {
|
||||
return getOutputDirectoryFor(theClass, rootDir, env, true);
|
||||
}
|
||||
|
||||
public static File getOutputDirectoryForStub(Identifier theClass,
|
||||
File rootDir,
|
||||
BatchEnvironment env) {
|
||||
return getOutputDirectoryFor(theClass, rootDir, env, false);
|
||||
}
|
||||
|
||||
private static void ensureDirectory (File dir, BatchEnvironment env) {
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
if (!dir.exists()) {
|
||||
env.error(0,"rmic.cannot.create.dir",dir.getAbsolutePath());
|
||||
throw new InternalError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String correctPackageName(
|
||||
String p, boolean idl, boolean standardPackage){
|
||||
if (idl){
|
||||
return p;
|
||||
} else {
|
||||
if (standardPackage) {
|
||||
return p;
|
||||
} else {
|
||||
return PackagePrefixChecker.correctPackageName(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isOffendingPackage(String p){
|
||||
return PackagePrefixChecker.isOffendingPackage(p);
|
||||
}
|
||||
|
||||
public static boolean hasOffendingPrefix(String p){
|
||||
return PackagePrefixChecker.hasOffendingPrefix(p);
|
||||
}
|
||||
|
||||
}
|
||||
488
jdkSrc/jdk8/sun/rmi/rmic/iiop/ValueType.java
Normal file
488
jdkSrc/jdk8/sun/rmi/rmic/iiop/ValueType.java
Normal file
@@ -0,0 +1,488 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
/*
|
||||
* Licensed Materials - Property of IBM
|
||||
* RMI-IIOP v1.0
|
||||
* Copyright IBM Corp. 1998 1999 All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.iiop;
|
||||
|
||||
import java.util.Vector;
|
||||
import sun.tools.java.ClassNotFound;
|
||||
import sun.tools.java.ClassDeclaration;
|
||||
import sun.tools.java.ClassDefinition;
|
||||
import sun.tools.java.MemberDefinition;
|
||||
import java.util.Hashtable;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.io.ObjectStreamField;
|
||||
|
||||
|
||||
/**
|
||||
* ValueType represents any non-special class which does inherit from
|
||||
* java.io.Serializable and does not inherit from java.rmi.Remote.
|
||||
* <p>
|
||||
* The static forValue(...) method must be used to obtain an instance, and
|
||||
* will return null if the ClassDefinition is non-conforming.
|
||||
*
|
||||
* @author Bryan Atsatt
|
||||
*/
|
||||
public class ValueType extends ClassType {
|
||||
|
||||
private boolean isCustom;
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Public Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create an ValueType object for the given class.
|
||||
*
|
||||
* If the class is not a properly formed or if some other error occurs, the
|
||||
* return value will be null, and errors will have been reported to the
|
||||
* supplied BatchEnvironment.
|
||||
*/
|
||||
public static ValueType forValue(ClassDefinition classDef,
|
||||
ContextStack stack,
|
||||
boolean quiet) {
|
||||
|
||||
if (stack.anyErrors()) return null;
|
||||
|
||||
// Do we already have it?
|
||||
|
||||
sun.tools.java.Type theType = classDef.getType();
|
||||
String typeKey = theType.toString();
|
||||
Type existing = getType(typeKey,stack);
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
if (!(existing instanceof ValueType)) return null; // False hit.
|
||||
|
||||
// Yep, so return it...
|
||||
|
||||
return (ValueType) existing;
|
||||
}
|
||||
|
||||
// Is this java.lang.Class?
|
||||
|
||||
boolean javaLangClass = false;
|
||||
|
||||
if (classDef.getClassDeclaration().getName() == idJavaLangClass) {
|
||||
|
||||
// Yes, so replace classDef with one for
|
||||
// javax.rmi.CORBA.ClassDesc...
|
||||
|
||||
javaLangClass = true;
|
||||
BatchEnvironment env = stack.getEnv();
|
||||
ClassDeclaration decl = env.getClassDeclaration(idClassDesc);
|
||||
ClassDefinition def = null;
|
||||
|
||||
try {
|
||||
def = decl.getClassDefinition(env);
|
||||
} catch (ClassNotFound ex) {
|
||||
classNotFound(stack,ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
classDef = def;
|
||||
}
|
||||
|
||||
// Could this be a value?
|
||||
|
||||
if (couldBeValue(stack,classDef)) {
|
||||
|
||||
// Yes, so check it...
|
||||
|
||||
ValueType it = new ValueType(classDef,stack,javaLangClass);
|
||||
putType(typeKey,it,stack);
|
||||
stack.push(it);
|
||||
|
||||
if (it.initialize(stack,quiet)) {
|
||||
stack.pop(true);
|
||||
return it;
|
||||
} else {
|
||||
removeType(typeKey,stack);
|
||||
stack.pop(false);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a string describing this type.
|
||||
*/
|
||||
public String getTypeDescription () {
|
||||
String result = addExceptionDescription("Value");
|
||||
if (isCustom) {
|
||||
result = "Custom " + result;
|
||||
}
|
||||
if (isIDLEntity) {
|
||||
result = result + " [IDLEntity]";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this type is a "custom" type (i.e.
|
||||
* it implements java.io.Externalizable or has a
|
||||
* method with the following signature:
|
||||
*
|
||||
* private void writeObject(java.io.ObjectOutputStream out);
|
||||
*
|
||||
*/
|
||||
public boolean isCustom () {
|
||||
return isCustom;
|
||||
}
|
||||
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Subclass/Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Create a ValueType instance for the given class. The resulting
|
||||
* object is not yet completely initialized.
|
||||
*/
|
||||
private ValueType(ClassDefinition classDef,
|
||||
ContextStack stack,
|
||||
boolean isMappedJavaLangClass) {
|
||||
super(stack,classDef,TYPE_VALUE | TM_CLASS | TM_COMPOUND);
|
||||
isCustom = false;
|
||||
|
||||
// If this is the mapped version of java.lang.Class,
|
||||
// set the non-IDL names back to java.lang.Class...
|
||||
|
||||
if (isMappedJavaLangClass) {
|
||||
setNames(idJavaLangClass,IDL_CLASS_MODULE,IDL_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// Internal Interfaces
|
||||
//_____________________________________________________________________
|
||||
|
||||
/**
|
||||
* Initialize this instance.
|
||||
*/
|
||||
|
||||
private static boolean couldBeValue(ContextStack stack, ClassDefinition classDef) {
|
||||
|
||||
boolean result = false;
|
||||
ClassDeclaration classDecl = classDef.getClassDeclaration();
|
||||
BatchEnvironment env = stack.getEnv();
|
||||
|
||||
try {
|
||||
// Make sure it's not remote...
|
||||
|
||||
if (env.defRemote.implementedBy(env, classDecl)) {
|
||||
failedConstraint(10,false,stack,classDef.getName());
|
||||
} else {
|
||||
|
||||
// Make sure it's Serializable...
|
||||
|
||||
if (!env.defSerializable.implementedBy(env, classDecl)) {
|
||||
failedConstraint(11,false,stack,classDef.getName());
|
||||
} else {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this instance.
|
||||
*/
|
||||
private boolean initialize (ContextStack stack, boolean quiet) {
|
||||
|
||||
ClassDefinition ourDef = getClassDefinition();
|
||||
ClassDeclaration ourDecl = getClassDeclaration();
|
||||
|
||||
try {
|
||||
|
||||
// Make sure our parentage is ok...
|
||||
|
||||
if (!initParents(stack)) {
|
||||
failedConstraint(12,quiet,stack,getQualifiedName());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// We're ok, so make up our collections...
|
||||
|
||||
Vector directInterfaces = new Vector();
|
||||
Vector directMethods = new Vector();
|
||||
Vector directMembers = new Vector();
|
||||
|
||||
// Get interfaces...
|
||||
|
||||
if (addNonRemoteInterfaces(directInterfaces,stack) != null) {
|
||||
|
||||
// Get methods...
|
||||
|
||||
if (addAllMethods(ourDef,directMethods,false,false,stack) != null) {
|
||||
|
||||
// Update parent class methods
|
||||
if (updateParentClassMethods(ourDef,directMethods,false,stack) != null) {
|
||||
|
||||
// Get constants and members...
|
||||
|
||||
if (addAllMembers(directMembers,false,false,stack)) {
|
||||
|
||||
// We're ok, so pass 'em up...
|
||||
|
||||
if (!initialize(directInterfaces,directMethods,directMembers,stack,quiet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is this class Externalizable?
|
||||
|
||||
boolean externalizable = false;
|
||||
if (!env.defExternalizable.implementedBy(env, ourDecl)) {
|
||||
|
||||
// No, so check to see if we have a serialPersistentField
|
||||
// that will modify the members.
|
||||
|
||||
if (!checkPersistentFields(getClassInstance(),quiet)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
||||
// Yes.
|
||||
|
||||
externalizable = true;
|
||||
}
|
||||
|
||||
// Should this class be considered "custom"? It is if
|
||||
// it is Externalizable OR if it has a method with the
|
||||
// following signature:
|
||||
//
|
||||
// private void writeObject(java.io.ObjectOutputStream out);
|
||||
//
|
||||
|
||||
if (externalizable) {
|
||||
isCustom = true;
|
||||
} else {
|
||||
for (MemberDefinition member = ourDef.getFirstMember();
|
||||
member != null;
|
||||
member = member.getNextMember()) {
|
||||
|
||||
if (member.isMethod() &&
|
||||
!member.isInitializer() &&
|
||||
member.isPrivate() &&
|
||||
member.getName().toString().equals("writeObject")) {
|
||||
|
||||
// Check return type, arguments and exceptions...
|
||||
|
||||
sun.tools.java.Type methodType = member.getType();
|
||||
sun.tools.java.Type rtnType = methodType.getReturnType();
|
||||
|
||||
if (rtnType == sun.tools.java.Type.tVoid) {
|
||||
|
||||
// Return type is correct. How about arguments?
|
||||
|
||||
sun.tools.java.Type[] args = methodType.getArgumentTypes();
|
||||
if (args.length == 1 &&
|
||||
args[0].getTypeSignature().equals("Ljava/io/ObjectOutputStream;")) {
|
||||
|
||||
// Arguments are correct, so it is a custom
|
||||
// value type...
|
||||
|
||||
isCustom = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFound e) {
|
||||
classNotFound(stack,e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private boolean checkPersistentFields (Class clz, boolean quiet) {
|
||||
|
||||
// Do we have a writeObject method?
|
||||
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
if (methods[i].getName().equals("writeObject") &&
|
||||
methods[i].getArguments().length == 1) {
|
||||
|
||||
Type returnType = methods[i].getReturnType();
|
||||
Type arg = methods[i].getArguments()[0];
|
||||
String id = arg.getQualifiedName();
|
||||
|
||||
if (returnType.isType(TYPE_VOID) &&
|
||||
id.equals("java.io.ObjectOutputStream")) {
|
||||
|
||||
// Got one, so there's nothing to do...
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have a valid serialPersistentField array?
|
||||
|
||||
MemberDefinition spfDef = null;
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
if (members[i].getName().equals("serialPersistentFields")) {
|
||||
|
||||
Member member = members[i];
|
||||
Type type = member.getType();
|
||||
Type elementType = type.getElementType();
|
||||
|
||||
// We have a member with the correct name. Make sure
|
||||
// we have the correct signature...
|
||||
|
||||
if (elementType != null &&
|
||||
elementType.getQualifiedName().equals(
|
||||
"java.io.ObjectStreamField")
|
||||
) {
|
||||
|
||||
if (member.isStatic() &&
|
||||
member.isFinal() &&
|
||||
member.isPrivate()) {
|
||||
|
||||
// We have the correct signature
|
||||
|
||||
spfDef = member.getMemberDefinition();
|
||||
|
||||
} else {
|
||||
|
||||
// Bad signature...
|
||||
|
||||
failedConstraint(4,quiet,stack,getQualifiedName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we do not have a serialPersistentField,
|
||||
// there's nothing to do, so return with no error...
|
||||
|
||||
if (spfDef == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ok, now we must examine the contents of the array -
|
||||
// then validate them...
|
||||
|
||||
Hashtable fields = getPersistentFields(clz);
|
||||
boolean result = true;
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
String fieldName = members[i].getName();
|
||||
String fieldType = members[i].getType().getSignature();
|
||||
|
||||
// Is this field present in the array?
|
||||
|
||||
String type = (String) fields.get(fieldName);
|
||||
|
||||
if (type == null) {
|
||||
|
||||
// No, so mark it transient...
|
||||
|
||||
members[i].setTransient();
|
||||
|
||||
} else {
|
||||
|
||||
// Yes, does the type match?
|
||||
|
||||
if (type.equals(fieldType)) {
|
||||
|
||||
// Yes, so remove it from the fields table...
|
||||
|
||||
fields.remove(fieldName);
|
||||
|
||||
} else {
|
||||
|
||||
// No, so error...
|
||||
|
||||
result = false;
|
||||
failedConstraint(2,quiet,stack,fieldName,getQualifiedName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ok, we've checked all of our fields. Are there any left in the "array"?
|
||||
// If so, it's an error...
|
||||
|
||||
if (result && fields.size() > 0) {
|
||||
|
||||
result = false;
|
||||
failedConstraint(9,quiet,stack,getQualifiedName());
|
||||
}
|
||||
|
||||
// Return result...
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names and types of all the persistent fields of a Class.
|
||||
*/
|
||||
private Hashtable getPersistentFields (Class clz) {
|
||||
Hashtable result = new Hashtable();
|
||||
ObjectStreamClass osc = ObjectStreamClass.lookup(clz);
|
||||
if (osc != null) {
|
||||
ObjectStreamField[] fields = osc.getFields();
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
String typeSig;
|
||||
String typePrefix = String.valueOf(fields[i].getTypeCode());
|
||||
if (fields[i].isPrimitive()) {
|
||||
typeSig = typePrefix;
|
||||
} else {
|
||||
if (fields[i].getTypeCode() == '[') {
|
||||
typePrefix = "";
|
||||
}
|
||||
typeSig = typePrefix + fields[i].getType().getName().replace('.','/');
|
||||
if (typeSig.endsWith(";")) {
|
||||
typeSig = typeSig.substring(0,typeSig.length()-1);
|
||||
}
|
||||
}
|
||||
result.put(fields[i].getName(),typeSig);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
145
jdkSrc/jdk8/sun/rmi/rmic/newrmic/BatchEnvironment.java
Normal file
145
jdkSrc/jdk8/sun/rmi/rmic/newrmic/BatchEnvironment.java
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.newrmic;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.RootDoc;
|
||||
import java.io.File;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static sun.rmi.rmic.newrmic.Constants.*;
|
||||
|
||||
/**
|
||||
* The environment for an rmic compilation batch.
|
||||
*
|
||||
* A BatchEnvironment contains a RootDoc, which is the entry point
|
||||
* into the doclet environment for the associated rmic compilation
|
||||
* batch. A BatchEnvironment collects the source files generated
|
||||
* during the batch's execution, for eventual source code compilation
|
||||
* and, possibly, deletion. Errors that occur during generation
|
||||
* activity should be reported through the BatchEnvironment's "error"
|
||||
* method.
|
||||
*
|
||||
* A protocol-specific generator class may require the use of a
|
||||
* particular BatchEnvironment subclass for enhanced environment
|
||||
* functionality. A BatchEnvironment subclass must declare a
|
||||
* public constructor with one parameter of type RootDoc.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
public class BatchEnvironment {
|
||||
|
||||
private final RootDoc rootDoc;
|
||||
|
||||
/** cached ClassDoc for certain types used by rmic */
|
||||
private final ClassDoc docRemote;
|
||||
private final ClassDoc docException;
|
||||
private final ClassDoc docRemoteException;
|
||||
private final ClassDoc docRuntimeException;
|
||||
|
||||
private boolean verbose = false;
|
||||
private final List<File> generatedFiles = new ArrayList<File>();
|
||||
|
||||
/**
|
||||
* Creates a new BatchEnvironment with the specified RootDoc.
|
||||
**/
|
||||
public BatchEnvironment(RootDoc rootDoc) {
|
||||
this.rootDoc = rootDoc;
|
||||
|
||||
/*
|
||||
* Initialize cached ClassDoc for types used by rmic. Note
|
||||
* that any of these could be null if the boot class path is
|
||||
* incorrect, which could cause a NullPointerException later.
|
||||
*/
|
||||
docRemote = rootDoc().classNamed(REMOTE);
|
||||
docException = rootDoc().classNamed(EXCEPTION);
|
||||
docRemoteException = rootDoc().classNamed(REMOTE_EXCEPTION);
|
||||
docRuntimeException = rootDoc().classNamed(RUNTIME_EXCEPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RootDoc for this environment.
|
||||
**/
|
||||
public RootDoc rootDoc() {
|
||||
return rootDoc;
|
||||
}
|
||||
|
||||
public ClassDoc docRemote() { return docRemote; }
|
||||
public ClassDoc docException() { return docException; }
|
||||
public ClassDoc docRemoteException() { return docRemoteException; }
|
||||
public ClassDoc docRuntimeException() { return docRuntimeException; }
|
||||
|
||||
/**
|
||||
* Sets this environment's verbosity status.
|
||||
**/
|
||||
public void setVerbose(boolean verbose) {
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this environment's verbosity status.
|
||||
**/
|
||||
public boolean verbose() {
|
||||
return verbose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified file to the list of source files generated
|
||||
* during this batch.
|
||||
**/
|
||||
public void addGeneratedFile(File file) {
|
||||
generatedFiles.add(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of files generated during this batch.
|
||||
**/
|
||||
public List<File> generatedFiles() {
|
||||
return Collections.unmodifiableList(generatedFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the specified (non-error) message.
|
||||
**/
|
||||
public void output(String msg) {
|
||||
rootDoc.printNotice(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an error using the specified resource key and text
|
||||
* formatting arguments.
|
||||
**/
|
||||
public void error(String key, String... args) {
|
||||
rootDoc.printError(Resources.getText(key, args));
|
||||
}
|
||||
}
|
||||
48
jdkSrc/jdk8/sun/rmi/rmic/newrmic/Constants.java
Normal file
48
jdkSrc/jdk8/sun/rmi/rmic/newrmic/Constants.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.newrmic;
|
||||
|
||||
/**
|
||||
* Constants potentially useful to all rmic generators.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
public final class Constants {
|
||||
|
||||
private Constants() { throw new AssertionError(); }
|
||||
|
||||
/*
|
||||
* fully-qualified names of types used by rmic
|
||||
*/
|
||||
public static final String REMOTE = "java.rmi.Remote";
|
||||
public static final String EXCEPTION = "java.lang.Exception";
|
||||
public static final String REMOTE_EXCEPTION = "java.rmi.RemoteException";
|
||||
public static final String RUNTIME_EXCEPTION = "java.lang.RuntimeException";
|
||||
}
|
||||
87
jdkSrc/jdk8/sun/rmi/rmic/newrmic/Generator.java
Normal file
87
jdkSrc/jdk8/sun/rmi/rmic/newrmic/Generator.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.newrmic;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The interface to rmic back end implementations. Classes that
|
||||
* implement this interface correspond to the various generation modes
|
||||
* of rmic (JRMP, IIOP, IDL, etc.).
|
||||
*
|
||||
* A Generator instance corresponds to a particular rmic compilation
|
||||
* batch, and its instance state represents the generator-specific
|
||||
* command line options for that batch. Main will instantiate a
|
||||
* generator class when the command line arguments indicate selection
|
||||
* of the corresponding generation mode. Main will then invoke the
|
||||
* "parseArgs" method to allow the generator to process any
|
||||
* generator-specific command line options and set its instance state
|
||||
* accordingly.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
public interface Generator {
|
||||
|
||||
/**
|
||||
* Processes the command line options specific to this generator.
|
||||
* Processed options are set to null in the specified array.
|
||||
* Returns true if successful or false if an error occurs. Errors
|
||||
* are output to the specific Main instance.
|
||||
**/
|
||||
public boolean parseArgs(String[] args, Main main);
|
||||
|
||||
/**
|
||||
* Returns the most specific environment class required by this
|
||||
* generator.
|
||||
**/
|
||||
public Class<? extends BatchEnvironment> envClass();
|
||||
|
||||
/**
|
||||
* Returns the names of the classes that must be available through
|
||||
* the doclet API in order for this generator to function.
|
||||
**/
|
||||
public Set<String> bootstrapClassNames();
|
||||
|
||||
/**
|
||||
* Generates the protocol-specific rmic output files for the
|
||||
* specified remote class. This method is invoked once for each
|
||||
* class or interface specified on the command line for the rmic
|
||||
* compilation batch associated with this instance.
|
||||
*
|
||||
* Any generated source files (to be compiled with javac) are
|
||||
* passed to the addGeneratedFile method of the specified
|
||||
* BatchEnvironment.
|
||||
**/
|
||||
public void generate(BatchEnvironment env,
|
||||
ClassDoc inputClass,
|
||||
File destDir);
|
||||
}
|
||||
291
jdkSrc/jdk8/sun/rmi/rmic/newrmic/IndentingWriter.java
Normal file
291
jdkSrc/jdk8/sun/rmi/rmic/newrmic/IndentingWriter.java
Normal file
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.newrmic;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A BufferedWriter that supports automatic indentation of lines of
|
||||
* text written to the underlying Writer.
|
||||
*
|
||||
* Methods are provided for compact/convenient indenting in and out,
|
||||
* writing text, and writing lines of text in various combinations.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
public class IndentingWriter extends BufferedWriter {
|
||||
|
||||
/** number of spaces to change indent when indenting in or out */
|
||||
private final int indentStep;
|
||||
|
||||
/** number of spaces to convert into tabs (use MAX_VALUE to disable) */
|
||||
private final int tabSize;
|
||||
|
||||
/** true if the next character written is the first on a line */
|
||||
private boolean beginningOfLine = true;
|
||||
|
||||
/** current number of spaces to prepend to lines */
|
||||
private int currentIndent = 0;
|
||||
|
||||
/**
|
||||
* Creates a new IndentingWriter that writes indented text to the
|
||||
* given Writer. Use the default indent step of four spaces.
|
||||
**/
|
||||
public IndentingWriter(Writer out) {
|
||||
this(out, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new IndentingWriter that writes indented text to the
|
||||
* given Writer and uses the supplied indent step.
|
||||
**/
|
||||
public IndentingWriter(Writer out, int indentStep) {
|
||||
this(out, indentStep, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new IndentingWriter that writes indented text to the
|
||||
* given Writer and uses the supplied indent step and tab size.
|
||||
**/
|
||||
public IndentingWriter(Writer out, int indentStep, int tabSize) {
|
||||
super(out);
|
||||
if (indentStep < 0) {
|
||||
throw new IllegalArgumentException("negative indent step");
|
||||
}
|
||||
if (tabSize < 0) {
|
||||
throw new IllegalArgumentException("negative tab size");
|
||||
}
|
||||
this.indentStep = indentStep;
|
||||
this.tabSize = tabSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a single character.
|
||||
**/
|
||||
public void write(int c) throws IOException {
|
||||
checkWrite();
|
||||
super.write(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a portion of an array of characters.
|
||||
**/
|
||||
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||
if (len > 0) {
|
||||
checkWrite();
|
||||
}
|
||||
super.write(cbuf, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a portion of a String.
|
||||
**/
|
||||
public void write(String s, int off, int len) throws IOException {
|
||||
if (len > 0) {
|
||||
checkWrite();
|
||||
}
|
||||
super.write(s, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a line separator. The next character written will be
|
||||
* preceded by an indent.
|
||||
**/
|
||||
public void newLine() throws IOException {
|
||||
super.newLine();
|
||||
beginningOfLine = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an indent needs to be written before writing the next
|
||||
* character.
|
||||
*
|
||||
* The indent generation is optimized (and made consistent with
|
||||
* certain coding conventions) by condensing groups of eight
|
||||
* spaces into tab characters.
|
||||
**/
|
||||
protected void checkWrite() throws IOException {
|
||||
if (beginningOfLine) {
|
||||
beginningOfLine = false;
|
||||
int i = currentIndent;
|
||||
while (i >= tabSize) {
|
||||
super.write('\t');
|
||||
i -= tabSize;
|
||||
}
|
||||
while (i > 0) {
|
||||
super.write(' ');
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the current indent by the indent step.
|
||||
**/
|
||||
protected void indentIn() {
|
||||
currentIndent += indentStep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases the current indent by the indent step.
|
||||
**/
|
||||
protected void indentOut() {
|
||||
currentIndent -= indentStep;
|
||||
if (currentIndent < 0)
|
||||
currentIndent = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indents in.
|
||||
**/
|
||||
public void pI() {
|
||||
indentIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indents out.
|
||||
**/
|
||||
public void pO() {
|
||||
indentOut();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes string.
|
||||
**/
|
||||
public void p(String s) throws IOException {
|
||||
write(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends current line.
|
||||
**/
|
||||
public void pln() throws IOException {
|
||||
newLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes string; ends current line.
|
||||
**/
|
||||
public void pln(String s) throws IOException {
|
||||
p(s);
|
||||
pln();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes string; ends current line; indents in.
|
||||
**/
|
||||
public void plnI(String s) throws IOException {
|
||||
p(s);
|
||||
pln();
|
||||
pI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indents out; writes string.
|
||||
**/
|
||||
public void pO(String s) throws IOException {
|
||||
pO();
|
||||
p(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indents out; writes string; ends current line.
|
||||
**/
|
||||
public void pOln(String s) throws IOException {
|
||||
pO(s);
|
||||
pln();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indents out; writes string; ends current line; indents in.
|
||||
*
|
||||
* This method is useful for generating lines of code that both
|
||||
* end and begin nested blocks, like "} else {".
|
||||
**/
|
||||
public void pOlnI(String s) throws IOException {
|
||||
pO(s);
|
||||
pln();
|
||||
pI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes object.
|
||||
**/
|
||||
public void p(Object o) throws IOException {
|
||||
write(o.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes object; ends current line.
|
||||
**/
|
||||
public void pln(Object o) throws IOException {
|
||||
p(o.toString());
|
||||
pln();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes object; ends current line; indents in.
|
||||
**/
|
||||
public void plnI(Object o) throws IOException {
|
||||
p(o.toString());
|
||||
pln();
|
||||
pI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indents out; writes object.
|
||||
**/
|
||||
public void pO(Object o) throws IOException {
|
||||
pO();
|
||||
p(o.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indents out; writes object; ends current line.
|
||||
**/
|
||||
public void pOln(Object o) throws IOException {
|
||||
pO(o.toString());
|
||||
pln();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indents out; writes object; ends current line; indents in.
|
||||
*
|
||||
* This method is useful for generating lines of code that both
|
||||
* end and begin nested blocks, like "} else {".
|
||||
**/
|
||||
public void pOlnI(Object o) throws IOException {
|
||||
pO(o.toString());
|
||||
pln();
|
||||
pI();
|
||||
}
|
||||
}
|
||||
689
jdkSrc/jdk8/sun/rmi/rmic/newrmic/Main.java
Normal file
689
jdkSrc/jdk8/sun/rmi/rmic/newrmic/Main.java
Normal file
@@ -0,0 +1,689 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.newrmic;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.RootDoc;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import sun.rmi.rmic.newrmic.jrmp.JrmpGenerator;
|
||||
import sun.tools.util.CommandLine;
|
||||
|
||||
/**
|
||||
* The rmic front end. This class contains the "main" method for rmic
|
||||
* command line invocation.
|
||||
*
|
||||
* A Main instance contains the stream to output error messages and
|
||||
* other diagnostics to.
|
||||
*
|
||||
* An rmic compilation batch (for example, one rmic command line
|
||||
* invocation) is executed by invoking the "compile" method of a Main
|
||||
* instance.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* NOTE: If and when there is a J2SE API for invoking SDK tools, this
|
||||
* class should be updated to support that API.
|
||||
*
|
||||
* NOTE: This class is the front end for a "new" rmic implementation,
|
||||
* which uses javadoc and the doclet API for reading class files and
|
||||
* javac for compiling generated source files. This implementation is
|
||||
* incomplete: it lacks any CORBA-based back end implementations, and
|
||||
* thus the command line options "-idl", "-iiop", and their related
|
||||
* options are not yet supported. The front end for the "old",
|
||||
* oldjavac-based rmic implementation is sun.rmi.rmic.Main.
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
public class Main {
|
||||
|
||||
/*
|
||||
* Implementation note:
|
||||
*
|
||||
* In order to use the doclet API to read class files, much of
|
||||
* this implementation of rmic executes as a doclet within an
|
||||
* invocation of javadoc. This class is used as the doclet class
|
||||
* for such javadoc invocations, via its static "start" and
|
||||
* "optionLength" methods. There is one javadoc invocation per
|
||||
* rmic compilation batch.
|
||||
*
|
||||
* The only guaranteed way to pass data to a doclet through a
|
||||
* javadoc invocation is through doclet-specific options on the
|
||||
* javadoc "command line". Rather than passing numerous pieces of
|
||||
* individual data in string form as javadoc options, we use a
|
||||
* single doclet-specific option ("-batchID") to pass a numeric
|
||||
* identifier that uniquely identifies the rmic compilation batch
|
||||
* that the javadoc invocation is for, and that identifier can
|
||||
* then be used as a key in a global table to retrieve an object
|
||||
* containing all of batch-specific data (rmic command line
|
||||
* arguments, etc.).
|
||||
*/
|
||||
|
||||
/** guards "batchCount" */
|
||||
private static final Object batchCountLock = new Object();
|
||||
|
||||
/** number of batches run; used to generated batch IDs */
|
||||
private static long batchCount = 0;
|
||||
|
||||
/** maps batch ID to batch data */
|
||||
private static final Map<Long,Batch> batchTable =
|
||||
Collections.synchronizedMap(new HashMap<Long,Batch>());
|
||||
|
||||
/** stream to output error messages and other diagnostics to */
|
||||
private final PrintStream out;
|
||||
|
||||
/** name of this program, to use in error messages */
|
||||
private final String program;
|
||||
|
||||
/**
|
||||
* Command line entry point.
|
||||
**/
|
||||
public static void main(String[] args) {
|
||||
Main rmic = new Main(System.err, "rmic");
|
||||
System.exit(rmic.compile(args) ? 0 : 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Main instance that writes output to the specified
|
||||
* stream. The specified program name is used in error messages.
|
||||
**/
|
||||
public Main(OutputStream out, String program) {
|
||||
this.out = out instanceof PrintStream ?
|
||||
(PrintStream) out : new PrintStream(out);
|
||||
this.program = program;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles a batch of input classes, as given by the specified
|
||||
* command line arguments. Protocol-specific generators are
|
||||
* determined by the choice options on the command line. Returns
|
||||
* true if successful, or false if an error occurred.
|
||||
*
|
||||
* NOTE: This method is retained for transitional consistency with
|
||||
* previous implementations.
|
||||
**/
|
||||
public boolean compile(String[] args) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
long batchID;
|
||||
synchronized (batchCountLock) {
|
||||
batchID = batchCount++; // assign batch ID
|
||||
}
|
||||
|
||||
// process command line
|
||||
Batch batch = parseArgs(args);
|
||||
if (batch == null) {
|
||||
return false; // terminate if error occurred
|
||||
}
|
||||
|
||||
/*
|
||||
* With the batch data retrievable in the global table, run
|
||||
* javadoc to continue the rest of the batch's compliation as
|
||||
* a doclet.
|
||||
*/
|
||||
boolean status;
|
||||
try {
|
||||
batchTable.put(batchID, batch);
|
||||
status = invokeJavadoc(batch, batchID);
|
||||
} finally {
|
||||
batchTable.remove(batchID);
|
||||
}
|
||||
|
||||
if (batch.verbose) {
|
||||
long deltaTime = System.currentTimeMillis() - startTime;
|
||||
output(Resources.getText("rmic.done_in",
|
||||
Long.toString(deltaTime)));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the specified string to the output stream of this Main
|
||||
* instance.
|
||||
**/
|
||||
public void output(String msg) {
|
||||
out.println(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints an error message to the output stream of this Main
|
||||
* instance. The first argument is used as a key in rmic's
|
||||
* resource bundle, and the rest of the arguments are used as
|
||||
* arguments in the formatting of the resource string.
|
||||
**/
|
||||
public void error(String msg, String... args) {
|
||||
output(Resources.getText(msg, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints rmic's usage message to the output stream of this Main
|
||||
* instance.
|
||||
*
|
||||
* This method is public so that it can be used by the "parseArgs"
|
||||
* methods of Generator implementations.
|
||||
**/
|
||||
public void usage() {
|
||||
error("rmic.usage", program);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes rmic command line arguments. Returns a Batch object
|
||||
* representing the command line arguments if successful, or null
|
||||
* if an error occurred. Processed elements of the args array are
|
||||
* set to null.
|
||||
**/
|
||||
private Batch parseArgs(String[] args) {
|
||||
Batch batch = new Batch();
|
||||
|
||||
/*
|
||||
* Pre-process command line for @file arguments.
|
||||
*/
|
||||
try {
|
||||
args = CommandLine.parse(args);
|
||||
} catch (FileNotFoundException e) {
|
||||
error("rmic.cant.read", e.getMessage());
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(out);
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
|
||||
if (args[i] == null) {
|
||||
// already processed by a generator
|
||||
continue;
|
||||
|
||||
} else if (args[i].equals("-Xnew")) {
|
||||
// we're already using the "new" implementation
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-show")) {
|
||||
// obselete: fail
|
||||
error("rmic.option.unsupported", args[i]);
|
||||
usage();
|
||||
return null;
|
||||
|
||||
} else if (args[i].equals("-O")) {
|
||||
// obselete: warn but tolerate
|
||||
error("rmic.option.unsupported", args[i]);
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-debug")) {
|
||||
// obselete: warn but tolerate
|
||||
error("rmic.option.unsupported", args[i]);
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-depend")) {
|
||||
// obselete: warn but tolerate
|
||||
// REMIND: should this fail instead?
|
||||
error("rmic.option.unsupported", args[i]);
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-keep") ||
|
||||
args[i].equals("-keepgenerated"))
|
||||
{
|
||||
batch.keepGenerated = true;
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-g")) {
|
||||
batch.debug = true;
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-nowarn")) {
|
||||
batch.noWarn = true;
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-nowrite")) {
|
||||
batch.noWrite = true;
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-verbose")) {
|
||||
batch.verbose = true;
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-Xnocompile")) {
|
||||
batch.noCompile = true;
|
||||
batch.keepGenerated = true;
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-bootclasspath")) {
|
||||
if ((i + 1) >= args.length) {
|
||||
error("rmic.option.requires.argument", args[i]);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
if (batch.bootClassPath != null) {
|
||||
error("rmic.option.already.seen", args[i]);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
args[i] = null;
|
||||
batch.bootClassPath = args[++i];
|
||||
assert batch.bootClassPath != null;
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-extdirs")) {
|
||||
if ((i + 1) >= args.length) {
|
||||
error("rmic.option.requires.argument", args[i]);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
if (batch.extDirs != null) {
|
||||
error("rmic.option.already.seen", args[i]);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
args[i] = null;
|
||||
batch.extDirs = args[++i];
|
||||
assert batch.extDirs != null;
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-classpath")) {
|
||||
if ((i + 1) >= args.length) {
|
||||
error("rmic.option.requires.argument", args[i]);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
if (batch.classPath != null) {
|
||||
error("rmic.option.already.seen", args[i]);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
args[i] = null;
|
||||
batch.classPath = args[++i];
|
||||
assert batch.classPath != null;
|
||||
args[i] = null;
|
||||
|
||||
} else if (args[i].equals("-d")) {
|
||||
if ((i + 1) >= args.length) {
|
||||
error("rmic.option.requires.argument", args[i]);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
if (batch.destDir != null) {
|
||||
error("rmic.option.already.seen", args[i]);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
args[i] = null;
|
||||
batch.destDir = new File(args[++i]);
|
||||
assert batch.destDir != null;
|
||||
args[i] = null;
|
||||
if (!batch.destDir.exists()) {
|
||||
error("rmic.no.such.directory", batch.destDir.getPath());
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
|
||||
} else if (args[i].equals("-v1.1") ||
|
||||
args[i].equals("-vcompat") ||
|
||||
args[i].equals("-v1.2"))
|
||||
{
|
||||
Generator gen = new JrmpGenerator();
|
||||
batch.generators.add(gen);
|
||||
// JrmpGenerator only requires base BatchEnvironment class
|
||||
if (!gen.parseArgs(args, this)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
} else if (args[i].equalsIgnoreCase("-iiop")) {
|
||||
error("rmic.option.unimplemented", args[i]);
|
||||
return null;
|
||||
|
||||
// Generator gen = new IiopGenerator();
|
||||
// batch.generators.add(gen);
|
||||
// if (!batch.envClass.isAssignableFrom(gen.envClass())) {
|
||||
// error("rmic.cannot.use.both",
|
||||
// batch.envClass.getName(), gen.envClass().getName());
|
||||
// return null;
|
||||
// }
|
||||
// batch.envClass = gen.envClass();
|
||||
// if (!gen.parseArgs(args, this)) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
} else if (args[i].equalsIgnoreCase("-idl")) {
|
||||
error("rmic.option.unimplemented", args[i]);
|
||||
return null;
|
||||
|
||||
// see implementation sketch above
|
||||
|
||||
} else if (args[i].equalsIgnoreCase("-xprint")) {
|
||||
error("rmic.option.unimplemented", args[i]);
|
||||
return null;
|
||||
|
||||
// see implementation sketch above
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, all that remains non-null in the args
|
||||
* array are input class names or illegal options.
|
||||
*/
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i] != null) {
|
||||
if (args[i].startsWith("-")) {
|
||||
error("rmic.no.such.option", args[i]);
|
||||
usage();
|
||||
return null;
|
||||
} else {
|
||||
batch.classes.add(args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (batch.classes.isEmpty()) {
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* If options did not specify at least one protocol-specific
|
||||
* generator, then JRMP is the default.
|
||||
*/
|
||||
if (batch.generators.isEmpty()) {
|
||||
batch.generators.add(new JrmpGenerator());
|
||||
}
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Doclet class entry point.
|
||||
**/
|
||||
public static boolean start(RootDoc rootDoc) {
|
||||
|
||||
/*
|
||||
* Find batch ID among javadoc options, and retrieve
|
||||
* corresponding batch data from global table.
|
||||
*/
|
||||
long batchID = -1;
|
||||
for (String[] option : rootDoc.options()) {
|
||||
if (option[0].equals("-batchID")) {
|
||||
try {
|
||||
batchID = Long.parseLong(option[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Batch batch = batchTable.get(batchID);
|
||||
assert batch != null;
|
||||
|
||||
/*
|
||||
* Construct batch environment using class agreed upon by
|
||||
* generator implementations.
|
||||
*/
|
||||
BatchEnvironment env;
|
||||
try {
|
||||
Constructor<? extends BatchEnvironment> cons =
|
||||
batch.envClass.getConstructor(new Class<?>[] { RootDoc.class });
|
||||
env = cons.newInstance(rootDoc);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
env.setVerbose(batch.verbose);
|
||||
|
||||
/*
|
||||
* Determine the destination directory (the top of the package
|
||||
* hierarchy) for the output of this batch; if no destination
|
||||
* directory was specified on the command line, then the
|
||||
* default is the current working directory.
|
||||
*/
|
||||
File destDir = batch.destDir;
|
||||
if (destDir == null) {
|
||||
destDir = new File(System.getProperty("user.dir"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Run each input class through each generator.
|
||||
*/
|
||||
for (String inputClassName : batch.classes) {
|
||||
ClassDoc inputClass = rootDoc.classNamed(inputClassName);
|
||||
try {
|
||||
for (Generator gen : batch.generators) {
|
||||
gen.generate(env, inputClass, destDir);
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
/*
|
||||
* We assume that this means that some class that was
|
||||
* needed (perhaps even a bootstrap class) was not
|
||||
* found, and that javadoc has already reported this
|
||||
* as an error. There is nothing for us to do here
|
||||
* but try to continue with the next input class.
|
||||
*
|
||||
* REMIND: More explicit error checking throughout
|
||||
* would be preferable, however.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile any generated source files, if configured to do so.
|
||||
*/
|
||||
boolean status = true;
|
||||
List<File> generatedFiles = env.generatedFiles();
|
||||
if (!batch.noCompile && !batch.noWrite && !generatedFiles.isEmpty()) {
|
||||
status = batch.enclosingMain().invokeJavac(batch, generatedFiles);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete any generated source files, if configured to do so.
|
||||
*/
|
||||
if (!batch.keepGenerated) {
|
||||
for (File file : generatedFiles) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Doclet class method that indicates that this doclet class
|
||||
* recognizes (only) the "-batchID" option on the javadoc command
|
||||
* line, and that the "-batchID" option comprises two arguments on
|
||||
* the javadoc command line.
|
||||
**/
|
||||
public static int optionLength(String option) {
|
||||
if (option.equals("-batchID")) {
|
||||
return 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the javadoc tool to invoke this class as a doclet, passing
|
||||
* command line options derived from the specified batch data and
|
||||
* indicating the specified batch ID.
|
||||
*
|
||||
* NOTE: This method currently uses a J2SE-internal API to run
|
||||
* javadoc. If and when there is a J2SE API for invoking SDK
|
||||
* tools, this method should be updated to use that API instead.
|
||||
**/
|
||||
private boolean invokeJavadoc(Batch batch, long batchID) {
|
||||
List<String> javadocArgs = new ArrayList<String>();
|
||||
|
||||
// include all types, regardless of language-level access
|
||||
javadocArgs.add("-private");
|
||||
|
||||
// inputs are class names, not source files
|
||||
javadocArgs.add("-Xclasses");
|
||||
|
||||
// reproduce relevant options from rmic invocation
|
||||
if (batch.verbose) {
|
||||
javadocArgs.add("-verbose");
|
||||
}
|
||||
if (batch.bootClassPath != null) {
|
||||
javadocArgs.add("-bootclasspath");
|
||||
javadocArgs.add(batch.bootClassPath);
|
||||
}
|
||||
if (batch.extDirs != null) {
|
||||
javadocArgs.add("-extdirs");
|
||||
javadocArgs.add(batch.extDirs);
|
||||
}
|
||||
if (batch.classPath != null) {
|
||||
javadocArgs.add("-classpath");
|
||||
javadocArgs.add(batch.classPath);
|
||||
}
|
||||
|
||||
// specify batch ID
|
||||
javadocArgs.add("-batchID");
|
||||
javadocArgs.add(Long.toString(batchID));
|
||||
|
||||
/*
|
||||
* Run javadoc on union of rmic input classes and all
|
||||
* generators' bootstrap classes, so that they will all be
|
||||
* available to the doclet code.
|
||||
*/
|
||||
Set<String> classNames = new HashSet<String>();
|
||||
for (Generator gen : batch.generators) {
|
||||
classNames.addAll(gen.bootstrapClassNames());
|
||||
}
|
||||
classNames.addAll(batch.classes);
|
||||
for (String s : classNames) {
|
||||
javadocArgs.add(s);
|
||||
}
|
||||
|
||||
// run javadoc with our program name and output stream
|
||||
int status = com.sun.tools.javadoc.Main.execute(
|
||||
program,
|
||||
new PrintWriter(out, true),
|
||||
new PrintWriter(out, true),
|
||||
new PrintWriter(out, true),
|
||||
this.getClass().getName(), // doclet class is this class
|
||||
javadocArgs.toArray(new String[javadocArgs.size()]));
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the javac tool to compile the specified source files,
|
||||
* passing command line options derived from the specified batch
|
||||
* data.
|
||||
*
|
||||
* NOTE: This method currently uses a J2SE-internal API to run
|
||||
* javac. If and when there is a J2SE API for invoking SDK tools,
|
||||
* this method should be updated to use that API instead.
|
||||
**/
|
||||
private boolean invokeJavac(Batch batch, List<File> files) {
|
||||
List<String> javacArgs = new ArrayList<String>();
|
||||
|
||||
// rmic never wants to display javac warnings
|
||||
javacArgs.add("-nowarn");
|
||||
|
||||
// reproduce relevant options from rmic invocation
|
||||
if (batch.debug) {
|
||||
javacArgs.add("-g");
|
||||
}
|
||||
if (batch.verbose) {
|
||||
javacArgs.add("-verbose");
|
||||
}
|
||||
if (batch.bootClassPath != null) {
|
||||
javacArgs.add("-bootclasspath");
|
||||
javacArgs.add(batch.bootClassPath);
|
||||
}
|
||||
if (batch.extDirs != null) {
|
||||
javacArgs.add("-extdirs");
|
||||
javacArgs.add(batch.extDirs);
|
||||
}
|
||||
if (batch.classPath != null) {
|
||||
javacArgs.add("-classpath");
|
||||
javacArgs.add(batch.classPath);
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, rmic still always produces class files that have a
|
||||
* class file format version compatible with JDK 1.1.
|
||||
*/
|
||||
javacArgs.add("-source");
|
||||
javacArgs.add("1.3");
|
||||
javacArgs.add("-target");
|
||||
javacArgs.add("1.1");
|
||||
|
||||
// add source files to compile
|
||||
for (File file : files) {
|
||||
javacArgs.add(file.getPath());
|
||||
}
|
||||
|
||||
// run javac with our output stream
|
||||
int status = com.sun.tools.javac.Main.compile(
|
||||
javacArgs.toArray(new String[javacArgs.size()]),
|
||||
new PrintWriter(out, true));
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The data for an rmic compliation batch: the processed command
|
||||
* line arguments.
|
||||
**/
|
||||
private class Batch {
|
||||
boolean keepGenerated = false; // -keep or -keepgenerated
|
||||
boolean debug = false; // -g
|
||||
boolean noWarn = false; // -nowarn
|
||||
boolean noWrite = false; // -nowrite
|
||||
boolean verbose = false; // -verbose
|
||||
boolean noCompile = false; // -Xnocompile
|
||||
String bootClassPath = null; // -bootclasspath
|
||||
String extDirs = null; // -extdirs
|
||||
String classPath = null; // -classpath
|
||||
File destDir = null; // -d
|
||||
List<Generator> generators = new ArrayList<Generator>();
|
||||
Class<? extends BatchEnvironment> envClass = BatchEnvironment.class;
|
||||
List<String> classes = new ArrayList<String>();
|
||||
|
||||
Batch() { }
|
||||
|
||||
/**
|
||||
* Returns the Main instance for this batch.
|
||||
**/
|
||||
Main enclosingMain() {
|
||||
return Main.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
95
jdkSrc/jdk8/sun/rmi/rmic/newrmic/Resources.java
Normal file
95
jdkSrc/jdk8/sun/rmi/rmic/newrmic/Resources.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.newrmic;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Provides resource support for rmic.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
public final class Resources {
|
||||
|
||||
private static ResourceBundle resources = null;
|
||||
private static ResourceBundle resourcesExt = null;
|
||||
static {
|
||||
try {
|
||||
resources =
|
||||
ResourceBundle.getBundle("sun.rmi.rmic.resources.rmic");
|
||||
} catch (MissingResourceException e) {
|
||||
// gracefully handle this later
|
||||
}
|
||||
try {
|
||||
resourcesExt =
|
||||
ResourceBundle.getBundle("sun.rmi.rmic.resources.rmicext");
|
||||
} catch (MissingResourceException e) {
|
||||
// OK if this isn't found
|
||||
}
|
||||
}
|
||||
|
||||
private Resources() { throw new AssertionError(); }
|
||||
|
||||
/**
|
||||
* Returns the text of the rmic resource for the specified key
|
||||
* formatted with the specified arguments.
|
||||
**/
|
||||
public static String getText(String key, String... args) {
|
||||
String format = getString(key);
|
||||
if (format == null) {
|
||||
format = "missing resource key: key = \"" + key + "\", " +
|
||||
"arguments = \"{0}\", \"{1}\", \"{2}\"";
|
||||
}
|
||||
return MessageFormat.format(format, (Object[]) args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rmic resource string for the specified key.
|
||||
**/
|
||||
private static String getString(String key) {
|
||||
if (resourcesExt != null) {
|
||||
try {
|
||||
return resourcesExt.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
}
|
||||
}
|
||||
if (resources != null) {
|
||||
try {
|
||||
return resources.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return "missing resource bundle: key = \"" + key + "\", " +
|
||||
"arguments = \"{0}\", \"{1}\", \"{2}\"";
|
||||
}
|
||||
}
|
||||
70
jdkSrc/jdk8/sun/rmi/rmic/newrmic/jrmp/Constants.java
Normal file
70
jdkSrc/jdk8/sun/rmi/rmic/newrmic/jrmp/Constants.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.newrmic.jrmp;
|
||||
|
||||
/**
|
||||
* Constants specific to the JRMP rmic generator.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
final class Constants {
|
||||
|
||||
private Constants() { throw new AssertionError(); }
|
||||
|
||||
/*
|
||||
* fully-qualified names of types used by rmic
|
||||
*/
|
||||
static final String REMOTE_OBJECT = "java.rmi.server.RemoteObject";
|
||||
static final String REMOTE_STUB = "java.rmi.server.RemoteStub";
|
||||
static final String REMOTE_REF = "java.rmi.server.RemoteRef";
|
||||
static final String OPERATION = "java.rmi.server.Operation";
|
||||
static final String SKELETON = "java.rmi.server.Skeleton";
|
||||
static final String SKELETON_MISMATCH_EXCEPTION =
|
||||
"java.rmi.server.SkeletonMismatchException";
|
||||
static final String REMOTE_CALL = "java.rmi.server.RemoteCall";
|
||||
static final String MARSHAL_EXCEPTION = "java.rmi.MarshalException";
|
||||
static final String UNMARSHAL_EXCEPTION = "java.rmi.UnmarshalException";
|
||||
static final String UNEXPECTED_EXCEPTION = "java.rmi.UnexpectedException";
|
||||
|
||||
/*
|
||||
* stub protocol versions
|
||||
*/
|
||||
enum StubVersion { V1_1, VCOMPAT, V1_2 };
|
||||
|
||||
/*
|
||||
* serialVersionUID for all stubs that can use 1.2 protocol
|
||||
*/
|
||||
static final long STUB_SERIAL_VERSION_UID = 2;
|
||||
|
||||
/*
|
||||
* version number used to seed interface hash computation
|
||||
*/
|
||||
static final int INTERFACE_HASH_STUB_VERSION = 1;
|
||||
}
|
||||
226
jdkSrc/jdk8/sun/rmi/rmic/newrmic/jrmp/JrmpGenerator.java
Normal file
226
jdkSrc/jdk8/sun/rmi/rmic/newrmic/jrmp/JrmpGenerator.java
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.newrmic.jrmp;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import sun.rmi.rmic.newrmic.BatchEnvironment;
|
||||
import sun.rmi.rmic.newrmic.Generator;
|
||||
import sun.rmi.rmic.newrmic.IndentingWriter;
|
||||
import sun.rmi.rmic.newrmic.Main;
|
||||
import sun.rmi.rmic.newrmic.Resources;
|
||||
|
||||
import static sun.rmi.rmic.newrmic.jrmp.Constants.*;
|
||||
|
||||
/**
|
||||
* JRMP rmic back end; generates source code for JRMP stub and
|
||||
* skeleton classes.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
public class JrmpGenerator implements Generator {
|
||||
|
||||
private static final Map<String,StubVersion> versionOptions =
|
||||
new HashMap<String,StubVersion>();
|
||||
static {
|
||||
versionOptions.put("-v1.1", StubVersion.V1_1);
|
||||
versionOptions.put("-vcompat", StubVersion.VCOMPAT);
|
||||
versionOptions.put("-v1.2", StubVersion.V1_2);
|
||||
}
|
||||
|
||||
private static final Set<String> bootstrapClassNames =
|
||||
new HashSet<String>();
|
||||
static {
|
||||
bootstrapClassNames.add("java.lang.Exception");
|
||||
bootstrapClassNames.add("java.rmi.Remote");
|
||||
bootstrapClassNames.add("java.rmi.RemoteException");
|
||||
bootstrapClassNames.add("java.lang.RuntimeException");
|
||||
};
|
||||
|
||||
/** version of the JRMP stub protocol to generate code for */
|
||||
private StubVersion version = StubVersion.V1_2; // default is -v1.2
|
||||
|
||||
/**
|
||||
* Creates a new JrmpGenerator.
|
||||
**/
|
||||
public JrmpGenerator() { }
|
||||
|
||||
/**
|
||||
* The JRMP generator recognizes command line options for
|
||||
* selecting the JRMP stub protocol version to generate classes
|
||||
* for. Only one such option is allowed.
|
||||
**/
|
||||
public boolean parseArgs(String[] args, Main main) {
|
||||
String explicitVersion = null;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
String arg = args[i];
|
||||
if (versionOptions.containsKey(arg)) {
|
||||
if (explicitVersion != null && !explicitVersion.equals(arg)) {
|
||||
main.error("rmic.cannot.use.both", explicitVersion, arg);
|
||||
return false;
|
||||
}
|
||||
explicitVersion = arg;
|
||||
version = versionOptions.get(arg);
|
||||
args[i] = null;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The JRMP generator does not require an environment class more
|
||||
* specific than BatchEnvironment.
|
||||
**/
|
||||
public Class<? extends BatchEnvironment> envClass() {
|
||||
return BatchEnvironment.class;
|
||||
}
|
||||
|
||||
public Set<String> bootstrapClassNames() {
|
||||
return Collections.unmodifiableSet(bootstrapClassNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the source file(s) for the JRMP stub class and
|
||||
* (optionally) skeleton class for the specified remote
|
||||
* implementation class.
|
||||
**/
|
||||
public void generate(BatchEnvironment env,
|
||||
ClassDoc inputClass,
|
||||
File destDir)
|
||||
{
|
||||
RemoteClass remoteClass = RemoteClass.forClass(env, inputClass);
|
||||
if (remoteClass == null) {
|
||||
return; // an error must have occurred
|
||||
}
|
||||
|
||||
StubSkeletonWriter writer =
|
||||
new StubSkeletonWriter(env, remoteClass, version);
|
||||
|
||||
File stubFile = sourceFileForClass(writer.stubClassName(), destDir);
|
||||
try {
|
||||
IndentingWriter out = new IndentingWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(stubFile)));
|
||||
writer.writeStub(out);
|
||||
out.close();
|
||||
if (env.verbose()) {
|
||||
env.output(Resources.getText("rmic.wrote",
|
||||
stubFile.getPath()));
|
||||
}
|
||||
env.addGeneratedFile(stubFile);
|
||||
} catch (IOException e) {
|
||||
env.error("rmic.cant.write", stubFile.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
File skeletonFile =
|
||||
sourceFileForClass(writer.skeletonClassName(), destDir);
|
||||
if (version == StubVersion.V1_1 ||
|
||||
version == StubVersion.VCOMPAT)
|
||||
{
|
||||
try {
|
||||
IndentingWriter out = new IndentingWriter(
|
||||
new OutputStreamWriter(
|
||||
new FileOutputStream(skeletonFile)));
|
||||
writer.writeSkeleton(out);
|
||||
out.close();
|
||||
if (env.verbose()) {
|
||||
env.output(Resources.getText("rmic.wrote",
|
||||
skeletonFile.getPath()));
|
||||
}
|
||||
env.addGeneratedFile(skeletonFile);
|
||||
} catch (IOException e) {
|
||||
env.error("rmic.cant.write", skeletonFile.toString());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If skeleton files are not being generated for this run,
|
||||
* delete old skeleton source or class files for this
|
||||
* remote implementation class that were (presumably) left
|
||||
* over from previous runs, to avoid user confusion from
|
||||
* extraneous or inconsistent generated files.
|
||||
*/
|
||||
File skeletonClassFile =
|
||||
classFileForClass(writer.skeletonClassName(), destDir);
|
||||
|
||||
skeletonFile.delete(); // ignore failures (no big deal)
|
||||
skeletonClassFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the File object to be used as the source file for a
|
||||
* class with the specified binary name, with the specified
|
||||
* destination directory as the top of the package hierarchy.
|
||||
**/
|
||||
private File sourceFileForClass(String binaryName, File destDir) {
|
||||
return fileForClass(binaryName, destDir, ".java");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the File object to be used as the class file for a
|
||||
* class with the specified binary name, with the supplied
|
||||
* destination directory as the top of the package hierarchy.
|
||||
**/
|
||||
private File classFileForClass(String binaryName, File destDir) {
|
||||
return fileForClass(binaryName, destDir, ".class");
|
||||
}
|
||||
|
||||
private File fileForClass(String binaryName, File destDir, String ext) {
|
||||
int i = binaryName.lastIndexOf('.');
|
||||
String classFileName = binaryName.substring(i + 1) + ext;
|
||||
if (i != -1) {
|
||||
String packageName = binaryName.substring(0, i);
|
||||
String packagePath = packageName.replace('.', File.separatorChar);
|
||||
File packageDir = new File(destDir, packagePath);
|
||||
/*
|
||||
* Make sure that the directory for this package exists.
|
||||
* We assume that the caller has verified that the top-
|
||||
* level destination directory exists, so we need not
|
||||
* worry about creating it unintentionally.
|
||||
*/
|
||||
if (!packageDir.exists()) {
|
||||
packageDir.mkdirs();
|
||||
}
|
||||
return new File(packageDir, classFileName);
|
||||
} else {
|
||||
return new File(destDir, classFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
710
jdkSrc/jdk8/sun/rmi/rmic/newrmic/jrmp/RemoteClass.java
Normal file
710
jdkSrc/jdk8/sun/rmi/rmic/newrmic/jrmp/RemoteClass.java
Normal file
@@ -0,0 +1,710 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.newrmic.jrmp;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.MethodDoc;
|
||||
import com.sun.javadoc.Parameter;
|
||||
import com.sun.javadoc.Type;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import sun.rmi.rmic.newrmic.BatchEnvironment;
|
||||
|
||||
import static sun.rmi.rmic.newrmic.Constants.*;
|
||||
import static sun.rmi.rmic.newrmic.jrmp.Constants.*;
|
||||
|
||||
/**
|
||||
* Encapsulates RMI-specific information about a remote implementation
|
||||
* class (a class that implements one or more remote interfaces).
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
final class RemoteClass {
|
||||
|
||||
/** rmic environment for this object */
|
||||
private final BatchEnvironment env;
|
||||
|
||||
/** the remote implementation class this object represents */
|
||||
private final ClassDoc implClass;
|
||||
|
||||
/** remote interfaces implemented by this class */
|
||||
private ClassDoc[] remoteInterfaces;
|
||||
|
||||
/** the remote methods of this class */
|
||||
private Method[] remoteMethods;
|
||||
|
||||
/** stub/skeleton "interface hash" for this class */
|
||||
private long interfaceHash;
|
||||
|
||||
/**
|
||||
* Creates a RemoteClass instance that represents the RMI-specific
|
||||
* information about the specified remote implementation class.
|
||||
*
|
||||
* If the class is not a valid remote implementation class or if
|
||||
* some other error occurs, the return value will be null, and
|
||||
* errors will have been reported to the supplied
|
||||
* BatchEnvironment.
|
||||
**/
|
||||
static RemoteClass forClass(BatchEnvironment env, ClassDoc implClass) {
|
||||
RemoteClass remoteClass = new RemoteClass(env, implClass);
|
||||
if (remoteClass.init()) {
|
||||
return remoteClass;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a RemoteClass instance for the specified class. The
|
||||
* resulting object is not yet initialized.
|
||||
**/
|
||||
private RemoteClass(BatchEnvironment env, ClassDoc implClass) {
|
||||
this.env = env;
|
||||
this.implClass = implClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ClassDoc for this remote implementation class.
|
||||
**/
|
||||
ClassDoc classDoc() {
|
||||
return implClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remote interfaces implemented by this remote
|
||||
* implementation class.
|
||||
*
|
||||
* A remote interface is an interface that is a subinterface of
|
||||
* java.rmi.Remote. The remote interfaces of a class are the
|
||||
* direct superinterfaces of the class and all of its superclasses
|
||||
* that are remote interfaces.
|
||||
*
|
||||
* The order of the array returned is arbitrary, and some elements
|
||||
* may be superfluous (i.e., superinterfaces of other interfaces
|
||||
* in the array).
|
||||
**/
|
||||
ClassDoc[] remoteInterfaces() {
|
||||
return remoteInterfaces.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of RemoteClass.Method objects representing all
|
||||
* of the remote methods of this remote implementation class (all
|
||||
* of the member methods of the class's remote interfaces).
|
||||
*
|
||||
* The methods in the array are ordered according to a comparison
|
||||
* of strings consisting of their name followed by their
|
||||
* descriptor, so each method's index in the array corresponds to
|
||||
* its "operation number" in the JDK 1.1 version of the JRMP
|
||||
* stub/skeleton protocol.
|
||||
**/
|
||||
Method[] remoteMethods() {
|
||||
return remoteMethods.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "interface hash" used to match a stub/skeleton pair
|
||||
* for this remote implementation class in the JDK 1.1 version of
|
||||
* the JRMP stub/skeleton protocol.
|
||||
**/
|
||||
long interfaceHash() {
|
||||
return interfaceHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates this remote implementation class and computes the
|
||||
* RMI-specific information. Returns true if successful, or false
|
||||
* if an error occurred.
|
||||
**/
|
||||
private boolean init() {
|
||||
/*
|
||||
* Verify that it is really a class, not an interface.
|
||||
*/
|
||||
if (implClass.isInterface()) {
|
||||
env.error("rmic.cant.make.stubs.for.interface",
|
||||
implClass.qualifiedName());
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find all of the remote interfaces of our remote
|
||||
* implementation class-- for each class up the superclass
|
||||
* chain, add each directly-implemented interface that somehow
|
||||
* extends Remote to a list.
|
||||
*/
|
||||
List<ClassDoc> remotesImplemented = new ArrayList<ClassDoc>();
|
||||
for (ClassDoc cl = implClass; cl != null; cl = cl.superclass()) {
|
||||
for (ClassDoc intf : cl.interfaces()) {
|
||||
/*
|
||||
* Add interface to the list if it extends Remote and
|
||||
* it is not already there.
|
||||
*/
|
||||
if (!remotesImplemented.contains(intf) &&
|
||||
intf.subclassOf(env.docRemote()))
|
||||
{
|
||||
remotesImplemented.add(intf);
|
||||
if (env.verbose()) {
|
||||
env.output("[found remote interface: " +
|
||||
intf.qualifiedName() + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that the candidate remote implementation class
|
||||
* implements at least one remote interface directly.
|
||||
*/
|
||||
if (cl == implClass && remotesImplemented.isEmpty()) {
|
||||
if (implClass.subclassOf(env.docRemote())) {
|
||||
/*
|
||||
* This error message is used if the class does
|
||||
* implement a remote interface through one of its
|
||||
* superclasses, but not directly.
|
||||
*/
|
||||
env.error("rmic.must.implement.remote.directly",
|
||||
implClass.qualifiedName());
|
||||
} else {
|
||||
/*
|
||||
* This error message is used if the class does
|
||||
* not implement a remote interface at all.
|
||||
*/
|
||||
env.error("rmic.must.implement.remote",
|
||||
implClass.qualifiedName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert list of remote interfaces to an array
|
||||
* (order is not important for this array).
|
||||
*/
|
||||
remoteInterfaces =
|
||||
remotesImplemented.toArray(
|
||||
new ClassDoc[remotesImplemented.size()]);
|
||||
|
||||
/*
|
||||
* Collect the methods from all of the remote interfaces into
|
||||
* a table, which maps from method name-and-descriptor string
|
||||
* to Method object.
|
||||
*/
|
||||
Map<String,Method> methods = new HashMap<String,Method>();
|
||||
boolean errors = false;
|
||||
for (ClassDoc intf : remotesImplemented) {
|
||||
if (!collectRemoteMethods(intf, methods)) {
|
||||
/*
|
||||
* Continue iterating despite errors in order to
|
||||
* generate more complete error report.
|
||||
*/
|
||||
errors = true;
|
||||
}
|
||||
}
|
||||
if (errors) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort table of remote methods into an array. The elements
|
||||
* are sorted in ascending order of the string of the method's
|
||||
* name and descriptor, so that each elements index is equal
|
||||
* to its operation number in the JDK 1.1 version of the JRMP
|
||||
* stub/skeleton protocol.
|
||||
*/
|
||||
String[] orderedKeys =
|
||||
methods.keySet().toArray(new String[methods.size()]);
|
||||
Arrays.sort(orderedKeys);
|
||||
remoteMethods = new Method[methods.size()];
|
||||
for (int i = 0; i < remoteMethods.length; i++) {
|
||||
remoteMethods[i] = methods.get(orderedKeys[i]);
|
||||
if (env.verbose()) {
|
||||
String msg = "[found remote method <" + i + ">: " +
|
||||
remoteMethods[i].operationString();
|
||||
ClassDoc[] exceptions = remoteMethods[i].exceptionTypes();
|
||||
if (exceptions.length > 0) {
|
||||
msg += " throws ";
|
||||
for (int j = 0; j < exceptions.length; j++) {
|
||||
if (j > 0) {
|
||||
msg += ", ";
|
||||
}
|
||||
msg += exceptions[j].qualifiedName();
|
||||
}
|
||||
}
|
||||
msg += "\n\tname and descriptor = \"" +
|
||||
remoteMethods[i].nameAndDescriptor();
|
||||
msg += "\n\tmethod hash = " +
|
||||
remoteMethods[i].methodHash() + "]";
|
||||
env.output(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, pre-compute the interface hash to be used by
|
||||
* stubs/skeletons for this remote class in the JDK 1.1
|
||||
* version of the JRMP stub/skeleton protocol.
|
||||
*/
|
||||
interfaceHash = computeInterfaceHash();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects and validates all methods from the specified interface
|
||||
* and all of its superinterfaces as remote methods. Remote
|
||||
* methods are added to the supplied table. Returns true if
|
||||
* successful, or false if an error occurred.
|
||||
**/
|
||||
private boolean collectRemoteMethods(ClassDoc intf,
|
||||
Map<String,Method> table)
|
||||
{
|
||||
if (!intf.isInterface()) {
|
||||
throw new AssertionError(
|
||||
intf.qualifiedName() + " not an interface");
|
||||
}
|
||||
|
||||
boolean errors = false;
|
||||
|
||||
/*
|
||||
* Search interface's declared methods.
|
||||
*/
|
||||
nextMethod:
|
||||
for (MethodDoc method : intf.methods()) {
|
||||
|
||||
/*
|
||||
* Verify that each method throws RemoteException (or a
|
||||
* superclass of RemoteException).
|
||||
*/
|
||||
boolean hasRemoteException = false;
|
||||
for (ClassDoc ex : method.thrownExceptions()) {
|
||||
if (env.docRemoteException().subclassOf(ex)) {
|
||||
hasRemoteException = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this method did not throw RemoteException as required,
|
||||
* generate the error but continue, so that multiple such
|
||||
* errors can be reported.
|
||||
*/
|
||||
if (!hasRemoteException) {
|
||||
env.error("rmic.must.throw.remoteexception",
|
||||
intf.qualifiedName(),
|
||||
method.name() + method.signature());
|
||||
errors = true;
|
||||
continue nextMethod;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that the implementation of this method throws only
|
||||
* java.lang.Exception or its subclasses (fix bugid 4092486).
|
||||
* JRMP does not support remote methods throwing
|
||||
* java.lang.Throwable or other subclasses.
|
||||
*/
|
||||
MethodDoc implMethod = findImplMethod(method);
|
||||
if (implMethod != null) { // should not be null
|
||||
for (ClassDoc ex : implMethod.thrownExceptions()) {
|
||||
if (!ex.subclassOf(env.docException())) {
|
||||
env.error("rmic.must.only.throw.exception",
|
||||
implMethod.name() + implMethod.signature(),
|
||||
ex.qualifiedName());
|
||||
errors = true;
|
||||
continue nextMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create RemoteClass.Method object to represent this method
|
||||
* found in a remote interface.
|
||||
*/
|
||||
Method newMethod = new Method(method);
|
||||
|
||||
/*
|
||||
* Store remote method's representation in the table of
|
||||
* remote methods found, keyed by its name and descriptor.
|
||||
*
|
||||
* If the table already contains an entry with the same
|
||||
* method name and descriptor, then we must replace the
|
||||
* old entry with a Method object that represents a legal
|
||||
* combination of the old and the new methods;
|
||||
* specifically, the combined method must have a throws
|
||||
* clause that contains (only) all of the checked
|
||||
* exceptions that can be thrown by both the old and the
|
||||
* new method (see bugid 4070653).
|
||||
*/
|
||||
String key = newMethod.nameAndDescriptor();
|
||||
Method oldMethod = table.get(key);
|
||||
if (oldMethod != null) {
|
||||
newMethod = newMethod.mergeWith(oldMethod);
|
||||
}
|
||||
table.put(key, newMethod);
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursively collect methods for all superinterfaces.
|
||||
*/
|
||||
for (ClassDoc superintf : intf.interfaces()) {
|
||||
if (!collectRemoteMethods(superintf, table)) {
|
||||
errors = true;
|
||||
}
|
||||
}
|
||||
|
||||
return !errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MethodDoc for the method of this remote
|
||||
* implementation class that implements the specified remote
|
||||
* method of a remote interface. Returns null if no matching
|
||||
* method was found in this remote implementation class.
|
||||
**/
|
||||
private MethodDoc findImplMethod(MethodDoc interfaceMethod) {
|
||||
String name = interfaceMethod.name();
|
||||
String desc = Util.methodDescriptorOf(interfaceMethod);
|
||||
for (MethodDoc implMethod : implClass.methods()) {
|
||||
if (name.equals(implMethod.name()) &&
|
||||
desc.equals(Util.methodDescriptorOf(implMethod)))
|
||||
{
|
||||
return implMethod;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the "interface hash" of the stub/skeleton pair for
|
||||
* this remote implementation class. This is the 64-bit value
|
||||
* used to enforce compatibility between a stub class and a
|
||||
* skeleton class in the JDK 1.1 version of the JRMP stub/skeleton
|
||||
* protocol.
|
||||
*
|
||||
* It is calculated using the first 64 bits of an SHA digest. The
|
||||
* digest is of a stream consisting of the following data:
|
||||
* (int) stub version number, always 1
|
||||
* for each remote method, in order of operation number:
|
||||
* (UTF-8) method name
|
||||
* (UTF-8) method descriptor
|
||||
* for each declared exception, in alphabetical name order:
|
||||
* (UTF-8) name of exception class
|
||||
* (where "UTF-8" includes a 16-bit length prefix as written by
|
||||
* java.io.DataOutput.writeUTF).
|
||||
**/
|
||||
private long computeInterfaceHash() {
|
||||
long hash = 0;
|
||||
ByteArrayOutputStream sink = new ByteArrayOutputStream(512);
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
DataOutputStream out = new DataOutputStream(
|
||||
new DigestOutputStream(sink, md));
|
||||
|
||||
out.writeInt(INTERFACE_HASH_STUB_VERSION);
|
||||
|
||||
for (Method method : remoteMethods) {
|
||||
MethodDoc methodDoc = method.methodDoc();
|
||||
|
||||
out.writeUTF(methodDoc.name());
|
||||
out.writeUTF(Util.methodDescriptorOf(methodDoc));
|
||||
// descriptors already use binary names
|
||||
|
||||
ClassDoc exceptions[] = methodDoc.thrownExceptions();
|
||||
Arrays.sort(exceptions, new ClassDocComparator());
|
||||
for (ClassDoc ex : exceptions) {
|
||||
out.writeUTF(Util.binaryNameOf(ex));
|
||||
}
|
||||
}
|
||||
out.flush();
|
||||
|
||||
// use only the first 64 bits of the digest for the hash
|
||||
byte hashArray[] = md.digest();
|
||||
for (int i = 0; i < Math.min(8, hashArray.length); i++) {
|
||||
hash += ((long) (hashArray[i] & 0xFF)) << (i * 8);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares ClassDoc instances according to the lexicographic
|
||||
* order of their binary names.
|
||||
**/
|
||||
private static class ClassDocComparator implements Comparator<ClassDoc> {
|
||||
public int compare(ClassDoc o1, ClassDoc o2) {
|
||||
return Util.binaryNameOf(o1).compareTo(Util.binaryNameOf(o2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates RMI-specific information about a particular remote
|
||||
* method in the remote implementation class represented by the
|
||||
* enclosing RemoteClass.
|
||||
**/
|
||||
final class Method implements Cloneable {
|
||||
|
||||
/**
|
||||
* MethodDoc for this remove method, from one of the remote
|
||||
* interfaces that this method was found in.
|
||||
*
|
||||
* Note that this MethodDoc may be only one of multiple that
|
||||
* correspond to this remote method object, if multiple of
|
||||
* this class's remote interfaces contain methods with the
|
||||
* same name and descriptor. Therefore, this MethodDoc may
|
||||
* declare more exceptions thrown that this remote method
|
||||
* does.
|
||||
**/
|
||||
private final MethodDoc methodDoc;
|
||||
|
||||
/** java.rmi.server.Operation string for this remote method */
|
||||
private final String operationString;
|
||||
|
||||
/** name and descriptor of this remote method */
|
||||
private final String nameAndDescriptor;
|
||||
|
||||
/** JRMP "method hash" for this remote method */
|
||||
private final long methodHash;
|
||||
|
||||
/**
|
||||
* Exceptions declared to be thrown by this remote method.
|
||||
*
|
||||
* This list may include superfluous entries, such as
|
||||
* unchecked exceptions and subclasses of other entries.
|
||||
**/
|
||||
private ClassDoc[] exceptionTypes;
|
||||
|
||||
/**
|
||||
* Creates a new Method instance for the specified method.
|
||||
**/
|
||||
Method(MethodDoc methodDoc) {
|
||||
this.methodDoc = methodDoc;
|
||||
exceptionTypes = methodDoc.thrownExceptions();
|
||||
/*
|
||||
* Sort exception types to improve consistency with
|
||||
* previous implementations.
|
||||
*/
|
||||
Arrays.sort(exceptionTypes, new ClassDocComparator());
|
||||
operationString = computeOperationString();
|
||||
nameAndDescriptor =
|
||||
methodDoc.name() + Util.methodDescriptorOf(methodDoc);
|
||||
methodHash = computeMethodHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MethodDoc object corresponding to this method
|
||||
* of a remote interface.
|
||||
**/
|
||||
MethodDoc methodDoc() {
|
||||
return methodDoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameter types declared by this method.
|
||||
**/
|
||||
Type[] parameterTypes() {
|
||||
Parameter[] parameters = methodDoc.parameters();
|
||||
Type[] paramTypes = new Type[parameters.length];
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
paramTypes[i] = parameters[i].type();
|
||||
}
|
||||
return paramTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exception types declared to be thrown by this
|
||||
* remote method.
|
||||
*
|
||||
* For methods with the same name and descriptor inherited
|
||||
* from multiple remote interfaces, the array will contain the
|
||||
* set of exceptions declared in all of the interfaces'
|
||||
* methods that can be legally thrown by all of them.
|
||||
**/
|
||||
ClassDoc[] exceptionTypes() {
|
||||
return exceptionTypes.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JRMP "method hash" used to identify this remote
|
||||
* method in the JDK 1.2 version of the stub protocol.
|
||||
**/
|
||||
long methodHash() {
|
||||
return methodHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation of this method
|
||||
* appropriate for the construction of a
|
||||
* java.rmi.server.Operation object.
|
||||
**/
|
||||
String operationString() {
|
||||
return operationString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string consisting of this method's name followed
|
||||
* by its descriptor.
|
||||
**/
|
||||
String nameAndDescriptor() {
|
||||
return nameAndDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new Method object that is a legal combination of
|
||||
* this Method object and another one.
|
||||
*
|
||||
* Doing this requires determining the exceptions declared by
|
||||
* the combined method, which must be (only) all of the
|
||||
* exceptions declared in both old Methods that may thrown in
|
||||
* either of them.
|
||||
**/
|
||||
Method mergeWith(Method other) {
|
||||
if (!nameAndDescriptor().equals(other.nameAndDescriptor())) {
|
||||
throw new AssertionError(
|
||||
"attempt to merge method \"" +
|
||||
other.nameAndDescriptor() + "\" with \"" +
|
||||
nameAndDescriptor());
|
||||
}
|
||||
|
||||
List<ClassDoc> legalExceptions = new ArrayList<ClassDoc>();
|
||||
collectCompatibleExceptions(
|
||||
other.exceptionTypes, exceptionTypes, legalExceptions);
|
||||
collectCompatibleExceptions(
|
||||
exceptionTypes, other.exceptionTypes, legalExceptions);
|
||||
|
||||
Method merged = clone();
|
||||
merged.exceptionTypes =
|
||||
legalExceptions.toArray(new ClassDoc[legalExceptions.size()]);
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cloning is supported by returning a shallow copy of this
|
||||
* object.
|
||||
**/
|
||||
protected Method clone() {
|
||||
try {
|
||||
return (Method) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the supplied list all exceptions in the "froms"
|
||||
* array that are subclasses of an exception in the "withs"
|
||||
* array.
|
||||
**/
|
||||
private void collectCompatibleExceptions(ClassDoc[] froms,
|
||||
ClassDoc[] withs,
|
||||
List<ClassDoc> list)
|
||||
{
|
||||
for (ClassDoc from : froms) {
|
||||
if (!list.contains(from)) {
|
||||
for (ClassDoc with : withs) {
|
||||
if (from.subclassOf(with)) {
|
||||
list.add(from);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the JRMP "method hash" of this remote method. The
|
||||
* method hash is a long containing the first 64 bits of the
|
||||
* SHA digest from the UTF-8 encoded string of the method name
|
||||
* and descriptor.
|
||||
**/
|
||||
private long computeMethodHash() {
|
||||
long hash = 0;
|
||||
ByteArrayOutputStream sink = new ByteArrayOutputStream(512);
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
DataOutputStream out = new DataOutputStream(
|
||||
new DigestOutputStream(sink, md));
|
||||
|
||||
String methodString = nameAndDescriptor();
|
||||
out.writeUTF(methodString);
|
||||
|
||||
// use only the first 64 bits of the digest for the hash
|
||||
out.flush();
|
||||
byte hashArray[] = md.digest();
|
||||
for (int i = 0; i < Math.min(8, hashArray.length); i++) {
|
||||
hash += ((long) (hashArray[i] & 0xFF)) << (i * 8);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the string representation of this method
|
||||
* appropriate for the construction of a
|
||||
* java.rmi.server.Operation object.
|
||||
**/
|
||||
private String computeOperationString() {
|
||||
/*
|
||||
* To be consistent with previous implementations, we use
|
||||
* the deprecated style of placing the "[]" for the return
|
||||
* type (if any) after the parameter list.
|
||||
*/
|
||||
Type returnType = methodDoc.returnType();
|
||||
String op = returnType.qualifiedTypeName() + " " +
|
||||
methodDoc.name() + "(";
|
||||
Parameter[] parameters = methodDoc.parameters();
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
if (i > 0) {
|
||||
op += ", ";
|
||||
}
|
||||
op += parameters[i].type().toString();
|
||||
}
|
||||
op += ")" + returnType.dimension();
|
||||
return op;
|
||||
}
|
||||
}
|
||||
}
|
||||
1079
jdkSrc/jdk8/sun/rmi/rmic/newrmic/jrmp/StubSkeletonWriter.java
Normal file
1079
jdkSrc/jdk8/sun/rmi/rmic/newrmic/jrmp/StubSkeletonWriter.java
Normal file
File diff suppressed because it is too large
Load Diff
149
jdkSrc/jdk8/sun/rmi/rmic/newrmic/jrmp/Util.java
Normal file
149
jdkSrc/jdk8/sun/rmi/rmic/newrmic/jrmp/Util.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.rmic.newrmic.jrmp;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.MethodDoc;
|
||||
import com.sun.javadoc.Parameter;
|
||||
import com.sun.javadoc.Type;
|
||||
|
||||
/**
|
||||
* Provides static utility methods.
|
||||
*
|
||||
* WARNING: The contents of this source file are not part of any
|
||||
* supported API. Code that depends on them does so at its own risk:
|
||||
* they are subject to change or removal without notice.
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
final class Util {
|
||||
|
||||
private Util() { throw new AssertionError(); }
|
||||
|
||||
/**
|
||||
* Returns the binary name of the class or interface represented
|
||||
* by the specified ClassDoc.
|
||||
**/
|
||||
static String binaryNameOf(ClassDoc cl) {
|
||||
String flat = cl.name().replace('.', '$');
|
||||
String packageName = cl.containingPackage().name();
|
||||
return packageName.equals("") ? flat : packageName + "." + flat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method descriptor for the specified method.
|
||||
*
|
||||
* See section 4.3.3 of The Java Virtual Machine Specification
|
||||
* Second Edition for the definition of a "method descriptor".
|
||||
**/
|
||||
static String methodDescriptorOf(MethodDoc method) {
|
||||
String desc = "(";
|
||||
Parameter[] parameters = method.parameters();
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
desc += typeDescriptorOf(parameters[i].type());
|
||||
}
|
||||
desc += ")" + typeDescriptorOf(method.returnType());
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the descriptor for the specified type, as appropriate
|
||||
* for either a parameter or return type in a method descriptor.
|
||||
**/
|
||||
private static String typeDescriptorOf(Type type) {
|
||||
String desc;
|
||||
ClassDoc classDoc = type.asClassDoc();
|
||||
if (classDoc == null) {
|
||||
/*
|
||||
* Handle primitive types.
|
||||
*/
|
||||
String name = type.typeName();
|
||||
if (name.equals("boolean")) {
|
||||
desc = "Z";
|
||||
} else if (name.equals("byte")) {
|
||||
desc = "B";
|
||||
} else if (name.equals("char")) {
|
||||
desc = "C";
|
||||
} else if (name.equals("short")) {
|
||||
desc = "S";
|
||||
} else if (name.equals("int")) {
|
||||
desc = "I";
|
||||
} else if (name.equals("long")) {
|
||||
desc = "J";
|
||||
} else if (name.equals("float")) {
|
||||
desc = "F";
|
||||
} else if (name.equals("double")) {
|
||||
desc = "D";
|
||||
} else if (name.equals("void")) {
|
||||
desc = "V";
|
||||
} else {
|
||||
throw new AssertionError(
|
||||
"unrecognized primitive type: " + name);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Handle non-array reference types.
|
||||
*/
|
||||
desc = "L" + binaryNameOf(classDoc).replace('.', '/') + ";";
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle array types.
|
||||
*/
|
||||
int dimensions = type.dimension().length() / 2;
|
||||
for (int i = 0; i < dimensions; i++) {
|
||||
desc = "[" + desc;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reader-friendly string representation of the
|
||||
* specified method's signature. Names of reference types are not
|
||||
* package-qualified.
|
||||
**/
|
||||
static String getFriendlyUnqualifiedSignature(MethodDoc method) {
|
||||
String sig = method.name() + "(";
|
||||
Parameter[] parameters = method.parameters();
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
if (i > 0) {
|
||||
sig += ", ";
|
||||
}
|
||||
Type paramType = parameters[i].type();
|
||||
sig += paramType.typeName() + paramType.dimension();
|
||||
}
|
||||
sig += ")";
|
||||
return sig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified type is void.
|
||||
**/
|
||||
static boolean isVoid(Type type) {
|
||||
return type.asClassDoc() == null && type.typeName().equals("void");
|
||||
}
|
||||
}
|
||||
456
jdkSrc/jdk8/sun/rmi/runtime/Log.java
Normal file
456
jdkSrc/jdk8/sun/rmi/runtime/Log.java
Normal file
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.runtime;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.OutputStream;
|
||||
import java.rmi.server.LogStream;
|
||||
import java.util.logging.ConsoleHandler;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.SimpleFormatter;
|
||||
import java.util.logging.StreamHandler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.logging.LogManager;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.StreamHandler;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Utility which provides an abstract "logger" like RMI internal API
|
||||
* which can be directed to use one of two types of logging
|
||||
* infrastructure: the java.util.logging API or the
|
||||
* java.rmi.server.LogStream API. The default behavior is to use the
|
||||
* java.util.logging API. The LogStream API may be used instead by
|
||||
* setting the system property sun.rmi.log.useOld to true.
|
||||
*
|
||||
* For backwards compatibility, supports the RMI system logging
|
||||
* properties which pre-1.4 comprised the only way to configure RMI
|
||||
* logging. If the java.util.logging API is used and RMI system log
|
||||
* properties are set, the system properties override initial RMI
|
||||
* logger values as appropriate. If the java.util.logging API is
|
||||
* turned off, pre-1.4 logging behavior is used.
|
||||
*
|
||||
* @author Laird Dornin
|
||||
* @since 1.4
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class Log {
|
||||
|
||||
/** Logger re-definition of old RMI log values */
|
||||
public static final Level BRIEF = Level.FINE;
|
||||
public static final Level VERBOSE = Level.FINER;
|
||||
|
||||
/* selects log implementation */
|
||||
private static final LogFactory logFactory;
|
||||
static {
|
||||
boolean useOld =
|
||||
Boolean.valueOf(java.security.AccessController.
|
||||
doPrivileged(new sun.security.action.GetPropertyAction(
|
||||
"sun.rmi.log.useOld"))).booleanValue();
|
||||
|
||||
/* set factory to select the logging facility to use */
|
||||
logFactory = (useOld ? (LogFactory) new LogStreamLogFactory() :
|
||||
(LogFactory) new LoggerLogFactory());
|
||||
}
|
||||
|
||||
/** "logger like" API to be used by RMI implementation */
|
||||
public abstract boolean isLoggable(Level level);
|
||||
public abstract void log(Level level, String message);
|
||||
public abstract void log(Level level, String message, Throwable thrown);
|
||||
|
||||
/** get and set the RMI server call output stream */
|
||||
public abstract void setOutputStream(OutputStream stream);
|
||||
public abstract PrintStream getPrintStream();
|
||||
|
||||
/** factory interface enables Logger and LogStream implementations */
|
||||
private static interface LogFactory {
|
||||
Log createLog(String loggerName, String oldLogName, Level level);
|
||||
}
|
||||
|
||||
/* access log objects */
|
||||
|
||||
/**
|
||||
* Access log for a tri-state system property.
|
||||
*
|
||||
* Need to first convert override value to a log level, taking
|
||||
* care to interpret a range of values between BRIEF, VERBOSE and
|
||||
* SILENT.
|
||||
*
|
||||
* An override < 0 is interpreted to mean that the logging
|
||||
* configuration should not be overridden. The level passed to the
|
||||
* factories createLog method will be null in this case.
|
||||
*
|
||||
* Note that if oldLogName is null and old logging is on, the
|
||||
* returned LogStreamLog will ignore the override parameter - the
|
||||
* log will never log messages. This permits new logs that only
|
||||
* write to Loggers to do nothing when old logging is active.
|
||||
*
|
||||
* Do not call getLog multiple times on the same logger name.
|
||||
* Since this is an internal API, no checks are made to ensure
|
||||
* that multiple logs do not exist for the same logger.
|
||||
*/
|
||||
public static Log getLog(String loggerName, String oldLogName,
|
||||
int override)
|
||||
{
|
||||
Level level;
|
||||
|
||||
if (override < 0) {
|
||||
level = null;
|
||||
} else if (override == LogStream.SILENT) {
|
||||
level = Level.OFF;
|
||||
} else if ((override > LogStream.SILENT) &&
|
||||
(override <= LogStream.BRIEF)) {
|
||||
level = BRIEF;
|
||||
} else if ((override > LogStream.BRIEF) &&
|
||||
(override <= LogStream.VERBOSE))
|
||||
{
|
||||
level = VERBOSE;
|
||||
} else {
|
||||
level = Level.FINEST;
|
||||
}
|
||||
return logFactory.createLog(loggerName, oldLogName, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access logs associated with boolean properties
|
||||
*
|
||||
* Do not call getLog multiple times on the same logger name.
|
||||
* Since this is an internal API, no checks are made to ensure
|
||||
* that multiple logs do not exist for the same logger.
|
||||
*/
|
||||
public static Log getLog(String loggerName, String oldLogName,
|
||||
boolean override)
|
||||
{
|
||||
Level level = (override ? VERBOSE : null);
|
||||
return logFactory.createLog(loggerName, oldLogName, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory to create Log objects which deliver log messages to the
|
||||
* java.util.logging API.
|
||||
*/
|
||||
private static class LoggerLogFactory implements LogFactory {
|
||||
LoggerLogFactory() {}
|
||||
|
||||
/*
|
||||
* Accessor to obtain an arbitrary RMI logger with name
|
||||
* loggerName. If the level of the logger is greater than the
|
||||
* level for the system property with name, the logger level
|
||||
* will be set to the value of system property.
|
||||
*/
|
||||
public Log createLog(final String loggerName, String oldLogName,
|
||||
final Level level)
|
||||
{
|
||||
Logger logger = Logger.getLogger(loggerName);
|
||||
return new LoggerLog(logger, level);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class specialized to log messages to the java.util.logging API
|
||||
*/
|
||||
private static class LoggerLog extends Log {
|
||||
|
||||
/* alternate console handler for RMI loggers */
|
||||
private static final Handler alternateConsole =
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Handler>() {
|
||||
public Handler run() {
|
||||
InternalStreamHandler alternate =
|
||||
new InternalStreamHandler(System.err);
|
||||
alternate.setLevel(Level.ALL);
|
||||
return alternate;
|
||||
}
|
||||
});
|
||||
|
||||
/** handler to which messages are copied */
|
||||
private InternalStreamHandler copyHandler = null;
|
||||
|
||||
/* logger to which log messages are written */
|
||||
private final Logger logger;
|
||||
|
||||
/* used as return value of RemoteServer.getLog */
|
||||
private LoggerPrintStream loggerSandwich;
|
||||
|
||||
/** creates a Log which will delegate to the given logger */
|
||||
private LoggerLog(final Logger logger, final Level level) {
|
||||
this.logger = logger;
|
||||
|
||||
if (level != null){
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
if (!logger.isLoggable(level)) {
|
||||
logger.setLevel(level);
|
||||
}
|
||||
logger.addHandler(alternateConsole);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLoggable(Level level) {
|
||||
return logger.isLoggable(level);
|
||||
}
|
||||
|
||||
public void log(Level level, String message) {
|
||||
if (isLoggable(level)) {
|
||||
String[] source = getSource();
|
||||
logger.logp(level, source[0], source[1],
|
||||
Thread.currentThread().getName() + ": " + message);
|
||||
}
|
||||
}
|
||||
|
||||
public void log(Level level, String message, Throwable thrown) {
|
||||
if (isLoggable(level)) {
|
||||
String[] source = getSource();
|
||||
logger.logp(level, source[0], source[1],
|
||||
Thread.currentThread().getName() + ": " +
|
||||
message, thrown);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output stream associated with the RMI server call
|
||||
* logger.
|
||||
*
|
||||
* Calling code needs LoggingPermission "control".
|
||||
*/
|
||||
public synchronized void setOutputStream(OutputStream out) {
|
||||
if (out != null) {
|
||||
if (!logger.isLoggable(VERBOSE)) {
|
||||
logger.setLevel(VERBOSE);
|
||||
}
|
||||
copyHandler = new InternalStreamHandler(out);
|
||||
copyHandler.setLevel(Log.VERBOSE);
|
||||
logger.addHandler(copyHandler);
|
||||
} else {
|
||||
/* ensure that messages are not logged */
|
||||
if (copyHandler != null) {
|
||||
logger.removeHandler(copyHandler);
|
||||
}
|
||||
copyHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized PrintStream getPrintStream() {
|
||||
if (loggerSandwich == null) {
|
||||
loggerSandwich = new LoggerPrintStream(logger);
|
||||
}
|
||||
return loggerSandwich;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass of StreamHandler for redirecting log output. flush
|
||||
* must be called in the publish and close methods.
|
||||
*/
|
||||
private static class InternalStreamHandler extends StreamHandler {
|
||||
InternalStreamHandler(OutputStream out) {
|
||||
super(out, new SimpleFormatter());
|
||||
}
|
||||
|
||||
public void publish(LogRecord record) {
|
||||
super.publish(record);
|
||||
flush();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PrintStream which forwards log messages to the logger. Class
|
||||
* is needed to maintain backwards compatibility with
|
||||
* RemoteServer.{set|get}Log().
|
||||
*/
|
||||
private static class LoggerPrintStream extends PrintStream {
|
||||
|
||||
/** logger where output of this log is sent */
|
||||
private final Logger logger;
|
||||
|
||||
/** record the last character written to this stream */
|
||||
private int last = -1;
|
||||
|
||||
/** stream used for buffering lines */
|
||||
private final ByteArrayOutputStream bufOut;
|
||||
|
||||
private LoggerPrintStream(Logger logger)
|
||||
{
|
||||
super(new ByteArrayOutputStream());
|
||||
bufOut = (ByteArrayOutputStream) super.out;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void write(int b) {
|
||||
if ((last == '\r') && (b == '\n')) {
|
||||
last = -1;
|
||||
return;
|
||||
} else if ((b == '\n') || (b == '\r')) {
|
||||
try {
|
||||
/* write the converted bytes of the log message */
|
||||
String message =
|
||||
Thread.currentThread().getName() + ": " +
|
||||
bufOut.toString();
|
||||
logger.logp(Level.INFO, "LogStream", "print", message);
|
||||
} finally {
|
||||
bufOut.reset();
|
||||
}
|
||||
} else {
|
||||
super.write(b);
|
||||
}
|
||||
last = b;
|
||||
}
|
||||
|
||||
public void write(byte b[], int off, int len) {
|
||||
if (len < 0) {
|
||||
throw new ArrayIndexOutOfBoundsException(len);
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
write(b[off + i]);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "RMI";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory to create Log objects which deliver log messages to the
|
||||
* java.rmi.server.LogStream API
|
||||
*/
|
||||
private static class LogStreamLogFactory implements LogFactory {
|
||||
LogStreamLogFactory() {}
|
||||
|
||||
/* create a new LogStreamLog for the specified log */
|
||||
public Log createLog(String loggerName, String oldLogName,
|
||||
Level level)
|
||||
{
|
||||
LogStream stream = null;
|
||||
if (oldLogName != null) {
|
||||
stream = LogStream.log(oldLogName);
|
||||
}
|
||||
return new LogStreamLog(stream, level);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class specialized to log messages to the
|
||||
* java.rmi.server.LogStream API
|
||||
*/
|
||||
private static class LogStreamLog extends Log {
|
||||
/** Log stream to which log messages are written */
|
||||
private final LogStream stream;
|
||||
|
||||
/** the level of the log as set by associated property */
|
||||
private int levelValue = Level.OFF.intValue();
|
||||
|
||||
private LogStreamLog(LogStream stream, Level level) {
|
||||
if ((stream != null) && (level != null)) {
|
||||
/* if the stream or level is null, don't log any
|
||||
* messages
|
||||
*/
|
||||
levelValue = level.intValue();
|
||||
}
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public synchronized boolean isLoggable(Level level) {
|
||||
return (level.intValue() >= levelValue);
|
||||
}
|
||||
|
||||
public void log(Level messageLevel, String message) {
|
||||
if (isLoggable(messageLevel)) {
|
||||
String[] source = getSource();
|
||||
stream.println(unqualifiedName(source[0]) +
|
||||
"." + source[1] + ": " + message);
|
||||
}
|
||||
}
|
||||
|
||||
public void log(Level level, String message, Throwable thrown) {
|
||||
if (isLoggable(level)) {
|
||||
/*
|
||||
* keep output contiguous and maintain the contract of
|
||||
* RemoteServer.getLog
|
||||
*/
|
||||
synchronized (stream) {
|
||||
String[] source = getSource();
|
||||
stream.println(unqualifiedName(source[0]) + "." +
|
||||
source[1] + ": " + message);
|
||||
thrown.printStackTrace(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PrintStream getPrintStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
public synchronized void setOutputStream(OutputStream out) {
|
||||
if (out != null) {
|
||||
if (VERBOSE.intValue() < levelValue) {
|
||||
levelValue = VERBOSE.intValue();
|
||||
}
|
||||
stream.setOutputStream(out);
|
||||
} else {
|
||||
/* ensure that messages are not logged */
|
||||
levelValue = Level.OFF.intValue();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Mimic old log messages that only contain unqualified names.
|
||||
*/
|
||||
private static String unqualifiedName(String name) {
|
||||
int lastDot = name.lastIndexOf(".");
|
||||
if (lastDot >= 0) {
|
||||
name = name.substring(lastDot + 1);
|
||||
}
|
||||
name = name.replace('$', '.');
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain class and method names of code calling a log method.
|
||||
*/
|
||||
private static String[] getSource() {
|
||||
StackTraceElement[] trace = (new Exception()).getStackTrace();
|
||||
return new String[] {
|
||||
trace[3].getClassName(),
|
||||
trace[3].getMethodName()
|
||||
};
|
||||
}
|
||||
}
|
||||
138
jdkSrc/jdk8/sun/rmi/runtime/NewThreadAction.java
Normal file
138
jdkSrc/jdk8/sun/rmi/runtime/NewThreadAction.java
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.runtime;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
||||
/**
|
||||
* A PrivilegedAction for creating a new thread conveniently with an
|
||||
* AccessController.doPrivileged construct.
|
||||
*
|
||||
* All constructors allow the choice of the Runnable for the new
|
||||
* thread to execute, the name of the new thread (which will be
|
||||
* prefixed with "RMI "), and whether or not it will be a daemon
|
||||
* thread.
|
||||
*
|
||||
* The new thread may be created in the system thread group (the root
|
||||
* of the thread group tree) or an internally created non-system
|
||||
* thread group, as specified at construction of this class.
|
||||
*
|
||||
* The new thread will have the system class loader as its initial
|
||||
* context class loader (that is, its context class loader will NOT be
|
||||
* inherited from the current thread).
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
public final class NewThreadAction implements PrivilegedAction<Thread> {
|
||||
|
||||
/** cached reference to the system (root) thread group */
|
||||
static final ThreadGroup systemThreadGroup =
|
||||
AccessController.doPrivileged(new PrivilegedAction<ThreadGroup>() {
|
||||
public ThreadGroup run() {
|
||||
ThreadGroup group = Thread.currentThread().getThreadGroup();
|
||||
ThreadGroup parent;
|
||||
while ((parent = group.getParent()) != null) {
|
||||
group = parent;
|
||||
}
|
||||
return group;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* special child of the system thread group for running tasks that
|
||||
* may execute user code, so that the security policy for threads in
|
||||
* the system thread group will not apply
|
||||
*/
|
||||
static final ThreadGroup userThreadGroup =
|
||||
AccessController.doPrivileged(new PrivilegedAction<ThreadGroup>() {
|
||||
public ThreadGroup run() {
|
||||
return new ThreadGroup(systemThreadGroup, "RMI Runtime");
|
||||
}
|
||||
});
|
||||
|
||||
private final ThreadGroup group;
|
||||
private final Runnable runnable;
|
||||
private final String name;
|
||||
private final boolean daemon;
|
||||
|
||||
NewThreadAction(ThreadGroup group, Runnable runnable,
|
||||
String name, boolean daemon)
|
||||
{
|
||||
this.group = group;
|
||||
this.runnable = runnable;
|
||||
this.name = name;
|
||||
this.daemon = daemon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an action that will create a new thread in the
|
||||
* system thread group.
|
||||
*
|
||||
* @param runnable the Runnable for the new thread to execute
|
||||
*
|
||||
* @param name the name of the new thread
|
||||
*
|
||||
* @param daemon if true, new thread will be a daemon thread;
|
||||
* if false, new thread will not be a daemon thread
|
||||
*/
|
||||
public NewThreadAction(Runnable runnable, String name, boolean daemon) {
|
||||
this(systemThreadGroup, runnable, name, daemon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an action that will create a new thread.
|
||||
*
|
||||
* @param runnable the Runnable for the new thread to execute
|
||||
*
|
||||
* @param name the name of the new thread
|
||||
*
|
||||
* @param daemon if true, new thread will be a daemon thread;
|
||||
* if false, new thread will not be a daemon thread
|
||||
*
|
||||
* @param user if true, thread will be created in a non-system
|
||||
* thread group; if false, thread will be created in the system
|
||||
* thread group
|
||||
*/
|
||||
public NewThreadAction(Runnable runnable, String name, boolean daemon,
|
||||
boolean user)
|
||||
{
|
||||
this(user ? userThreadGroup : systemThreadGroup,
|
||||
runnable, name, daemon);
|
||||
}
|
||||
|
||||
public Thread run() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
}
|
||||
Thread t = new Thread(group, runnable, "RMI " + name);
|
||||
t.setContextClassLoader(ClassLoader.getSystemClassLoader());
|
||||
t.setDaemon(daemon);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
131
jdkSrc/jdk8/sun/rmi/runtime/RuntimeUtil.java
Normal file
131
jdkSrc/jdk8/sun/rmi/runtime/RuntimeUtil.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.runtime;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.Permission;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
|
||||
/**
|
||||
* RMI runtime implementation utilities.
|
||||
*
|
||||
* There is a single instance of this class, which can be obtained
|
||||
* with a GetInstanceAction. Getting the instance requires
|
||||
* RuntimePermission("sun.rmi.runtime.RuntimeUtil.getInstance")
|
||||
* because the public methods of this class expose security-sensitive
|
||||
* capabilities.
|
||||
*
|
||||
* @author Peter Jones
|
||||
**/
|
||||
public final class RuntimeUtil {
|
||||
|
||||
/** runtime package log */
|
||||
private static final Log runtimeLog =
|
||||
Log.getLog("sun.rmi.runtime", null, false);
|
||||
|
||||
/** number of scheduler threads */
|
||||
private static final int schedulerThreads = // default 1
|
||||
AccessController.doPrivileged(
|
||||
new GetIntegerAction("sun.rmi.runtime.schedulerThreads", 1));
|
||||
|
||||
/** permission required to get instance */
|
||||
private static final Permission GET_INSTANCE_PERMISSION =
|
||||
new RuntimePermission("sun.rmi.runtime.RuntimeUtil.getInstance");
|
||||
|
||||
/** the singleton instance of this class */
|
||||
private static final RuntimeUtil instance = new RuntimeUtil();
|
||||
|
||||
/** thread pool for scheduling delayed tasks */
|
||||
private final ScheduledThreadPoolExecutor scheduler;
|
||||
|
||||
private RuntimeUtil() {
|
||||
scheduler = new ScheduledThreadPoolExecutor(
|
||||
schedulerThreads,
|
||||
new ThreadFactory() {
|
||||
private final AtomicInteger count = new AtomicInteger(0);
|
||||
public Thread newThread(Runnable runnable) {
|
||||
try {
|
||||
return AccessController.doPrivileged(
|
||||
new NewThreadAction(runnable,
|
||||
"Scheduler(" + count.getAndIncrement() + ")",
|
||||
true));
|
||||
} catch (Throwable t) {
|
||||
runtimeLog.log(Level.WARNING,
|
||||
"scheduler thread factory throws", t);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
/*
|
||||
* We would like to allow the scheduler's threads to terminate
|
||||
* if possible, but a bug in DelayQueue.poll can cause code
|
||||
* like this to result in a busy loop:
|
||||
*/
|
||||
// stpe.setKeepAliveTime(10, TimeUnit.MINUTES);
|
||||
// stpe.allowCoreThreadTimeOut(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* A PrivilegedAction for getting the RuntimeUtil instance.
|
||||
**/
|
||||
public static class GetInstanceAction
|
||||
implements PrivilegedAction<RuntimeUtil>
|
||||
{
|
||||
/**
|
||||
* Creates an action that returns the RuntimeUtil instance.
|
||||
**/
|
||||
public GetInstanceAction() {
|
||||
}
|
||||
|
||||
public RuntimeUtil run() {
|
||||
return getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
private static RuntimeUtil getInstance() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(GET_INSTANCE_PERMISSION);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared thread pool for scheduling delayed tasks.
|
||||
*
|
||||
* Note that the returned pool has limited concurrency, so
|
||||
* submitted tasks should be short-lived and should not block.
|
||||
**/
|
||||
public ScheduledThreadPoolExecutor getScheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
}
|
||||
412
jdkSrc/jdk8/sun/rmi/server/ActivatableRef.java
Normal file
412
jdkSrc/jdk8/sun/rmi/server/ActivatableRef.java
Normal file
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.rmi.*;
|
||||
import java.rmi.activation.*;
|
||||
import java.rmi.server.Operation;
|
||||
import java.rmi.server.RMIClassLoader;
|
||||
import java.rmi.server.RemoteCall;
|
||||
import java.rmi.server.RemoteObject;
|
||||
import java.rmi.server.RemoteObjectInvocationHandler;
|
||||
import java.rmi.server.RemoteRef;
|
||||
import java.rmi.server.RemoteStub;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ActivatableRef implements RemoteRef {
|
||||
|
||||
private static final long serialVersionUID = 7579060052569229166L;
|
||||
|
||||
protected ActivationID id;
|
||||
protected RemoteRef ref;
|
||||
transient boolean force = false;
|
||||
|
||||
private static final int MAX_RETRIES = 3;
|
||||
private static final String versionComplaint =
|
||||
"activation requires 1.2 stubs";
|
||||
|
||||
/**
|
||||
* Create a new (empty) ActivatableRef
|
||||
*/
|
||||
public ActivatableRef()
|
||||
{}
|
||||
|
||||
/**
|
||||
* Create a ActivatableRef with the specified id
|
||||
*/
|
||||
public ActivatableRef(ActivationID id, RemoteRef ref)
|
||||
{
|
||||
this.id = id;
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stub for the remote object whose class is
|
||||
* specified in the activation descriptor. The ActivatableRef
|
||||
* in the resulting stub has its activation id set to the
|
||||
* activation id supplied as the second argument.
|
||||
*/
|
||||
public static Remote getStub(ActivationDesc desc, ActivationID id)
|
||||
throws StubNotFoundException
|
||||
{
|
||||
String className = desc.getClassName();
|
||||
|
||||
try {
|
||||
Class<?> cl =
|
||||
RMIClassLoader.loadClass(desc.getLocation(), className);
|
||||
RemoteRef clientRef = new ActivatableRef(id, null);
|
||||
return Util.createProxy(cl, clientRef, false);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new StubNotFoundException(
|
||||
"class implements an illegal remote interface", e);
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new StubNotFoundException("unable to load class: " +
|
||||
className, e);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new StubNotFoundException("malformed URL", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke method on remote object. This method delegates remote
|
||||
* method invocation to the underlying ref type. If the
|
||||
* underlying reference is not known (is null), then the object
|
||||
* must be activated first. If an attempt at method invocation
|
||||
* fails, the object should force reactivation. Method invocation
|
||||
* must preserve "at most once" call semantics. In RMI, "at most
|
||||
* once" applies to parameter deserialization at the remote site
|
||||
* and the remote object's method execution. "At most once" does
|
||||
* not apply to parameter serialization at the client so the
|
||||
* parameters of a call don't need to be buffered in anticipation
|
||||
* of call retry. Thus, a method call is only be retried if the
|
||||
* initial method invocation does not execute at all at the server
|
||||
* (including parameter deserialization).
|
||||
*/
|
||||
public Object invoke(Remote obj,
|
||||
java.lang.reflect.Method method,
|
||||
Object[] params,
|
||||
long opnum)
|
||||
throws Exception
|
||||
{
|
||||
|
||||
boolean force = false;
|
||||
RemoteRef localRef;
|
||||
Exception exception = null;
|
||||
|
||||
/*
|
||||
* Attempt object activation if active ref is unknown.
|
||||
* Throws a RemoteException if object can't be activated.
|
||||
*/
|
||||
synchronized (this) {
|
||||
if (ref == null) {
|
||||
localRef = activate(force);
|
||||
force = true;
|
||||
} else {
|
||||
localRef = ref;
|
||||
}
|
||||
}
|
||||
|
||||
for (int retries = MAX_RETRIES; retries > 0; retries--) {
|
||||
|
||||
try {
|
||||
return localRef.invoke(obj, method, params, opnum);
|
||||
} catch (NoSuchObjectException e) {
|
||||
/*
|
||||
* Object is not active in VM; retry call
|
||||
*/
|
||||
exception = e;
|
||||
} catch (ConnectException e) {
|
||||
/*
|
||||
* Failure during connection setup; retry call
|
||||
*/
|
||||
exception = e;
|
||||
} catch (UnknownHostException e) {
|
||||
/*
|
||||
* Failure during connection setup; retry call.
|
||||
*/
|
||||
exception = e;
|
||||
} catch (ConnectIOException e) {
|
||||
/*
|
||||
* Failure setting up multiplexed connection or reusing
|
||||
* cached connection; retry call
|
||||
*/
|
||||
exception = e;
|
||||
} catch (MarshalException e) {
|
||||
/*
|
||||
* Failure during parameter serialization; call may
|
||||
* have reached server, so call retry not possible.
|
||||
*/
|
||||
throw e;
|
||||
} catch (ServerError e) {
|
||||
/*
|
||||
* Call reached server; propagate remote exception.
|
||||
*/
|
||||
throw e;
|
||||
} catch (ServerException e) {
|
||||
/*
|
||||
* Call reached server; propagate remote exception
|
||||
*/
|
||||
throw e;
|
||||
} catch (RemoteException e) {
|
||||
/*
|
||||
* This is a catch-all for other RemoteExceptions.
|
||||
* UnmarshalException being the only one relevant.
|
||||
*
|
||||
* StubNotFoundException should never show up because
|
||||
* it is generally thrown when attempting to locate
|
||||
* a stub.
|
||||
*
|
||||
* UnexpectedException should never show up because
|
||||
* it is only thrown by a stub and would be wrapped
|
||||
* in a ServerException if it was propagated by a
|
||||
* remote call.
|
||||
*/
|
||||
synchronized (this) {
|
||||
if (localRef == ref) {
|
||||
ref = null; // this may be overly conservative
|
||||
}
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (retries > 1) {
|
||||
/*
|
||||
* Activate object, since object could not be reached.
|
||||
*/
|
||||
synchronized (this) {
|
||||
if (localRef.remoteEquals(ref) || ref == null) {
|
||||
RemoteRef newRef = activate(force);
|
||||
|
||||
if (newRef.remoteEquals(localRef) &&
|
||||
exception instanceof NoSuchObjectException &&
|
||||
force == false) {
|
||||
/*
|
||||
* If last exception was NoSuchObjectException,
|
||||
* then old value of ref is definitely wrong,
|
||||
* so make sure that it is different.
|
||||
*/
|
||||
newRef = activate(true);
|
||||
}
|
||||
|
||||
localRef = newRef;
|
||||
force = true;
|
||||
} else {
|
||||
localRef = ref;
|
||||
force = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Retries unsuccessful, so throw last exception
|
||||
*/
|
||||
throw exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* private method to obtain the ref for a call.
|
||||
*/
|
||||
private synchronized RemoteRef getRef()
|
||||
throws RemoteException
|
||||
{
|
||||
if (ref == null) {
|
||||
ref = activate(false);
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* private method to activate the remote object.
|
||||
*
|
||||
* NOTE: the caller must be synchronized on "this" before
|
||||
* calling this method.
|
||||
*/
|
||||
private RemoteRef activate(boolean force)
|
||||
throws RemoteException
|
||||
{
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
ref = null;
|
||||
try {
|
||||
/*
|
||||
* Activate the object and retrieve the remote reference
|
||||
* from inside the stub returned as the result. Then
|
||||
* set this activatable ref's internal ref to be the
|
||||
* ref inside the ref of the stub. In more clear terms,
|
||||
* the stub returned from the activate call contains an
|
||||
* ActivatableRef. We need to set the ref in *this*
|
||||
* ActivatableRef to the ref inside the ActivatableRef
|
||||
* retrieved from the stub. The ref type embedded in the
|
||||
* ActivatableRef is typically a UnicastRef.
|
||||
*/
|
||||
|
||||
Remote proxy = id.activate(force);
|
||||
ActivatableRef newRef = null;
|
||||
|
||||
if (proxy instanceof RemoteStub) {
|
||||
newRef = (ActivatableRef) ((RemoteStub) proxy).getRef();
|
||||
} else {
|
||||
/*
|
||||
* Assume that proxy is an instance of a dynamic proxy
|
||||
* class. If that assumption is not correct, or either of
|
||||
* the casts below fails, the resulting exception will be
|
||||
* wrapped in an ActivateFailedException below.
|
||||
*/
|
||||
RemoteObjectInvocationHandler handler =
|
||||
(RemoteObjectInvocationHandler)
|
||||
Proxy.getInvocationHandler(proxy);
|
||||
newRef = (ActivatableRef) handler.getRef();
|
||||
}
|
||||
ref = newRef.ref;
|
||||
return ref;
|
||||
|
||||
} catch (ConnectException e) {
|
||||
throw new ConnectException("activation failed", e);
|
||||
} catch (RemoteException e) {
|
||||
throw new ConnectIOException("activation failed", e);
|
||||
} catch (UnknownObjectException e) {
|
||||
throw new NoSuchObjectException("object not registered");
|
||||
} catch (ActivationException e) {
|
||||
throw new ActivateFailedException("activation failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This call is used by the old 1.1 stub protocol and is
|
||||
* unsupported since activation requires 1.2 stubs.
|
||||
*/
|
||||
public synchronized RemoteCall newCall(RemoteObject obj,
|
||||
Operation[] ops,
|
||||
int opnum,
|
||||
long hash)
|
||||
throws RemoteException
|
||||
{
|
||||
throw new UnsupportedOperationException(versionComplaint);
|
||||
}
|
||||
|
||||
/**
|
||||
* This call is used by the old 1.1 stub protocol and is
|
||||
* unsupported since activation requires 1.2 stubs.
|
||||
*/
|
||||
public void invoke(RemoteCall call) throws Exception
|
||||
{
|
||||
throw new UnsupportedOperationException(versionComplaint);
|
||||
}
|
||||
|
||||
/**
|
||||
* This call is used by the old 1.1 stub protocol and is
|
||||
* unsupported since activation requires 1.2 stubs.
|
||||
*/
|
||||
public void done(RemoteCall call) throws RemoteException {
|
||||
throw new UnsupportedOperationException(versionComplaint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of the ref type to be serialized
|
||||
*/
|
||||
public String getRefClass(ObjectOutput out)
|
||||
{
|
||||
return "ActivatableRef";
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out external representation for remote ref.
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out) throws IOException
|
||||
{
|
||||
RemoteRef localRef = ref;
|
||||
|
||||
out.writeObject(id);
|
||||
if (localRef == null) {
|
||||
out.writeUTF("");
|
||||
} else {
|
||||
out.writeUTF(localRef.getRefClass(out));
|
||||
localRef.writeExternal(out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in external representation for remote ref.
|
||||
* @exception ClassNotFoundException If the class for an object
|
||||
* being restored cannot be found.
|
||||
*/
|
||||
public void readExternal(ObjectInput in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
id = (ActivationID)in.readObject();
|
||||
ref = null;
|
||||
String className = in.readUTF();
|
||||
|
||||
if (className.equals("")) return;
|
||||
|
||||
try {
|
||||
Class<?> refClass = Class.forName(RemoteRef.packagePrefix + "." +
|
||||
className);
|
||||
ref = (RemoteRef)refClass.newInstance();
|
||||
ref.readExternal(in);
|
||||
} catch (InstantiationException e) {
|
||||
throw new UnmarshalException("Unable to create remote reference",
|
||||
e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new UnmarshalException("Illegal access creating remote reference");
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------;
|
||||
/**
|
||||
* Method from object, forward from RemoteObject
|
||||
*/
|
||||
public String remoteToString() {
|
||||
return Util.getUnqualifiedName(getClass()) +
|
||||
" [remoteRef: " + ref + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* default implementation of hashCode for remote objects
|
||||
*/
|
||||
public int remoteHashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
/** default implementation of equals for remote objects
|
||||
*/
|
||||
public boolean remoteEquals(RemoteRef ref) {
|
||||
if (ref instanceof ActivatableRef)
|
||||
return id.equals(((ActivatableRef)ref).id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
93
jdkSrc/jdk8/sun/rmi/server/ActivatableServerRef.java
Normal file
93
jdkSrc/jdk8/sun/rmi/server/ActivatableServerRef.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectOutput;
|
||||
import java.rmi.*;
|
||||
import java.rmi.server.*;
|
||||
import java.rmi.activation.ActivationID;
|
||||
import sun.rmi.transport.LiveRef;
|
||||
|
||||
/**
|
||||
* Server-side ref for a persistent remote impl.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
*/
|
||||
public class ActivatableServerRef extends UnicastServerRef2 {
|
||||
|
||||
private static final long serialVersionUID = 2002967993223003793L;
|
||||
|
||||
private ActivationID id;
|
||||
|
||||
/**
|
||||
* Construct a Unicast server remote reference to be exported
|
||||
* on the specified port.
|
||||
*/
|
||||
public ActivatableServerRef(ActivationID id, int port)
|
||||
{
|
||||
this(id, port, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Unicast server remote reference to be exported
|
||||
* on the specified port.
|
||||
*/
|
||||
public ActivatableServerRef(ActivationID id, int port,
|
||||
RMIClientSocketFactory csf,
|
||||
RMIServerSocketFactory ssf)
|
||||
{
|
||||
super(new LiveRef(port, csf, ssf));
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of the ref type to be serialized
|
||||
*/
|
||||
public String getRefClass(ObjectOutput out)
|
||||
{
|
||||
return "ActivatableServerRef";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client remote reference for this remoteRef.
|
||||
* In the case of a client RemoteRef "this" is the answer.
|
||||
* For a server remote reference, a client side one will have to
|
||||
* found or created.
|
||||
*/
|
||||
protected RemoteRef getClientRef() {
|
||||
return new ActivatableRef(id, new UnicastRef2(ref));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents serialization (because deserializaion is impossible).
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
throw new NotSerializableException(
|
||||
"ActivatableServerRef not serializable");
|
||||
}
|
||||
}
|
||||
2559
jdkSrc/jdk8/sun/rmi/server/Activation.java
Normal file
2559
jdkSrc/jdk8/sun/rmi/server/Activation.java
Normal file
File diff suppressed because it is too large
Load Diff
500
jdkSrc/jdk8/sun/rmi/server/ActivationGroupImpl.java
Normal file
500
jdkSrc/jdk8/sun/rmi/server/ActivationGroupImpl.java
Normal file
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.ServerSocket;
|
||||
import java.rmi.MarshalledObject;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.activation.Activatable;
|
||||
import java.rmi.activation.ActivationDesc;
|
||||
import java.rmi.activation.ActivationException;
|
||||
import java.rmi.activation.ActivationGroup;
|
||||
import java.rmi.activation.ActivationGroupID;
|
||||
import java.rmi.activation.ActivationID;
|
||||
import java.rmi.activation.UnknownObjectException;
|
||||
import java.rmi.server.RMIClassLoader;
|
||||
import java.rmi.server.RMIServerSocketFactory;
|
||||
import java.rmi.server.RMISocketFactory;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import sun.rmi.registry.RegistryImpl;
|
||||
|
||||
/**
|
||||
* The default activation group implementation.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
* @since 1.2
|
||||
* @see java.rmi.activation.ActivationGroup
|
||||
*/
|
||||
public class ActivationGroupImpl extends ActivationGroup {
|
||||
|
||||
// use serialVersionUID from JDK 1.2.2 for interoperability
|
||||
private static final long serialVersionUID = 5758693559430427303L;
|
||||
|
||||
/** maps persistent IDs to activated remote objects */
|
||||
private final Hashtable<ActivationID,ActiveEntry> active =
|
||||
new Hashtable<>();
|
||||
private boolean groupInactive = false;
|
||||
private final ActivationGroupID groupID;
|
||||
private final List<ActivationID> lockedIDs = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a default activation group implementation.
|
||||
*
|
||||
* @param id the group's identifier
|
||||
* @param data ignored
|
||||
*/
|
||||
public ActivationGroupImpl(ActivationGroupID id, MarshalledObject<?> data)
|
||||
throws RemoteException
|
||||
{
|
||||
super(id);
|
||||
groupID = id;
|
||||
|
||||
/*
|
||||
* Unexport activation group impl and attempt to export it on
|
||||
* an unshared anonymous port. See 4692286.
|
||||
*/
|
||||
unexportObject(this, true);
|
||||
RMIServerSocketFactory ssf = new ServerSocketFactoryImpl();
|
||||
UnicastRemoteObject.exportObject(this, 0, null, ssf);
|
||||
|
||||
if (System.getSecurityManager() == null) {
|
||||
try {
|
||||
// Provide a default security manager.
|
||||
System.setSecurityManager(new SecurityManager());
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RemoteException("unable to set security manager", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trivial server socket factory used to export the activation group
|
||||
* impl on an unshared port.
|
||||
*/
|
||||
private static class ServerSocketFactoryImpl
|
||||
implements RMIServerSocketFactory
|
||||
{
|
||||
public ServerSocket createServerSocket(int port) throws IOException
|
||||
{
|
||||
RMISocketFactory sf = RMISocketFactory.getSocketFactory();
|
||||
if (sf == null) {
|
||||
sf = RMISocketFactory.getDefaultSocketFactory();
|
||||
}
|
||||
return sf.createServerSocket(port);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtains a lock on the ActivationID id before returning. Allows only one
|
||||
* thread at a time to hold a lock on a particular id. If the lock for id
|
||||
* is in use, all requests for an equivalent (in the Object.equals sense)
|
||||
* id will wait for the id to be notified and use the supplied id as the
|
||||
* next lock. The caller of "acquireLock" must execute the "releaseLock"
|
||||
* method" to release the lock and "notifyAll" waiters for the id lock
|
||||
* obtained from this method. The typical usage pattern is as follows:
|
||||
*
|
||||
* try {
|
||||
* acquireLock(id);
|
||||
* // do stuff pertaining to id...
|
||||
* } finally {
|
||||
* releaseLock(id);
|
||||
* checkInactiveGroup();
|
||||
* }
|
||||
*/
|
||||
private void acquireLock(ActivationID id) {
|
||||
|
||||
ActivationID waitForID;
|
||||
|
||||
for (;;) {
|
||||
|
||||
synchronized (lockedIDs) {
|
||||
int index = lockedIDs.indexOf(id);
|
||||
if (index < 0) {
|
||||
lockedIDs.add(id);
|
||||
return;
|
||||
} else {
|
||||
waitForID = lockedIDs.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (waitForID) {
|
||||
synchronized (lockedIDs) {
|
||||
int index = lockedIDs.indexOf(waitForID);
|
||||
if (index < 0) continue;
|
||||
ActivationID actualID = lockedIDs.get(index);
|
||||
if (actualID != waitForID)
|
||||
/*
|
||||
* don't wait on an id that won't be notified.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
waitForID.wait();
|
||||
} catch (InterruptedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Releases the id lock obtained via the "acquireLock" method and then
|
||||
* notifies all threads waiting on the lock.
|
||||
*/
|
||||
private void releaseLock(ActivationID id) {
|
||||
synchronized (lockedIDs) {
|
||||
id = lockedIDs.remove(lockedIDs.indexOf(id));
|
||||
}
|
||||
|
||||
synchronized (id) {
|
||||
id.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of an activatable remote object. The
|
||||
* <code>Activator</code> calls this method to create an activatable
|
||||
* object in this group. This method should be idempotent; a call to
|
||||
* activate an already active object should return the previously
|
||||
* activated object.
|
||||
*
|
||||
* Note: this method assumes that the Activator will only invoke
|
||||
* newInstance for the same object in a serial fashion (i.e.,
|
||||
* the activator will not allow the group to see concurrent requests
|
||||
* to activate the same object.
|
||||
*
|
||||
* @param id the object's activation identifier
|
||||
* @param desc the object's activation descriptor
|
||||
* @return a marshalled object containing the activated object's stub
|
||||
*/
|
||||
public MarshalledObject<? extends Remote>
|
||||
newInstance(final ActivationID id,
|
||||
final ActivationDesc desc)
|
||||
throws ActivationException, RemoteException
|
||||
{
|
||||
RegistryImpl.checkAccess("ActivationInstantiator.newInstance");
|
||||
|
||||
if (!groupID.equals(desc.getGroupID()))
|
||||
throw new ActivationException("newInstance in wrong group");
|
||||
|
||||
try {
|
||||
acquireLock(id);
|
||||
synchronized (this) {
|
||||
if (groupInactive == true)
|
||||
throw new InactiveGroupException("group is inactive");
|
||||
}
|
||||
|
||||
ActiveEntry entry = active.get(id);
|
||||
if (entry != null)
|
||||
return entry.mobj;
|
||||
|
||||
String className = desc.getClassName();
|
||||
|
||||
final Class<? extends Remote> cl =
|
||||
RMIClassLoader.loadClass(desc.getLocation(), className)
|
||||
.asSubclass(Remote.class);
|
||||
Remote impl = null;
|
||||
|
||||
final Thread t = Thread.currentThread();
|
||||
final ClassLoader savedCcl = t.getContextClassLoader();
|
||||
ClassLoader objcl = cl.getClassLoader();
|
||||
final ClassLoader ccl = covers(objcl, savedCcl) ? objcl : savedCcl;
|
||||
|
||||
/*
|
||||
* Fix for 4164971: allow non-public activatable class
|
||||
* and/or constructor, create the activatable object in a
|
||||
* privileged block
|
||||
*/
|
||||
try {
|
||||
/*
|
||||
* The code below is in a doPrivileged block to
|
||||
* protect against user code which code might have set
|
||||
* a global socket factory (in which case application
|
||||
* code would be on the stack).
|
||||
*/
|
||||
impl = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<Remote>() {
|
||||
public Remote run() throws InstantiationException,
|
||||
NoSuchMethodException, IllegalAccessException,
|
||||
InvocationTargetException
|
||||
{
|
||||
Constructor<? extends Remote> constructor =
|
||||
cl.getDeclaredConstructor(
|
||||
ActivationID.class, MarshalledObject.class);
|
||||
constructor.setAccessible(true);
|
||||
try {
|
||||
/*
|
||||
* Fix for 4289544: make sure to set the
|
||||
* context class loader to be the class
|
||||
* loader of the impl class before
|
||||
* constructing that class.
|
||||
*/
|
||||
t.setContextClassLoader(ccl);
|
||||
return constructor.newInstance(id,
|
||||
desc.getData());
|
||||
} finally {
|
||||
t.setContextClassLoader(savedCcl);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (PrivilegedActionException pae) {
|
||||
Throwable e = pae.getException();
|
||||
|
||||
// narrow the exception's type and rethrow it
|
||||
if (e instanceof InstantiationException) {
|
||||
throw (InstantiationException) e;
|
||||
} else if (e instanceof NoSuchMethodException) {
|
||||
throw (NoSuchMethodException) e;
|
||||
} else if (e instanceof IllegalAccessException) {
|
||||
throw (IllegalAccessException) e;
|
||||
} else if (e instanceof InvocationTargetException) {
|
||||
throw (InvocationTargetException) e;
|
||||
} else if (e instanceof RuntimeException) {
|
||||
throw (RuntimeException) e;
|
||||
} else if (e instanceof Error) {
|
||||
throw (Error) e;
|
||||
}
|
||||
}
|
||||
|
||||
entry = new ActiveEntry(impl);
|
||||
active.put(id, entry);
|
||||
return entry.mobj;
|
||||
|
||||
} catch (NoSuchMethodException | NoSuchMethodError e) {
|
||||
/* user forgot to provide activatable constructor?
|
||||
* or code recompiled and user forgot to provide
|
||||
* activatable constructor?
|
||||
*/
|
||||
throw new ActivationException
|
||||
("Activatable object must provide an activation"+
|
||||
" constructor", e );
|
||||
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ActivationException("exception in object constructor",
|
||||
e.getTargetException());
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new ActivationException("unable to activate object", e);
|
||||
} finally {
|
||||
releaseLock(id);
|
||||
checkInactiveGroup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The group's <code>inactiveObject</code> method is called
|
||||
* indirectly via a call to the <code>Activatable.inactive</code>
|
||||
* method. A remote object implementation must call
|
||||
* <code>Activatable</code>'s <code>inactive</code> method when
|
||||
* that object deactivates (the object deems that it is no longer
|
||||
* active). If the object does not call
|
||||
* <code>Activatable.inactive</code> when it deactivates, the
|
||||
* object will never be garbage collected since the group keeps
|
||||
* strong references to the objects it creates. <p>
|
||||
*
|
||||
* The group's <code>inactiveObject</code> method
|
||||
* unexports the remote object from the RMI runtime so that the
|
||||
* object can no longer receive incoming RMI calls. This call will
|
||||
* only succeed if the object has no pending/executing calls. If
|
||||
* the object does have pending/executing RMI calls, then false
|
||||
* will be returned.
|
||||
*
|
||||
* If the object has no pending/executing calls, the object is
|
||||
* removed from the RMI runtime and the group informs its
|
||||
* <code>ActivationMonitor</code> (via the monitor's
|
||||
* <code>inactiveObject</code> method) that the remote object is
|
||||
* not currently active so that the remote object will be
|
||||
* re-activated by the activator upon a subsequent activation
|
||||
* request.
|
||||
*
|
||||
* @param id the object's activation identifier
|
||||
* @returns true if the operation succeeds (the operation will
|
||||
* succeed if the object in currently known to be active and is
|
||||
* either already unexported or is currently exported and has no
|
||||
* pending/executing calls); false is returned if the object has
|
||||
* pending/executing calls in which case it cannot be deactivated
|
||||
* @exception UnknownObjectException if object is unknown (may already
|
||||
* be inactive)
|
||||
* @exception RemoteException if call informing monitor fails
|
||||
*/
|
||||
public boolean inactiveObject(ActivationID id)
|
||||
throws ActivationException, UnknownObjectException, RemoteException
|
||||
{
|
||||
|
||||
try {
|
||||
acquireLock(id);
|
||||
synchronized (this) {
|
||||
if (groupInactive == true)
|
||||
throw new ActivationException("group is inactive");
|
||||
}
|
||||
|
||||
ActiveEntry entry = active.get(id);
|
||||
if (entry == null) {
|
||||
// REMIND: should this be silent?
|
||||
throw new UnknownObjectException("object not active");
|
||||
}
|
||||
|
||||
try {
|
||||
if (Activatable.unexportObject(entry.impl, false) == false)
|
||||
return false;
|
||||
} catch (NoSuchObjectException allowUnexportedObjects) {
|
||||
}
|
||||
|
||||
try {
|
||||
super.inactiveObject(id);
|
||||
} catch (UnknownObjectException allowUnregisteredObjects) {
|
||||
}
|
||||
|
||||
active.remove(id);
|
||||
|
||||
} finally {
|
||||
releaseLock(id);
|
||||
checkInactiveGroup();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines if the group has become inactive and
|
||||
* marks it as such.
|
||||
*/
|
||||
private void checkInactiveGroup() {
|
||||
boolean groupMarkedInactive = false;
|
||||
synchronized (this) {
|
||||
if (active.size() == 0 && lockedIDs.size() == 0 &&
|
||||
groupInactive == false)
|
||||
{
|
||||
groupInactive = true;
|
||||
groupMarkedInactive = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (groupMarkedInactive) {
|
||||
try {
|
||||
super.inactiveGroup();
|
||||
} catch (Exception ignoreDeactivateFailure) {
|
||||
}
|
||||
|
||||
try {
|
||||
UnicastRemoteObject.unexportObject(this, true);
|
||||
} catch (NoSuchObjectException allowUnexportedGroup) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The group's <code>activeObject</code> method is called when an
|
||||
* object is exported (either by <code>Activatable</code> object
|
||||
* construction or an explicit call to
|
||||
* <code>Activatable.exportObject</code>. The group must inform its
|
||||
* <code>ActivationMonitor</code> that the object is active (via
|
||||
* the monitor's <code>activeObject</code> method) if the group
|
||||
* hasn't already done so.
|
||||
*
|
||||
* @param id the object's identifier
|
||||
* @param obj the remote object implementation
|
||||
* @exception UnknownObjectException if object is not registered
|
||||
* @exception RemoteException if call informing monitor fails
|
||||
*/
|
||||
public void activeObject(ActivationID id, Remote impl)
|
||||
throws ActivationException, UnknownObjectException, RemoteException
|
||||
{
|
||||
|
||||
try {
|
||||
acquireLock(id);
|
||||
synchronized (this) {
|
||||
if (groupInactive == true)
|
||||
throw new ActivationException("group is inactive");
|
||||
}
|
||||
if (!active.contains(id)) {
|
||||
ActiveEntry entry = new ActiveEntry(impl);
|
||||
active.put(id, entry);
|
||||
// created new entry, so inform monitor of active object
|
||||
try {
|
||||
super.activeObject(id, entry.mobj);
|
||||
} catch (RemoteException e) {
|
||||
// daemon can still find it by calling newInstance
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
releaseLock(id);
|
||||
checkInactiveGroup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry in table for active object.
|
||||
*/
|
||||
private static class ActiveEntry {
|
||||
Remote impl;
|
||||
MarshalledObject<Remote> mobj;
|
||||
|
||||
ActiveEntry(Remote impl) throws ActivationException {
|
||||
this.impl = impl;
|
||||
try {
|
||||
this.mobj = new MarshalledObject<Remote>(impl);
|
||||
} catch (IOException e) {
|
||||
throw new
|
||||
ActivationException("failed to marshal remote object", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the first argument is either equal to, or is a
|
||||
* descendant of, the second argument. Null is treated as the root of
|
||||
* the tree.
|
||||
*/
|
||||
private static boolean covers(ClassLoader sub, ClassLoader sup) {
|
||||
if (sup == null) {
|
||||
return true;
|
||||
} else if (sub == null) {
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
if (sub == sup) {
|
||||
return true;
|
||||
}
|
||||
sub = sub.getParent();
|
||||
} while (sub != null);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
85
jdkSrc/jdk8/sun/rmi/server/ActivationGroupInit.java
Normal file
85
jdkSrc/jdk8/sun/rmi/server/ActivationGroupInit.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.rmi.activation.ActivationGroupDesc;
|
||||
import java.rmi.activation.ActivationGroupID;
|
||||
import java.rmi.activation.ActivationGroup;
|
||||
|
||||
/**
|
||||
* This is the bootstrap code to start a VM executing an activation
|
||||
* group.
|
||||
*
|
||||
* The activator spawns (as a child process) an activation group as needed
|
||||
* and directs activation requests to the appropriate activation
|
||||
* group. After spawning the VM, the activator passes some
|
||||
* information to the bootstrap code via its stdin: <p>
|
||||
* <ul>
|
||||
* <li> the activation group's id,
|
||||
* <li> the activation group's descriptor (an instance of the class
|
||||
* java.rmi.activation.ActivationGroupDesc) for the group, adn
|
||||
* <li> the group's incarnation number.
|
||||
* </ul><p>
|
||||
*
|
||||
* When the bootstrap VM starts executing, it reads group id and
|
||||
* descriptor from its stdin so that it can create the activation
|
||||
* group for the VM.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
*/
|
||||
public abstract class ActivationGroupInit
|
||||
{
|
||||
/**
|
||||
* Main program to start a VM for an activation group.
|
||||
*/
|
||||
public static void main(String args[])
|
||||
{
|
||||
try {
|
||||
if (System.getSecurityManager() == null) {
|
||||
System.setSecurityManager(new SecurityManager());
|
||||
}
|
||||
// read group id, descriptor, and incarnation number from stdin
|
||||
MarshalInputStream in = new MarshalInputStream(System.in);
|
||||
ActivationGroupID id = (ActivationGroupID)in.readObject();
|
||||
ActivationGroupDesc desc = (ActivationGroupDesc)in.readObject();
|
||||
long incarnation = in.readLong();
|
||||
|
||||
// create and set group for the VM
|
||||
ActivationGroup.createGroup(id, desc, incarnation);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Exception in starting ActivationGroupInit:");
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
System.in.close();
|
||||
// note: system out/err shouldn't be closed
|
||||
// since the parent may want to read them.
|
||||
} catch (Exception ex) {
|
||||
// ignore exceptions
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
93
jdkSrc/jdk8/sun/rmi/server/DeserializationChecker.java
Normal file
93
jdkSrc/jdk8/sun/rmi/server/DeserializationChecker.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Implementing this interface to have a deserialization control when RMI
|
||||
* dispatches a remote request. If an exported object implements this interface,
|
||||
* RMI dispatching mechanism will call the method {@code check} every time
|
||||
* deserialising a remote object for invoking a method of the exported object.
|
||||
*
|
||||
* @author sjiang
|
||||
*/
|
||||
public interface DeserializationChecker {
|
||||
/**
|
||||
* Will be called to check a descriptor.
|
||||
* This method may be called 2 times, the first time is when a descriptor is read
|
||||
* from the stream, the second is just before creating an object described
|
||||
* by this descriptor.
|
||||
*
|
||||
* @param method the method invoked from a remote request.
|
||||
* @param descriptor The descriptor of the class of any object deserialised
|
||||
* while deserialising the parameter. The first descriptor will be that of
|
||||
* the top level object (the concrete class of the parameter itself);
|
||||
* Subsequent calls with the same {@code method}, {@code paramIndex} and
|
||||
* {@code callID} will correspond to objects contained in the parameter.
|
||||
* @param paramIndex an index indicates the position of a parameter in the
|
||||
* method. This index will be reused for deserialising all
|
||||
* objects contained in the parameter object. For example, the parameter
|
||||
* being deserialised is a {@code List}, all deserialisation calls for its
|
||||
* elements will have same index.
|
||||
* @param callID a unique ID identifying one
|
||||
* time method invocation, the same ID is used for deserialization call of
|
||||
* all parameters within the method.
|
||||
*/
|
||||
public void check(Method method,
|
||||
ObjectStreamClass descriptor,
|
||||
int paramIndex,
|
||||
int callID);
|
||||
|
||||
/**
|
||||
* Will be called to validate a Proxy interfaces from a remote user before loading it.
|
||||
* @param method the method invoked from a remote request.
|
||||
* @param ifaces a string table of all interfaces implemented by the proxy to be checked.
|
||||
* @param paramIndex an index indicates the position of a parameter in the
|
||||
* method. This index will be reused for deserialising all
|
||||
* objects contained in the parameter object. For example, the parameter
|
||||
* being deserialised is a {@code List}, all deserialisation calls for its
|
||||
* elements will have same index.
|
||||
* @param callID a unique ID identifying one
|
||||
* time method invocation, the same ID is used for deserialization call of
|
||||
* all parameters within the method.
|
||||
*/
|
||||
public void checkProxyClass(Method method,
|
||||
String[] ifaces,
|
||||
int paramIndex,
|
||||
int callID);
|
||||
|
||||
/**
|
||||
* Inform of the completion of parameter deserialisation for a method invocation.
|
||||
* This is useful if the last parameter is a complex object, like a {@code List}
|
||||
* which elements are complex object too.
|
||||
*
|
||||
* The default implementation does nothing.
|
||||
* @param callID the ID identifying a method invocation.
|
||||
*/
|
||||
public default void end(int callID) {}
|
||||
}
|
||||
50
jdkSrc/jdk8/sun/rmi/server/Dispatcher.java
Normal file
50
jdkSrc/jdk8/sun/rmi/server/Dispatcher.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.server.RemoteCall;
|
||||
|
||||
/**
|
||||
* The Dispatcher interface allows the transport to make
|
||||
* the upcall to the server side remote reference.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public interface Dispatcher {
|
||||
|
||||
/**
|
||||
* Call to dispatch to the remote object (on the server side).
|
||||
* The up-call to the server and the marshaling of return result
|
||||
* (or exception) should be handled before returning from this
|
||||
* method.
|
||||
* @param obj the target remote object for the call
|
||||
* @param call the "remote call" from which operation and
|
||||
* method arguments can be obtained.
|
||||
* @exception RemoteException unable to marshal
|
||||
* return result
|
||||
*/
|
||||
void dispatch(Remote obj, RemoteCall call)
|
||||
throws java.io.IOException;
|
||||
}
|
||||
50
jdkSrc/jdk8/sun/rmi/server/InactiveGroupException.java
Normal file
50
jdkSrc/jdk8/sun/rmi/server/InactiveGroupException.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.rmi.activation.ActivationException;
|
||||
|
||||
/**
|
||||
* Thrown if a local or remote call is made on a group implementation
|
||||
* instance that is inactive.
|
||||
*
|
||||
* @author Sun Microsystems, Inc.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public class InactiveGroupException extends ActivationException {
|
||||
|
||||
private static final long serialVersionUID = -7491041778450214975L;
|
||||
|
||||
/**
|
||||
* Constructs an instance with the specified detail message.
|
||||
*
|
||||
* @param s the detail message
|
||||
*/
|
||||
public InactiveGroupException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
1224
jdkSrc/jdk8/sun/rmi/server/LoaderHandler.java
Normal file
1224
jdkSrc/jdk8/sun/rmi/server/LoaderHandler.java
Normal file
File diff suppressed because it is too large
Load Diff
357
jdkSrc/jdk8/sun/rmi/server/MarshalInputStream.java
Normal file
357
jdkSrc/jdk8/sun/rmi/server/MarshalInputStream.java
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.io.StreamCorruptedException;
|
||||
import java.util.*;
|
||||
import java.security.AccessControlException;
|
||||
import java.security.Permission;
|
||||
import java.rmi.server.RMIClassLoader;
|
||||
import sun.misc.ObjectStreamClassValidator;
|
||||
import sun.misc.SharedSecrets;
|
||||
|
||||
/**
|
||||
* MarshalInputStream is an extension of ObjectInputStream. When resolving
|
||||
* a class, it reads an object from the stream written by a corresponding
|
||||
* MarshalOutputStream. If the class to be resolved is not available
|
||||
* locally, from the first class loader on the execution stack, or from the
|
||||
* context class loader of the current thread, it will attempt to load the
|
||||
* class from the location annotated by the sending MarshalOutputStream.
|
||||
* This location object must be a string representing a path of URLs.
|
||||
*
|
||||
* A new MarshalInputStream should be created to deserialize remote objects or
|
||||
* graphs containing remote objects. Objects are created from the stream
|
||||
* using the ObjectInputStream.readObject method.
|
||||
*
|
||||
* @author Peter Jones
|
||||
*/
|
||||
public class MarshalInputStream extends ObjectInputStream {
|
||||
interface StreamChecker extends ObjectStreamClassValidator {
|
||||
void checkProxyInterfaceNames(String[] ifaces);
|
||||
}
|
||||
|
||||
private volatile StreamChecker streamChecker = null;
|
||||
|
||||
/**
|
||||
* Value of "java.rmi.server.useCodebaseOnly" property,
|
||||
* as cached at class initialization time.
|
||||
*
|
||||
* The default value is true. That is, the value is true
|
||||
* if the property is absent or is not equal to "false".
|
||||
* The value is only false when the property is present
|
||||
* and is equal to "false".
|
||||
*/
|
||||
private static final boolean useCodebaseOnlyProperty =
|
||||
! java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction(
|
||||
"java.rmi.server.useCodebaseOnly", "true"))
|
||||
.equalsIgnoreCase("false");
|
||||
|
||||
/** table to hold sun classes to which access is explicitly permitted */
|
||||
protected static Map<String, Class<?>> permittedSunClasses
|
||||
= new HashMap<>(3);
|
||||
|
||||
/** if true, don't try superclass first in resolveClass() */
|
||||
private boolean skipDefaultResolveClass = false;
|
||||
|
||||
/** callbacks to make when done() called: maps Object to Runnable */
|
||||
private final Map<Object, Runnable> doneCallbacks
|
||||
= new HashMap<>(3);
|
||||
|
||||
/**
|
||||
* if true, load classes (if not available locally) only from the
|
||||
* URL specified by the "java.rmi.server.codebase" property.
|
||||
*/
|
||||
private boolean useCodebaseOnly = useCodebaseOnlyProperty;
|
||||
|
||||
/*
|
||||
* Fix for 4179055: The remote object services inside the
|
||||
* activation daemon use stubs that are in the package
|
||||
* sun.rmi.server. Classes for these stubs should be loaded from
|
||||
* the classpath by RMI system code and not by the normal
|
||||
* unmarshalling process as applications should not need to have
|
||||
* permission to access the sun implementation classes.
|
||||
*
|
||||
* Note: this fix should be redone when API changes may be
|
||||
* integrated
|
||||
*
|
||||
* During parameter unmarshalling RMI needs to explicitly permit
|
||||
* access to three sun.* stub classes
|
||||
*/
|
||||
static {
|
||||
try {
|
||||
String system =
|
||||
"sun.rmi.server.Activation$ActivationSystemImpl_Stub";
|
||||
String registry = "sun.rmi.registry.RegistryImpl_Stub";
|
||||
|
||||
permittedSunClasses.put(system, Class.forName(system));
|
||||
permittedSunClasses.put(registry, Class.forName(registry));
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new NoClassDefFoundError("Missing system class: " +
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MarshalInputStream object.
|
||||
*/
|
||||
public MarshalInputStream(InputStream in)
|
||||
throws IOException, StreamCorruptedException
|
||||
{
|
||||
super(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a callback previously registered via the setDoneCallback
|
||||
* method with given key, or null if no callback has yet been registered
|
||||
* with that key.
|
||||
*/
|
||||
public Runnable getDoneCallback(Object key) {
|
||||
return doneCallbacks.get(key); // not thread-safe
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback to make when this stream's done() method is
|
||||
* invoked, along with a key for retrieving the same callback instance
|
||||
* subsequently from the getDoneCallback method.
|
||||
*/
|
||||
public void setDoneCallback(Object key, Runnable callback) {
|
||||
//assert(!doneCallbacks.contains(key));
|
||||
doneCallbacks.put(key, callback); // not thread-safe
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the user of this MarshalInputStream is done reading
|
||||
* objects from it, so all callbacks registered with the setDoneCallback
|
||||
* method should now be (synchronously) executed. When this method
|
||||
* returns, there are no more callbacks registered.
|
||||
*
|
||||
* This method is implicitly invoked by close() before it delegates to
|
||||
* the superclass's close method.
|
||||
*/
|
||||
public void done() {
|
||||
Iterator<Runnable> iter = doneCallbacks.values().iterator();
|
||||
while (iter.hasNext()) { // not thread-safe
|
||||
Runnable callback = iter.next();
|
||||
callback.run();
|
||||
}
|
||||
doneCallbacks.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this stream, implicitly invoking done() first.
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
done();
|
||||
super.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* resolveClass is extended to acquire (if present) the location
|
||||
* from which to load the specified class.
|
||||
* It will find, load, and return the class.
|
||||
*/
|
||||
protected Class<?> resolveClass(ObjectStreamClass classDesc)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
/*
|
||||
* Always read annotation written by MarshalOutputStream
|
||||
* describing where to load class from.
|
||||
*/
|
||||
Object annotation = readLocation();
|
||||
|
||||
String className = classDesc.getName();
|
||||
|
||||
/*
|
||||
* Unless we were told to skip this consideration, choose the
|
||||
* "default loader" to simulate the default ObjectInputStream
|
||||
* resolveClass mechanism (that is, choose the first non-null
|
||||
* loader on the execution stack) to maximize the likelihood of
|
||||
* type compatibility with calling code. (This consideration
|
||||
* is skipped during server parameter unmarshalling using the 1.2
|
||||
* stub protocol, because there would never be a non-null class
|
||||
* loader on the stack in that situation anyway.)
|
||||
*/
|
||||
ClassLoader defaultLoader =
|
||||
skipDefaultResolveClass ? null : latestUserDefinedLoader();
|
||||
|
||||
/*
|
||||
* If the "java.rmi.server.useCodebaseOnly" property was true or
|
||||
* useCodebaseOnly() was called or the annotation is not a String,
|
||||
* load from the local loader using the "java.rmi.server.codebase"
|
||||
* URL. Otherwise, load from a loader using the codebase URL in
|
||||
* the annotation.
|
||||
*/
|
||||
String codebase = null;
|
||||
if (!useCodebaseOnly && annotation instanceof String) {
|
||||
codebase = (String) annotation;
|
||||
}
|
||||
|
||||
try {
|
||||
return RMIClassLoader.loadClass(codebase, className,
|
||||
defaultLoader);
|
||||
} catch (AccessControlException e) {
|
||||
return checkSunClass(className, e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
/*
|
||||
* Fix for 4442373: delegate to ObjectInputStream.resolveClass()
|
||||
* to resolve primitive classes.
|
||||
*/
|
||||
try {
|
||||
if (Character.isLowerCase(className.charAt(0)) &&
|
||||
className.indexOf('.') == -1)
|
||||
{
|
||||
return super.resolveClass(classDesc);
|
||||
}
|
||||
} catch (ClassNotFoundException e2) {
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* resolveProxyClass is extended to acquire (if present) the location
|
||||
* to determine the class loader to define the proxy class in.
|
||||
*/
|
||||
protected Class<?> resolveProxyClass(String[] interfaces)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
StreamChecker checker = streamChecker;
|
||||
if (checker != null) {
|
||||
checker.checkProxyInterfaceNames(interfaces);
|
||||
}
|
||||
|
||||
/*
|
||||
* Always read annotation written by MarshalOutputStream.
|
||||
*/
|
||||
Object annotation = readLocation();
|
||||
|
||||
ClassLoader defaultLoader =
|
||||
skipDefaultResolveClass ? null : latestUserDefinedLoader();
|
||||
|
||||
String codebase = null;
|
||||
if (!useCodebaseOnly && annotation instanceof String) {
|
||||
codebase = (String) annotation;
|
||||
}
|
||||
|
||||
return RMIClassLoader.loadProxyClass(codebase, interfaces,
|
||||
defaultLoader);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns first non-privileged class loader on the stack (excluding
|
||||
* reflection generated frames) or the extension class loader if only
|
||||
* class loaded by the boot class loader and extension class loader are
|
||||
* found on the stack.
|
||||
*/
|
||||
private static ClassLoader latestUserDefinedLoader() {
|
||||
return sun.misc.VM.latestUserDefinedLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix for 4179055: Need to assist resolving sun stubs; resolve
|
||||
* class locally if it is a "permitted" sun class
|
||||
*/
|
||||
private Class<?> checkSunClass(String className, AccessControlException e)
|
||||
throws AccessControlException
|
||||
{
|
||||
// ensure that we are giving out a stub for the correct reason
|
||||
Permission perm = e.getPermission();
|
||||
String name = null;
|
||||
if (perm != null) {
|
||||
name = perm.getName();
|
||||
}
|
||||
|
||||
Class<?> resolvedClass = permittedSunClasses.get(className);
|
||||
|
||||
// if class not permitted, throw the SecurityException
|
||||
if ((name == null) ||
|
||||
(resolvedClass == null) ||
|
||||
((!name.equals("accessClassInPackage.sun.rmi.server")) &&
|
||||
(!name.equals("accessClassInPackage.sun.rmi.registry"))))
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
return resolvedClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location for the class in the stream. This method can
|
||||
* be overridden by subclasses that store this annotation somewhere
|
||||
* else than as the next object in the stream, as is done by this class.
|
||||
*/
|
||||
protected Object readLocation()
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
return readObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a flag to indicate that the superclass's default resolveClass()
|
||||
* implementation should not be invoked by our resolveClass().
|
||||
*/
|
||||
void skipDefaultResolveClass() {
|
||||
skipDefaultResolveClass = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable code downloading except from the URL specified by the
|
||||
* "java.rmi.server.codebase" property.
|
||||
*/
|
||||
void useCodebaseOnly() {
|
||||
useCodebaseOnly = true;
|
||||
}
|
||||
|
||||
synchronized void setStreamChecker(StreamChecker checker) {
|
||||
streamChecker = checker;
|
||||
SharedSecrets.getJavaObjectInputStreamAccess().setValidator(this, checker);
|
||||
}
|
||||
@Override
|
||||
protected ObjectStreamClass readClassDescriptor() throws IOException,
|
||||
ClassNotFoundException {
|
||||
ObjectStreamClass descriptor = super.readClassDescriptor();
|
||||
|
||||
validateDesc(descriptor);
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
private void validateDesc(ObjectStreamClass descriptor) {
|
||||
StreamChecker checker;
|
||||
synchronized (this) {
|
||||
checker = streamChecker;
|
||||
}
|
||||
if (checker != null) {
|
||||
checker.validateDescriptor(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
111
jdkSrc/jdk8/sun/rmi/server/MarshalOutputStream.java
Normal file
111
jdkSrc/jdk8/sun/rmi/server/MarshalOutputStream.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.io.*;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.server.RemoteStub;
|
||||
import sun.rmi.transport.ObjectTable;
|
||||
import sun.rmi.transport.Target;
|
||||
|
||||
/**
|
||||
* A MarshalOutputStream extends ObjectOutputStream to add functions
|
||||
* specific to marshaling of remote object references. If it is
|
||||
* necessary to serialize remote objects or objects that contain
|
||||
* references to remote objects a MarshalOutputStream must be used
|
||||
* instead of ObjectOutputStream. <p>
|
||||
*
|
||||
* A new MarshalOutputStream is constructed to serialize remote
|
||||
* objects or graphs containing remote objects. Objects are written to
|
||||
* the stream using the ObjectOutputStream.writeObject method. <p>
|
||||
*
|
||||
* MarshalOutputStream maps remote objects to the corresponding remote
|
||||
* stub and embeds the location from which to load the stub
|
||||
* classes. The location may be ignored by the client but is supplied.
|
||||
*/
|
||||
public class MarshalOutputStream extends ObjectOutputStream
|
||||
{
|
||||
/**
|
||||
* Creates a marshal output stream with protocol version 1.
|
||||
*/
|
||||
public MarshalOutputStream(OutputStream out) throws IOException {
|
||||
this(out, ObjectStreamConstants.PROTOCOL_VERSION_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a marshal output stream with the given protocol version.
|
||||
*/
|
||||
public MarshalOutputStream(OutputStream out, int protocolVersion)
|
||||
throws IOException
|
||||
{
|
||||
super(out);
|
||||
this.useProtocolVersion(protocolVersion);
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
enableReplaceObject(true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for objects that are instances of java.rmi.Remote
|
||||
* that need to be serialized as proxy objects.
|
||||
*/
|
||||
protected final Object replaceObject(Object obj) throws IOException {
|
||||
if ((obj instanceof Remote) && !(obj instanceof RemoteStub)) {
|
||||
Target target = ObjectTable.getTarget((Remote) obj);
|
||||
if (target != null) {
|
||||
return target.getStub();
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes a location from which to load the the specified class.
|
||||
*/
|
||||
protected void annotateClass(Class<?> cl) throws IOException {
|
||||
writeLocation(java.rmi.server.RMIClassLoader.getClassAnnotation(cl));
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes a location from which to load the specified class.
|
||||
*/
|
||||
protected void annotateProxyClass(Class<?> cl) throws IOException {
|
||||
annotateClass(cl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the location for the class into the stream. This method can
|
||||
* be overridden by subclasses that store this annotation somewhere
|
||||
* else than as the next object in the stream, as is done by this class.
|
||||
*/
|
||||
protected void writeLocation(String location) throws IOException {
|
||||
writeObject(location);
|
||||
}
|
||||
}
|
||||
519
jdkSrc/jdk8/sun/rmi/server/UnicastRef.java
Normal file
519
jdkSrc/jdk8/sun/rmi/server/UnicastRef.java
Normal file
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutput;
|
||||
import java.lang.reflect.Method;
|
||||
import java.rmi.MarshalException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.UnmarshalException;
|
||||
import java.rmi.server.Operation;
|
||||
import java.rmi.server.RemoteCall;
|
||||
import java.rmi.server.RemoteObject;
|
||||
import java.rmi.server.RemoteRef;
|
||||
import java.security.AccessController;
|
||||
|
||||
import sun.misc.SharedSecrets;
|
||||
import sun.rmi.runtime.Log;
|
||||
import sun.rmi.transport.Connection;
|
||||
import sun.rmi.transport.LiveRef;
|
||||
import sun.rmi.transport.StreamRemoteCall;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
|
||||
/**
|
||||
* NOTE: There is a JDK-internal dependency on the existence of this
|
||||
* class's getLiveRef method (as it is inherited by UnicastRef2) in
|
||||
* the implementation of javax.management.remote.rmi.RMIConnector.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class UnicastRef implements RemoteRef {
|
||||
|
||||
/**
|
||||
* Client-side transport log.
|
||||
*/
|
||||
public static final Log clientRefLog =
|
||||
Log.getLog("sun.rmi.client.ref", "transport", Util.logLevel);
|
||||
|
||||
/**
|
||||
* Client-side call log.
|
||||
*/
|
||||
public static final Log clientCallLog =
|
||||
Log.getLog("sun.rmi.client.call", "RMI",
|
||||
AccessController.doPrivileged(
|
||||
new GetBooleanAction("sun.rmi.client.logCalls")));
|
||||
private static final long serialVersionUID = 8258372400816541186L;
|
||||
|
||||
protected LiveRef ref;
|
||||
|
||||
/**
|
||||
* Create a new (empty) Unicast remote reference.
|
||||
*/
|
||||
public UnicastRef() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Unicast RemoteRef.
|
||||
*/
|
||||
public UnicastRef(LiveRef liveRef) {
|
||||
ref = liveRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value of this UnicastRef's underlying
|
||||
* LiveRef.
|
||||
*
|
||||
* NOTE: There is a JDK-internal dependency on the existence of
|
||||
* this method (as it is inherited by UnicastRef) in the
|
||||
* implementation of javax.management.remote.rmi.RMIConnector.
|
||||
**/
|
||||
public LiveRef getLiveRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke a method. This form of delegating method invocation
|
||||
* to the reference allows the reference to take care of
|
||||
* setting up the connection to the remote host, marshalling
|
||||
* some representation for the method and parameters, then
|
||||
* communicating the method invocation to the remote host.
|
||||
* This method either returns the result of a method invocation
|
||||
* on the remote object which resides on the remote host or
|
||||
* throws a RemoteException if the call failed or an
|
||||
* application-level exception if the remote invocation throws
|
||||
* an exception.
|
||||
*
|
||||
* @param obj the proxy for the remote object
|
||||
* @param method the method to be invoked
|
||||
* @param params the parameter list
|
||||
* @param opnum a hash that may be used to represent the method
|
||||
* @since 1.2
|
||||
*/
|
||||
public Object invoke(Remote obj,
|
||||
Method method,
|
||||
Object[] params,
|
||||
long opnum)
|
||||
throws Exception
|
||||
{
|
||||
if (clientRefLog.isLoggable(Log.VERBOSE)) {
|
||||
clientRefLog.log(Log.VERBOSE, "method: " + method);
|
||||
}
|
||||
|
||||
if (clientCallLog.isLoggable(Log.VERBOSE)) {
|
||||
logClientCall(obj, method);
|
||||
}
|
||||
|
||||
Connection conn = ref.getChannel().newConnection();
|
||||
RemoteCall call = null;
|
||||
boolean reuse = true;
|
||||
|
||||
/* If the call connection is "reused" early, remember not to
|
||||
* reuse again.
|
||||
*/
|
||||
boolean alreadyFreed = false;
|
||||
|
||||
try {
|
||||
if (clientRefLog.isLoggable(Log.VERBOSE)) {
|
||||
clientRefLog.log(Log.VERBOSE, "opnum = " + opnum);
|
||||
}
|
||||
|
||||
// create call context
|
||||
call = new StreamRemoteCall(conn, ref.getObjID(), -1, opnum);
|
||||
|
||||
// marshal parameters
|
||||
try {
|
||||
ObjectOutput out = call.getOutputStream();
|
||||
marshalCustomCallData(out);
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
marshalValue(types[i], params[i], out);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
clientRefLog.log(Log.BRIEF,
|
||||
"IOException marshalling arguments: ", e);
|
||||
throw new MarshalException("error marshalling arguments", e);
|
||||
}
|
||||
|
||||
// unmarshal return
|
||||
call.executeCall();
|
||||
|
||||
try {
|
||||
Class<?> rtype = method.getReturnType();
|
||||
if (rtype == void.class)
|
||||
return null;
|
||||
ObjectInput in = call.getInputStream();
|
||||
|
||||
/* StreamRemoteCall.done() does not actually make use
|
||||
* of conn, therefore it is safe to reuse this
|
||||
* connection before the dirty call is sent for
|
||||
* registered refs.
|
||||
*/
|
||||
Object returnValue = unmarshalValue(rtype, in);
|
||||
|
||||
/* we are freeing the connection now, do not free
|
||||
* again or reuse.
|
||||
*/
|
||||
alreadyFreed = true;
|
||||
|
||||
/* if we got to this point, reuse must have been true. */
|
||||
clientRefLog.log(Log.BRIEF, "free connection (reuse = true)");
|
||||
|
||||
/* Free the call's connection early. */
|
||||
ref.getChannel().free(conn, true);
|
||||
|
||||
return returnValue;
|
||||
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
// disable saving any refs in the inputStream for GC
|
||||
((StreamRemoteCall)call).discardPendingRefs();
|
||||
clientRefLog.log(Log.BRIEF,
|
||||
e.getClass().getName() + " unmarshalling return: ", e);
|
||||
throw new UnmarshalException("error unmarshalling return", e);
|
||||
} finally {
|
||||
try {
|
||||
call.done();
|
||||
} catch (IOException e) {
|
||||
/* WARNING: If the conn has been reused early,
|
||||
* then it is too late to recover from thrown
|
||||
* IOExceptions caught here. This code is relying
|
||||
* on StreamRemoteCall.done() not actually
|
||||
* throwing IOExceptions.
|
||||
*/
|
||||
reuse = false;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
/*
|
||||
* Need to distinguish between client (generated by the
|
||||
* invoke method itself) and server RuntimeExceptions.
|
||||
* Client side RuntimeExceptions are likely to have
|
||||
* corrupted the call connection and those from the server
|
||||
* are not likely to have done so. If the exception came
|
||||
* from the server the call connection should be reused.
|
||||
*/
|
||||
if ((call == null) ||
|
||||
(((StreamRemoteCall) call).getServerException() != e))
|
||||
{
|
||||
reuse = false;
|
||||
}
|
||||
throw e;
|
||||
|
||||
} catch (RemoteException e) {
|
||||
/*
|
||||
* Some failure during call; assume connection cannot
|
||||
* be reused. Must assume failure even if ServerException
|
||||
* or ServerError occurs since these failures can happen
|
||||
* during parameter deserialization which would leave
|
||||
* the connection in a corrupted state.
|
||||
*/
|
||||
reuse = false;
|
||||
throw e;
|
||||
|
||||
} catch (Error e) {
|
||||
/* If errors occurred, the connection is most likely not
|
||||
* reusable.
|
||||
*/
|
||||
reuse = false;
|
||||
throw e;
|
||||
|
||||
} finally {
|
||||
|
||||
/* alreadyFreed ensures that we do not log a reuse that
|
||||
* may have already happened.
|
||||
*/
|
||||
if (!alreadyFreed) {
|
||||
if (clientRefLog.isLoggable(Log.BRIEF)) {
|
||||
clientRefLog.log(Log.BRIEF, "free connection (reuse = " +
|
||||
reuse + ")");
|
||||
}
|
||||
ref.getChannel().free(conn, reuse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void marshalCustomCallData(ObjectOutput out) throws IOException
|
||||
{}
|
||||
|
||||
/**
|
||||
* Marshal value to an ObjectOutput sink using RMI's serialization
|
||||
* format for parameters or return values.
|
||||
*/
|
||||
protected static void marshalValue(Class<?> type, Object value,
|
||||
ObjectOutput out)
|
||||
throws IOException
|
||||
{
|
||||
if (type.isPrimitive()) {
|
||||
if (type == int.class) {
|
||||
out.writeInt(((Integer) value).intValue());
|
||||
} else if (type == boolean.class) {
|
||||
out.writeBoolean(((Boolean) value).booleanValue());
|
||||
} else if (type == byte.class) {
|
||||
out.writeByte(((Byte) value).byteValue());
|
||||
} else if (type == char.class) {
|
||||
out.writeChar(((Character) value).charValue());
|
||||
} else if (type == short.class) {
|
||||
out.writeShort(((Short) value).shortValue());
|
||||
} else if (type == long.class) {
|
||||
out.writeLong(((Long) value).longValue());
|
||||
} else if (type == float.class) {
|
||||
out.writeFloat(((Float) value).floatValue());
|
||||
} else if (type == double.class) {
|
||||
out.writeDouble(((Double) value).doubleValue());
|
||||
} else {
|
||||
throw new Error("Unrecognized primitive type: " + type);
|
||||
}
|
||||
} else {
|
||||
out.writeObject(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshal value from an ObjectInput source using RMI's serialization
|
||||
* format for parameters or return values.
|
||||
*/
|
||||
protected static Object unmarshalValue(Class<?> type, ObjectInput in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
if (type.isPrimitive()) {
|
||||
if (type == int.class) {
|
||||
return Integer.valueOf(in.readInt());
|
||||
} else if (type == boolean.class) {
|
||||
return Boolean.valueOf(in.readBoolean());
|
||||
} else if (type == byte.class) {
|
||||
return Byte.valueOf(in.readByte());
|
||||
} else if (type == char.class) {
|
||||
return Character.valueOf(in.readChar());
|
||||
} else if (type == short.class) {
|
||||
return Short.valueOf(in.readShort());
|
||||
} else if (type == long.class) {
|
||||
return Long.valueOf(in.readLong());
|
||||
} else if (type == float.class) {
|
||||
return Float.valueOf(in.readFloat());
|
||||
} else if (type == double.class) {
|
||||
return Double.valueOf(in.readDouble());
|
||||
} else {
|
||||
throw new Error("Unrecognized primitive type: " + type);
|
||||
}
|
||||
} else if (type == String.class && in instanceof ObjectInputStream) {
|
||||
return SharedSecrets.getJavaObjectInputStreamReadString().readString((ObjectInputStream)in);
|
||||
} else {
|
||||
return in.readObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an appropriate call object for a new call on this object.
|
||||
* Passing operation array and index, allows the stubs generator to
|
||||
* assign the operation indexes and interpret them. The RemoteRef
|
||||
* may need the operation to encode in for the call.
|
||||
*/
|
||||
public RemoteCall newCall(RemoteObject obj, Operation[] ops, int opnum,
|
||||
long hash)
|
||||
throws RemoteException
|
||||
{
|
||||
clientRefLog.log(Log.BRIEF, "get connection");
|
||||
|
||||
Connection conn = ref.getChannel().newConnection();
|
||||
try {
|
||||
clientRefLog.log(Log.VERBOSE, "create call context");
|
||||
|
||||
/* log information about the outgoing call */
|
||||
if (clientCallLog.isLoggable(Log.VERBOSE)) {
|
||||
logClientCall(obj, ops[opnum]);
|
||||
}
|
||||
|
||||
RemoteCall call =
|
||||
new StreamRemoteCall(conn, ref.getObjID(), opnum, hash);
|
||||
try {
|
||||
marshalCustomCallData(call.getOutputStream());
|
||||
} catch (IOException e) {
|
||||
throw new MarshalException("error marshaling " +
|
||||
"custom call data");
|
||||
}
|
||||
return call;
|
||||
} catch (RemoteException e) {
|
||||
ref.getChannel().free(conn, false);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke makes the remote call present in the RemoteCall object.
|
||||
*
|
||||
* Invoke will raise any "user" exceptions which
|
||||
* should pass through and not be caught by the stub. If any
|
||||
* exception is raised during the remote invocation, invoke should
|
||||
* take care of cleaning up the connection before raising the
|
||||
* "user" or remote exception.
|
||||
*/
|
||||
public void invoke(RemoteCall call) throws Exception {
|
||||
try {
|
||||
clientRefLog.log(Log.VERBOSE, "execute call");
|
||||
|
||||
call.executeCall();
|
||||
|
||||
} catch (RemoteException e) {
|
||||
/*
|
||||
* Call did not complete; connection can't be reused.
|
||||
*/
|
||||
clientRefLog.log(Log.BRIEF, "exception: ", e);
|
||||
free(call, false);
|
||||
throw e;
|
||||
|
||||
} catch (Error e) {
|
||||
/* If errors occurred, the connection is most likely not
|
||||
* reusable.
|
||||
*/
|
||||
clientRefLog.log(Log.BRIEF, "error: ", e);
|
||||
free(call, false);
|
||||
throw e;
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
/*
|
||||
* REMIND: Since runtime exceptions are no longer wrapped,
|
||||
* we can't assue that the connection was left in
|
||||
* a reusable state. Is this okay?
|
||||
*/
|
||||
clientRefLog.log(Log.BRIEF, "exception: ", e);
|
||||
free(call, false);
|
||||
throw e;
|
||||
|
||||
} catch (Exception e) {
|
||||
/*
|
||||
* Assume that these other exceptions are user exceptions
|
||||
* and leave the connection in a reusable state.
|
||||
*/
|
||||
clientRefLog.log(Log.BRIEF, "exception: ", e);
|
||||
free(call, true);
|
||||
/* reraise user (and unknown) exceptions. */
|
||||
throw e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't free the connection if an exception did not
|
||||
* occur because the stub needs to unmarshal the
|
||||
* return value. The connection will be freed
|
||||
* by a call to the "done" method.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method to free a connection.
|
||||
*/
|
||||
private void free(RemoteCall call, boolean reuse) throws RemoteException {
|
||||
Connection conn = ((StreamRemoteCall)call).getConnection();
|
||||
ref.getChannel().free(conn, reuse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Done should only be called if the invoke returns successfully
|
||||
* (non-exceptionally) to the stub. It allows the remote reference to
|
||||
* clean up (or reuse) the connection.
|
||||
*/
|
||||
public void done(RemoteCall call) throws RemoteException {
|
||||
|
||||
/* Done only uses the connection inside the call to obtain the
|
||||
* channel the connection uses. Once all information is read
|
||||
* from the connection, the connection may be freed.
|
||||
*/
|
||||
clientRefLog.log(Log.BRIEF, "free connection (reuse = true)");
|
||||
|
||||
/* Free the call connection early. */
|
||||
free(call, true);
|
||||
|
||||
try {
|
||||
call.done();
|
||||
} catch (IOException e) {
|
||||
/* WARNING: If the conn has been reused early, then it is
|
||||
* too late to recover from thrown IOExceptions caught
|
||||
* here. This code is relying on StreamRemoteCall.done()
|
||||
* not actually throwing IOExceptions.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the details of an outgoing call. The method parameter is either of
|
||||
* type java.lang.reflect.Method or java.rmi.server.Operation.
|
||||
*/
|
||||
void logClientCall(Object obj, Object method) {
|
||||
clientCallLog.log(Log.VERBOSE, "outbound call: " +
|
||||
ref + " : " + obj.getClass().getName() +
|
||||
ref.getObjID().toString() + ": " + method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of the ref type to be serialized
|
||||
*/
|
||||
public String getRefClass(ObjectOutput out) {
|
||||
return "UnicastRef";
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out external representation for remote ref.
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
ref.write(out, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in external representation for remote ref.
|
||||
* @exception ClassNotFoundException If the class for an object
|
||||
* being restored cannot be found.
|
||||
*/
|
||||
public void readExternal(ObjectInput in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
ref = LiveRef.read(in, false);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------;
|
||||
/**
|
||||
* Method from object, forward from RemoteObject
|
||||
*/
|
||||
public String remoteToString() {
|
||||
return Util.getUnqualifiedName(getClass()) + " [liveRef: " + ref + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* default implementation of hashCode for remote objects
|
||||
*/
|
||||
public int remoteHashCode() {
|
||||
return ref.hashCode();
|
||||
}
|
||||
|
||||
/** default implementation of equals for remote objects
|
||||
*/
|
||||
public boolean remoteEquals(RemoteRef sub) {
|
||||
if (sub instanceof UnicastRef)
|
||||
return ref.remoteEquals(((UnicastRef)sub).ref);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
80
jdkSrc/jdk8/sun/rmi/server/UnicastRef2.java
Normal file
80
jdkSrc/jdk8/sun/rmi/server/UnicastRef2.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import sun.rmi.transport.LiveRef;
|
||||
|
||||
/**
|
||||
* NOTE: There is a JDK-internal dependency on the existence of this
|
||||
* class and its getLiveRef method (inherited from UnicastRef) in the
|
||||
* implementation of javax.management.remote.rmi.RMIConnector.
|
||||
**/
|
||||
public class UnicastRef2 extends UnicastRef {
|
||||
private static final long serialVersionUID = 1829537514995881838L;
|
||||
|
||||
/**
|
||||
* Create a new (empty) Unicast remote reference.
|
||||
*/
|
||||
public UnicastRef2()
|
||||
{}
|
||||
|
||||
/**
|
||||
* Create a new Unicast RemoteRef.
|
||||
*/
|
||||
public UnicastRef2(LiveRef liveRef) {
|
||||
super(liveRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of the ref type to be serialized
|
||||
*/
|
||||
public String getRefClass(ObjectOutput out)
|
||||
{
|
||||
return "UnicastRef2";
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out external representation for remote ref.
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out) throws IOException
|
||||
{
|
||||
ref.write(out, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in external representation for remote ref.
|
||||
* @exception ClassNotFoundException If the class for an object
|
||||
* being restored cannot be found.
|
||||
*/
|
||||
public void readExternal(ObjectInput in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
ref = LiveRef.read(in, true);
|
||||
}
|
||||
}
|
||||
689
jdkSrc/jdk8/sun/rmi/server/UnicastServerRef.java
Normal file
689
jdkSrc/jdk8/sun/rmi/server/UnicastServerRef.java
Normal file
@@ -0,0 +1,689 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.rmi.AccessException;
|
||||
import java.rmi.MarshalException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.ServerError;
|
||||
import java.rmi.ServerException;
|
||||
import java.rmi.UnmarshalException;
|
||||
import java.rmi.server.ExportException;
|
||||
import java.rmi.server.Operation;
|
||||
import java.rmi.server.RemoteCall;
|
||||
import java.rmi.server.RemoteRef;
|
||||
import java.rmi.server.RemoteStub;
|
||||
import java.rmi.server.ServerNotActiveException;
|
||||
import java.rmi.server.ServerRef;
|
||||
import java.rmi.server.Skeleton;
|
||||
import java.rmi.server.SkeletonNotFoundException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import sun.misc.ObjectInputFilter;
|
||||
import sun.rmi.runtime.Log;
|
||||
import sun.rmi.transport.LiveRef;
|
||||
import sun.rmi.transport.StreamRemoteCall;
|
||||
import sun.rmi.transport.Target;
|
||||
import sun.rmi.transport.tcp.TCPTransport;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
|
||||
/**
|
||||
* UnicastServerRef implements the remote reference layer server-side
|
||||
* behavior for remote objects exported with the "UnicastRef" reference
|
||||
* type.
|
||||
* If an {@link ObjectInputFilter ObjectInputFilter} is supplied it is
|
||||
* invoked during deserialization to filter the arguments,
|
||||
* otherwise the default filter of {@link ObjectInputStream ObjectInputStream}
|
||||
* applies.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
* @author Roger Riggs
|
||||
* @author Peter Jones
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class UnicastServerRef extends UnicastRef
|
||||
implements ServerRef, Dispatcher
|
||||
{
|
||||
/** value of server call log property */
|
||||
public static final boolean logCalls = AccessController.doPrivileged(
|
||||
new GetBooleanAction("java.rmi.server.logCalls"));
|
||||
|
||||
/** server call log */
|
||||
public static final Log callLog =
|
||||
Log.getLog("sun.rmi.server.call", "RMI", logCalls);
|
||||
|
||||
// use serialVersionUID from JDK 1.2.2 for interoperability
|
||||
private static final long serialVersionUID = -7384275867073752268L;
|
||||
|
||||
/** flag to enable writing exceptions to System.err */
|
||||
private static final boolean wantExceptionLog =
|
||||
AccessController.doPrivileged(
|
||||
new GetBooleanAction("sun.rmi.server.exceptionTrace"));
|
||||
|
||||
private boolean forceStubUse = false;
|
||||
|
||||
/**
|
||||
* flag to remove server-side stack traces before marshalling
|
||||
* exceptions thrown by remote invocations to this VM
|
||||
*/
|
||||
private static final boolean suppressStackTraces =
|
||||
AccessController.doPrivileged(
|
||||
new GetBooleanAction(
|
||||
"sun.rmi.server.suppressStackTraces"));
|
||||
|
||||
/**
|
||||
* skeleton to dispatch remote calls through, for 1.1 stub protocol
|
||||
* (may be null if stub class only uses 1.2 stub protocol)
|
||||
*/
|
||||
private transient Skeleton skel;
|
||||
|
||||
// The ObjectInputFilter for checking the invocation arguments
|
||||
private final transient ObjectInputFilter filter;
|
||||
|
||||
/** maps method hash to Method object for each remote method */
|
||||
private transient Map<Long,Method> hashToMethod_Map = null;
|
||||
|
||||
/**
|
||||
* A weak hash map, mapping classes to hash maps that map method
|
||||
* hashes to method objects.
|
||||
**/
|
||||
private static final WeakClassHashMap<Map<Long,Method>> hashToMethod_Maps =
|
||||
new HashToMethod_Maps();
|
||||
|
||||
/** cache of impl classes that have no corresponding skeleton class */
|
||||
private static final Map<Class<?>,?> withoutSkeletons =
|
||||
Collections.synchronizedMap(new WeakHashMap<Class<?>,Void>());
|
||||
|
||||
private final AtomicInteger methodCallIDCount = new AtomicInteger(0);
|
||||
|
||||
/**
|
||||
* Create a new (empty) Unicast server remote reference.
|
||||
* The filter is null to defer to the default ObjectInputStream filter, if any.
|
||||
*/
|
||||
public UnicastServerRef() {
|
||||
this.filter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Unicast server remote reference for a specified
|
||||
* liveRef.
|
||||
* The filter is null to defer to the default ObjectInputStream filter, if any.
|
||||
*/
|
||||
public UnicastServerRef(LiveRef ref) {
|
||||
super(ref);
|
||||
this.filter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Unicast server remote reference for a specified
|
||||
* liveRef and filter.
|
||||
*/
|
||||
public UnicastServerRef(LiveRef ref, ObjectInputFilter filter) {
|
||||
super(ref);
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Unicast server remote reference to be exported
|
||||
* on the specified port.
|
||||
*/
|
||||
public UnicastServerRef(int port) {
|
||||
super(new LiveRef(port));
|
||||
this.filter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a UnicastServerRef to be exported on an
|
||||
* anonymous port (i.e., 0) and that uses a pregenerated stub class
|
||||
* (NOT a dynamic proxy instance) if 'forceStubUse' is 'true'.
|
||||
*
|
||||
* This constructor is only called by the method
|
||||
* UnicastRemoteObject.exportObject(Remote) passing 'true' for
|
||||
* 'forceStubUse'. The UnicastRemoteObject.exportObject(Remote) method
|
||||
* returns RemoteStub, so it must ensure that the stub for the
|
||||
* exported object is an instance of a pregenerated stub class that
|
||||
* extends RemoteStub (instead of an instance of a dynamic proxy class
|
||||
* which is not an instance of RemoteStub).
|
||||
**/
|
||||
public UnicastServerRef(boolean forceStubUse) {
|
||||
this(0);
|
||||
this.forceStubUse = forceStubUse;
|
||||
}
|
||||
|
||||
/**
|
||||
* With the addition of support for dynamic proxies as stubs, this
|
||||
* method is obsolete because it returns RemoteStub instead of the more
|
||||
* general Remote. It should not be called. It sets the
|
||||
* 'forceStubUse' flag to true so that the stub for the exported object
|
||||
* is forced to be an instance of the pregenerated stub class, which
|
||||
* extends RemoteStub.
|
||||
*
|
||||
* Export this object, create the skeleton and stubs for this
|
||||
* dispatcher. Create a stub based on the type of the impl,
|
||||
* initialize it with the appropriate remote reference. Create the
|
||||
* target defined by the impl, dispatcher (this) and stub.
|
||||
* Export that target via the Ref.
|
||||
**/
|
||||
public RemoteStub exportObject(Remote impl, Object data)
|
||||
throws RemoteException
|
||||
{
|
||||
forceStubUse = true;
|
||||
return (RemoteStub) exportObject(impl, data, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this object, create the skeleton and stubs for this
|
||||
* dispatcher. Create a stub based on the type of the impl,
|
||||
* initialize it with the appropriate remote reference. Create the
|
||||
* target defined by the impl, dispatcher (this) and stub.
|
||||
* Export that target via the Ref.
|
||||
*/
|
||||
public Remote exportObject(Remote impl, Object data,
|
||||
boolean permanent)
|
||||
throws RemoteException
|
||||
{
|
||||
Class<?> implClass = impl.getClass();
|
||||
Remote stub;
|
||||
|
||||
try {
|
||||
stub = Util.createProxy(implClass, getClientRef(), forceStubUse);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ExportException(
|
||||
"remote object implements illegal remote interface", e);
|
||||
}
|
||||
if (stub instanceof RemoteStub) {
|
||||
setSkeleton(impl);
|
||||
}
|
||||
|
||||
Target target =
|
||||
new Target(impl, this, stub, ref.getObjID(), permanent);
|
||||
ref.exportObject(target);
|
||||
hashToMethod_Map = hashToMethod_Maps.get(implClass);
|
||||
return stub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hostname of the current client. When called from a
|
||||
* thread actively handling a remote method invocation the
|
||||
* hostname of the client is returned.
|
||||
* @exception ServerNotActiveException If called outside of servicing
|
||||
* a remote method invocation.
|
||||
*/
|
||||
public String getClientHost() throws ServerNotActiveException {
|
||||
return TCPTransport.getClientHost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers and sets the appropriate skeleton for the impl.
|
||||
*/
|
||||
public void setSkeleton(Remote impl) throws RemoteException {
|
||||
if (!withoutSkeletons.containsKey(impl.getClass())) {
|
||||
try {
|
||||
skel = Util.createSkeleton(impl);
|
||||
} catch (SkeletonNotFoundException e) {
|
||||
/*
|
||||
* Ignore exception for skeleton class not found, because a
|
||||
* skeleton class is not necessary with the 1.2 stub protocol.
|
||||
* Remember that this impl's class does not have a skeleton
|
||||
* class so we don't waste time searching for it again.
|
||||
*/
|
||||
withoutSkeletons.put(impl.getClass(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call to dispatch to the remote object (on the server side).
|
||||
* The up-call to the server and the marshalling of return result
|
||||
* (or exception) should be handled before returning from this
|
||||
* method.
|
||||
* @param obj the target remote object for the call
|
||||
* @param call the "remote call" from which operation and
|
||||
* method arguments can be obtained.
|
||||
* @exception IOException If unable to marshal return result or
|
||||
* release input or output streams
|
||||
*/
|
||||
public void dispatch(Remote obj, RemoteCall call) throws IOException {
|
||||
// positive operation number in 1.1 stubs;
|
||||
// negative version number in 1.2 stubs and beyond...
|
||||
int num;
|
||||
long op;
|
||||
|
||||
try {
|
||||
// read remote call header
|
||||
ObjectInput in;
|
||||
try {
|
||||
in = call.getInputStream();
|
||||
num = in.readInt();
|
||||
} catch (Exception readEx) {
|
||||
throw new UnmarshalException("error unmarshalling call header",
|
||||
readEx);
|
||||
}
|
||||
if (skel != null) {
|
||||
// If there is a skeleton, use it
|
||||
oldDispatch(obj, call, num);
|
||||
return;
|
||||
|
||||
} else if (num >= 0){
|
||||
throw new UnmarshalException(
|
||||
"skeleton class not found but required for client version");
|
||||
}
|
||||
try {
|
||||
op = in.readLong();
|
||||
} catch (Exception readEx) {
|
||||
throw new UnmarshalException("error unmarshalling call header",
|
||||
readEx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since only system classes (with null class loaders) will be on
|
||||
* the execution stack during parameter unmarshalling for the 1.2
|
||||
* stub protocol, tell the MarshalInputStream not to bother trying
|
||||
* to resolve classes using its superclasses's default method of
|
||||
* consulting the first non-null class loader on the stack.
|
||||
*/
|
||||
MarshalInputStream marshalStream = (MarshalInputStream) in;
|
||||
marshalStream.skipDefaultResolveClass();
|
||||
|
||||
Method method = hashToMethod_Map.get(op);
|
||||
if (method == null) {
|
||||
throw new UnmarshalException("unrecognized method hash: " +
|
||||
"method not supported by remote object");
|
||||
}
|
||||
|
||||
// if calls are being logged, write out object id and operation
|
||||
logCall(obj, method);
|
||||
|
||||
// unmarshal parameters
|
||||
Object[] params = null;
|
||||
try {
|
||||
unmarshalCustomCallData(in);
|
||||
params = unmarshalParameters(obj, method, marshalStream);
|
||||
|
||||
} catch (AccessException aex) {
|
||||
// For compatibility, AccessException is not wrapped in UnmarshalException
|
||||
// disable saving any refs in the inputStream for GC
|
||||
((StreamRemoteCall) call).discardPendingRefs();
|
||||
throw aex;
|
||||
} catch (java.io.IOException | ClassNotFoundException e) {
|
||||
// disable saving any refs in the inputStream for GC
|
||||
((StreamRemoteCall) call).discardPendingRefs();
|
||||
throw new UnmarshalException(
|
||||
"error unmarshalling arguments", e);
|
||||
} finally {
|
||||
call.releaseInputStream();
|
||||
}
|
||||
|
||||
// make upcall on remote object
|
||||
Object result;
|
||||
try {
|
||||
result = method.invoke(obj, params);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw e.getTargetException();
|
||||
}
|
||||
|
||||
// marshal return value
|
||||
try {
|
||||
ObjectOutput out = call.getResultStream(true);
|
||||
Class<?> rtype = method.getReturnType();
|
||||
if (rtype != void.class) {
|
||||
marshalValue(rtype, result, out);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new MarshalException("error marshalling return", ex);
|
||||
/*
|
||||
* This throw is problematic because when it is caught below,
|
||||
* we attempt to marshal it back to the client, but at this
|
||||
* point, a "normal return" has already been indicated,
|
||||
* so marshalling an exception will corrupt the stream.
|
||||
* This was the case with skeletons as well; there is no
|
||||
* immediately obvious solution without a protocol change.
|
||||
*/
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Throwable origEx = e;
|
||||
logCallException(e);
|
||||
|
||||
ObjectOutput out = call.getResultStream(false);
|
||||
if (e instanceof Error) {
|
||||
e = new ServerError(
|
||||
"Error occurred in server thread", (Error) e);
|
||||
} else if (e instanceof RemoteException) {
|
||||
e = new ServerException(
|
||||
"RemoteException occurred in server thread",
|
||||
(Exception) e);
|
||||
}
|
||||
if (suppressStackTraces) {
|
||||
clearStackTraces(e);
|
||||
}
|
||||
out.writeObject(e);
|
||||
|
||||
// AccessExceptions should cause Transport.serviceCall
|
||||
// to flag the connection as unusable.
|
||||
if (origEx instanceof AccessException) {
|
||||
throw new IOException("Connection is not reusable", origEx);
|
||||
}
|
||||
} finally {
|
||||
call.releaseInputStream(); // in case skeleton doesn't
|
||||
call.releaseOutputStream();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a filter for invocation arguments, if a filter has been set.
|
||||
* Called by dispatch before the arguments are read.
|
||||
*/
|
||||
protected void unmarshalCustomCallData(ObjectInput in)
|
||||
throws IOException, ClassNotFoundException {
|
||||
if (filter != null &&
|
||||
in instanceof ObjectInputStream) {
|
||||
// Set the filter on the stream
|
||||
ObjectInputStream ois = (ObjectInputStream) in;
|
||||
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
ObjectInputFilter.Config.setObjectInputFilter(ois, filter);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle server-side dispatch using the RMI 1.1 stub/skeleton
|
||||
* protocol, given a non-negative operation number or negative method hash
|
||||
* that has already been read from the call stream.
|
||||
* Exceptions are handled by the caller to be sent to the remote client.
|
||||
*
|
||||
* @param obj the target remote object for the call
|
||||
* @param call the "remote call" from which operation and
|
||||
* method arguments can be obtained.
|
||||
* @param op the operation number
|
||||
* @throws Exception if unable to marshal return result or
|
||||
* release input or output streams
|
||||
*/
|
||||
private void oldDispatch(Remote obj, RemoteCall call, int op)
|
||||
throws Exception
|
||||
{
|
||||
long hash; // hash for matching stub with skeleton
|
||||
|
||||
// read remote call header
|
||||
ObjectInput in;
|
||||
in = call.getInputStream();
|
||||
try {
|
||||
Class<?> clazz = Class.forName("sun.rmi.transport.DGCImpl_Skel");
|
||||
if (clazz.isAssignableFrom(skel.getClass())) {
|
||||
((MarshalInputStream)in).useCodebaseOnly();
|
||||
}
|
||||
} catch (ClassNotFoundException ignore) { }
|
||||
|
||||
try {
|
||||
hash = in.readLong();
|
||||
} catch (Exception ioe) {
|
||||
throw new UnmarshalException("error unmarshalling call header", ioe);
|
||||
}
|
||||
|
||||
// if calls are being logged, write out object id and operation
|
||||
Operation[] operations = skel.getOperations();
|
||||
logCall(obj, op >= 0 && op < operations.length ? operations[op] : "op: " + op);
|
||||
unmarshalCustomCallData(in);
|
||||
// dispatch to skeleton for remote object
|
||||
skel.dispatch(obj, call, op, hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the stack trace of the given Throwable by replacing it with
|
||||
* an empty StackTraceElement array, and do the same for all of its
|
||||
* chained causative exceptions.
|
||||
*/
|
||||
public static void clearStackTraces(Throwable t) {
|
||||
StackTraceElement[] empty = new StackTraceElement[0];
|
||||
while (t != null) {
|
||||
t.setStackTrace(empty);
|
||||
t = t.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the details of an incoming call. The method parameter is either of
|
||||
* type java.lang.reflect.Method or java.rmi.server.Operation.
|
||||
*/
|
||||
private void logCall(Remote obj, Object method) {
|
||||
if (callLog.isLoggable(Log.VERBOSE)) {
|
||||
String clientHost;
|
||||
try {
|
||||
clientHost = getClientHost();
|
||||
} catch (ServerNotActiveException snae) {
|
||||
clientHost = "(local)"; // shouldn't happen
|
||||
}
|
||||
callLog.log(Log.VERBOSE, "[" + clientHost + ": " +
|
||||
obj.getClass().getName() +
|
||||
ref.getObjID().toString() + ": " +
|
||||
method + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the exception detail of an incoming call.
|
||||
*/
|
||||
private void logCallException(Throwable e) {
|
||||
// if calls are being logged, log them
|
||||
if (callLog.isLoggable(Log.BRIEF)) {
|
||||
String clientHost = "";
|
||||
try {
|
||||
clientHost = "[" + getClientHost() + "] ";
|
||||
} catch (ServerNotActiveException snae) {
|
||||
}
|
||||
callLog.log(Log.BRIEF, clientHost + "exception: ", e);
|
||||
}
|
||||
|
||||
// write exceptions (only) to System.err if desired
|
||||
if (wantExceptionLog) {
|
||||
java.io.PrintStream log = System.err;
|
||||
synchronized (log) {
|
||||
log.println();
|
||||
log.println("Exception dispatching call to " +
|
||||
ref.getObjID() + " in thread \"" +
|
||||
Thread.currentThread().getName() +
|
||||
"\" at " + (new Date()) + ":");
|
||||
e.printStackTrace(log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of the ref type to be serialized.
|
||||
*/
|
||||
public String getRefClass(ObjectOutput out) {
|
||||
return "UnicastServerRef";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client remote reference for this remoteRef.
|
||||
* In the case of a client RemoteRef "this" is the answer.
|
||||
* For a server remote reference, a client side one will have to
|
||||
* found or created.
|
||||
*/
|
||||
protected RemoteRef getClientRef() {
|
||||
return new UnicastRef(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out external representation for remote ref.
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in external representation for remote ref.
|
||||
* @exception ClassNotFoundException If the class for an object
|
||||
* being restored cannot be found.
|
||||
*/
|
||||
public void readExternal(ObjectInput in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
// object is re-exported elsewhere (e.g., by UnicastRemoteObject)
|
||||
ref = null;
|
||||
skel = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A weak hash map, mapping classes to hash maps that map method
|
||||
* hashes to method objects.
|
||||
**/
|
||||
private static class HashToMethod_Maps
|
||||
extends WeakClassHashMap<Map<Long,Method>>
|
||||
{
|
||||
HashToMethod_Maps() {}
|
||||
|
||||
protected Map<Long,Method> computeValue(Class<?> remoteClass) {
|
||||
Map<Long,Method> map = new HashMap<>();
|
||||
for (Class<?> cl = remoteClass;
|
||||
cl != null;
|
||||
cl = cl.getSuperclass())
|
||||
{
|
||||
for (Class<?> intf : cl.getInterfaces()) {
|
||||
if (Remote.class.isAssignableFrom(intf)) {
|
||||
for (Method method : intf.getMethods()) {
|
||||
final Method m = method;
|
||||
/*
|
||||
* Set this Method object to override language
|
||||
* access checks so that the dispatcher can invoke
|
||||
* methods from non-public remote interfaces.
|
||||
*/
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
m.setAccessible(true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
map.put(Util.computeMethodHash(m), m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshal parameters for the given method of the given instance over
|
||||
* the given marshalinputstream. Perform any necessary checks.
|
||||
*/
|
||||
private Object[] unmarshalParameters(Object obj, Method method, MarshalInputStream in)
|
||||
throws IOException, ClassNotFoundException {
|
||||
return (obj instanceof DeserializationChecker) ?
|
||||
unmarshalParametersChecked((DeserializationChecker)obj, method, in) :
|
||||
unmarshalParametersUnchecked(method, in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshal parameters for the given method of the given instance over
|
||||
* the given marshalinputstream. Do not perform any additional checks.
|
||||
*/
|
||||
private Object[] unmarshalParametersUnchecked(Method method, ObjectInput in)
|
||||
throws IOException, ClassNotFoundException {
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
Object[] params = new Object[types.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
params[i] = unmarshalValue(types[i], in);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshal parameters for the given method of the given instance over
|
||||
* the given marshalinputstream. Do perform all additional checks.
|
||||
*/
|
||||
private Object[] unmarshalParametersChecked(
|
||||
DeserializationChecker checker,
|
||||
Method method, MarshalInputStream in)
|
||||
throws IOException, ClassNotFoundException {
|
||||
int callID = methodCallIDCount.getAndIncrement();
|
||||
MyChecker myChecker = new MyChecker(checker, method, callID);
|
||||
in.setStreamChecker(myChecker);
|
||||
try {
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
Object[] values = new Object[types.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
myChecker.setIndex(i);
|
||||
values[i] = unmarshalValue(types[i], in);
|
||||
}
|
||||
myChecker.end(callID);
|
||||
return values;
|
||||
} finally {
|
||||
in.setStreamChecker(null);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyChecker implements MarshalInputStream.StreamChecker {
|
||||
private final DeserializationChecker descriptorCheck;
|
||||
private final Method method;
|
||||
private final int callID;
|
||||
private int parameterIndex;
|
||||
|
||||
MyChecker(DeserializationChecker descriptorCheck, Method method, int callID) {
|
||||
this.descriptorCheck = descriptorCheck;
|
||||
this.method = method;
|
||||
this.callID = callID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateDescriptor(ObjectStreamClass descriptor) {
|
||||
descriptorCheck.check(method, descriptor, parameterIndex, callID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkProxyInterfaceNames(String[] ifaces) {
|
||||
descriptorCheck.checkProxyClass(method, ifaces, parameterIndex, callID);
|
||||
}
|
||||
|
||||
void setIndex(int parameterIndex) {
|
||||
this.parameterIndex = parameterIndex;
|
||||
}
|
||||
|
||||
void end(int callId) {
|
||||
descriptorCheck.end(callId);
|
||||
}
|
||||
}
|
||||
}
|
||||
114
jdkSrc/jdk8/sun/rmi/server/UnicastServerRef2.java
Normal file
114
jdkSrc/jdk8/sun/rmi/server/UnicastServerRef2.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
|
||||
import java.io.ObjectOutput;
|
||||
import java.rmi.server.RMIClientSocketFactory;
|
||||
import java.rmi.server.RMIServerSocketFactory;
|
||||
import java.rmi.server.RemoteRef;
|
||||
|
||||
import sun.misc.ObjectInputFilter;
|
||||
|
||||
import sun.rmi.transport.LiveRef;
|
||||
|
||||
/**
|
||||
* Server-side ref for a remote impl that uses a custom socket factory.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
* @author Roger Riggs
|
||||
*/
|
||||
public class UnicastServerRef2 extends UnicastServerRef
|
||||
{
|
||||
// use serialVersionUID from JDK 1.2.2 for interoperability
|
||||
private static final long serialVersionUID = -2289703812660767614L;
|
||||
|
||||
/**
|
||||
* Create a new (empty) Unicast server remote reference.
|
||||
*/
|
||||
public UnicastServerRef2()
|
||||
{}
|
||||
|
||||
/**
|
||||
* Construct a Unicast server remote reference for a specified
|
||||
* liveRef.
|
||||
*/
|
||||
public UnicastServerRef2(LiveRef ref)
|
||||
{
|
||||
super(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Unicast server remote reference for a specified
|
||||
* liveRef and filter.
|
||||
*/
|
||||
public UnicastServerRef2(LiveRef ref,
|
||||
ObjectInputFilter filter)
|
||||
{
|
||||
super(ref, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Unicast server remote reference to be exported
|
||||
* on the specified port.
|
||||
*/
|
||||
public UnicastServerRef2(int port,
|
||||
RMIClientSocketFactory csf,
|
||||
RMIServerSocketFactory ssf)
|
||||
{
|
||||
super(new LiveRef(port, csf, ssf));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Unicast server remote reference to be exported
|
||||
* on the specified port.
|
||||
*/
|
||||
public UnicastServerRef2(int port,
|
||||
RMIClientSocketFactory csf,
|
||||
RMIServerSocketFactory ssf,
|
||||
ObjectInputFilter filter)
|
||||
{
|
||||
super(new LiveRef(port, csf, ssf), filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of the ref type to be serialized
|
||||
*/
|
||||
public String getRefClass(ObjectOutput out)
|
||||
{
|
||||
return "UnicastServerRef2";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client remote reference for this remoteRef.
|
||||
* In the case of a client RemoteRef "this" is the answer.
|
||||
* For a server remote reference, a client side one will have to
|
||||
* found or created.
|
||||
*/
|
||||
protected RemoteRef getClientRef() {
|
||||
return new UnicastRef2(ref);
|
||||
}
|
||||
}
|
||||
466
jdkSrc/jdk8/sun/rmi/server/Util.java
Normal file
466
jdkSrc/jdk8/sun/rmi/server/Util.java
Normal file
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.DataOutputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.Method;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.StubNotFoundException;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.rmi.server.LogStream;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.RMIClientSocketFactory;
|
||||
import java.rmi.server.RemoteObjectInvocationHandler;
|
||||
import java.rmi.server.RemoteRef;
|
||||
import java.rmi.server.RemoteStub;
|
||||
import java.rmi.server.Skeleton;
|
||||
import java.rmi.server.SkeletonNotFoundException;
|
||||
import java.security.AccessController;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import sun.rmi.registry.RegistryImpl;
|
||||
import sun.rmi.runtime.Log;
|
||||
import sun.rmi.transport.LiveRef;
|
||||
import sun.rmi.transport.tcp.TCPEndpoint;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* A utility class with static methods for creating stubs/proxies and
|
||||
* skeletons for remote objects.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public final class Util {
|
||||
|
||||
/** "server" package log level */
|
||||
static final int logLevel = LogStream.parseLevel(
|
||||
AccessController.doPrivileged(
|
||||
new GetPropertyAction("sun.rmi.server.logLevel")));
|
||||
|
||||
/** server reference log */
|
||||
public static final Log serverRefLog =
|
||||
Log.getLog("sun.rmi.server.ref", "transport", Util.logLevel);
|
||||
|
||||
/** cached value of property java.rmi.server.ignoreStubClasses */
|
||||
private static final boolean ignoreStubClasses =
|
||||
AccessController.doPrivileged(
|
||||
new GetBooleanAction("java.rmi.server.ignoreStubClasses")).
|
||||
booleanValue();
|
||||
|
||||
/** cache of impl classes that have no corresponding stub class */
|
||||
private static final Map<Class<?>, Void> withoutStubs =
|
||||
Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>(11));
|
||||
|
||||
/** parameter types for stub constructor */
|
||||
private static final Class<?>[] stubConsParamTypes = { RemoteRef.class };
|
||||
|
||||
private Util() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a proxy for the specified implClass.
|
||||
*
|
||||
* If both of the following criteria is satisfied, a dynamic proxy for
|
||||
* the specified implClass is returned (otherwise a RemoteStub instance
|
||||
* for the specified implClass is returned):
|
||||
*
|
||||
* a) either the property java.rmi.server.ignoreStubClasses is true or
|
||||
* a pregenerated stub class does not exist for the impl class, and
|
||||
* b) forceStubUse is false.
|
||||
*
|
||||
* If the above criteria are satisfied, this method constructs a
|
||||
* dynamic proxy instance (that implements the remote interfaces of
|
||||
* implClass) constructed with a RemoteObjectInvocationHandler instance
|
||||
* constructed with the clientRef.
|
||||
*
|
||||
* Otherwise, this method loads the pregenerated stub class (which
|
||||
* extends RemoteStub and implements the remote interfaces of
|
||||
* implClass) and constructs an instance of the pregenerated stub
|
||||
* class with the clientRef.
|
||||
*
|
||||
* @param implClass the class to obtain remote interfaces from
|
||||
* @param clientRef the remote ref to use in the invocation handler
|
||||
* @param forceStubUse if true, forces creation of a RemoteStub
|
||||
* @throws IllegalArgumentException if implClass implements illegal
|
||||
* remote interfaces
|
||||
* @throws StubNotFoundException if problem locating/creating stub or
|
||||
* creating the dynamic proxy instance
|
||||
**/
|
||||
public static Remote createProxy(Class<?> implClass,
|
||||
RemoteRef clientRef,
|
||||
boolean forceStubUse)
|
||||
throws StubNotFoundException
|
||||
{
|
||||
Class<?> remoteClass;
|
||||
|
||||
try {
|
||||
remoteClass = getRemoteClass(implClass);
|
||||
} catch (ClassNotFoundException ex ) {
|
||||
throw new StubNotFoundException(
|
||||
"object does not implement a remote interface: " +
|
||||
implClass.getName());
|
||||
}
|
||||
|
||||
if (forceStubUse ||
|
||||
!(ignoreStubClasses || !stubClassExists(remoteClass)))
|
||||
{
|
||||
return createStub(remoteClass, clientRef);
|
||||
}
|
||||
|
||||
final ClassLoader loader = implClass.getClassLoader();
|
||||
final Class<?>[] interfaces = getRemoteInterfaces(implClass);
|
||||
final InvocationHandler handler =
|
||||
new RemoteObjectInvocationHandler(clientRef);
|
||||
|
||||
/* REMIND: private remote interfaces? */
|
||||
|
||||
try {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Remote>() {
|
||||
public Remote run() {
|
||||
return (Remote) Proxy.newProxyInstance(loader,
|
||||
interfaces,
|
||||
handler);
|
||||
}});
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new StubNotFoundException("unable to create proxy", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a stub class for the given impl class can be loaded,
|
||||
* otherwise returns false.
|
||||
*
|
||||
* @param remoteClass the class to obtain remote interfaces from
|
||||
*/
|
||||
private static boolean stubClassExists(Class<?> remoteClass) {
|
||||
if (!withoutStubs.containsKey(remoteClass)) {
|
||||
try {
|
||||
Class.forName(remoteClass.getName() + "_Stub",
|
||||
false,
|
||||
remoteClass.getClassLoader());
|
||||
return true;
|
||||
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
withoutStubs.put(remoteClass, null);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the class/superclass that implements the remote interface.
|
||||
* @throws ClassNotFoundException if no class is found to have a
|
||||
* remote interface
|
||||
*/
|
||||
private static Class<?> getRemoteClass(Class<?> cl)
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
while (cl != null) {
|
||||
Class<?>[] interfaces = cl.getInterfaces();
|
||||
for (int i = interfaces.length -1; i >= 0; i--) {
|
||||
if (Remote.class.isAssignableFrom(interfaces[i]))
|
||||
return cl; // this class implements remote object
|
||||
}
|
||||
cl = cl.getSuperclass();
|
||||
}
|
||||
throw new ClassNotFoundException(
|
||||
"class does not implement java.rmi.Remote");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing the remote interfaces implemented
|
||||
* by the given class.
|
||||
*
|
||||
* @param remoteClass the class to obtain remote interfaces from
|
||||
* @throws IllegalArgumentException if remoteClass implements
|
||||
* any illegal remote interfaces
|
||||
* @throws NullPointerException if remoteClass is null
|
||||
*/
|
||||
private static Class<?>[] getRemoteInterfaces(Class<?> remoteClass) {
|
||||
ArrayList<Class<?>> list = new ArrayList<>();
|
||||
getRemoteInterfaces(list, remoteClass);
|
||||
return list.toArray(new Class<?>[list.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the given array list with the remote interfaces implemented
|
||||
* by the given class.
|
||||
*
|
||||
* @throws IllegalArgumentException if the specified class implements
|
||||
* any illegal remote interfaces
|
||||
* @throws NullPointerException if the specified class or list is null
|
||||
*/
|
||||
private static void getRemoteInterfaces(ArrayList<Class<?>> list, Class<?> cl) {
|
||||
Class<?> superclass = cl.getSuperclass();
|
||||
if (superclass != null) {
|
||||
getRemoteInterfaces(list, superclass);
|
||||
}
|
||||
|
||||
Class<?>[] interfaces = cl.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
Class<?> intf = interfaces[i];
|
||||
/*
|
||||
* If it is a remote interface (if it extends from
|
||||
* java.rmi.Remote) and is not already in the list,
|
||||
* then add the interface to the list.
|
||||
*/
|
||||
if (Remote.class.isAssignableFrom(intf)) {
|
||||
if (!(list.contains(intf))) {
|
||||
Method[] methods = intf.getMethods();
|
||||
for (int j = 0; j < methods.length; j++) {
|
||||
checkMethod(methods[j]);
|
||||
}
|
||||
list.add(intf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the supplied method has at least one declared exception
|
||||
* type that is RemoteException or one of its superclasses. If not,
|
||||
* then this method throws IllegalArgumentException.
|
||||
*
|
||||
* @throws IllegalArgumentException if m is an illegal remote method
|
||||
*/
|
||||
private static void checkMethod(Method m) {
|
||||
Class<?>[] ex = m.getExceptionTypes();
|
||||
for (int i = 0; i < ex.length; i++) {
|
||||
if (ex[i].isAssignableFrom(RemoteException.class))
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"illegal remote method encountered: " + m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a RemoteStub instance for the specified class, constructed
|
||||
* with the specified RemoteRef. The supplied class must be the most
|
||||
* derived class in the remote object's superclass chain that
|
||||
* implements a remote interface. The stub class name is the name of
|
||||
* the specified remoteClass with the suffix "_Stub". The loading of
|
||||
* the stub class is initiated from class loader of the specified class
|
||||
* (which may be the bootstrap class loader).
|
||||
**/
|
||||
private static RemoteStub createStub(Class<?> remoteClass, RemoteRef ref)
|
||||
throws StubNotFoundException
|
||||
{
|
||||
String stubname = remoteClass.getName() + "_Stub";
|
||||
|
||||
/* Make sure to use the local stub loader for the stub classes.
|
||||
* When loaded by the local loader the load path can be
|
||||
* propagated to remote clients, by the MarshalOutputStream/InStream
|
||||
* pickle methods
|
||||
*/
|
||||
try {
|
||||
Class<?> stubcl =
|
||||
Class.forName(stubname, false, remoteClass.getClassLoader());
|
||||
Constructor<?> cons = stubcl.getConstructor(stubConsParamTypes);
|
||||
return (RemoteStub) cons.newInstance(new Object[] { ref });
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new StubNotFoundException(
|
||||
"Stub class not found: " + stubname, e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new StubNotFoundException(
|
||||
"Stub class missing constructor: " + stubname, e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new StubNotFoundException(
|
||||
"Can't create instance of stub class: " + stubname, e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new StubNotFoundException(
|
||||
"Stub class constructor not public: " + stubname, e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new StubNotFoundException(
|
||||
"Exception creating instance of stub class: " + stubname, e);
|
||||
} catch (ClassCastException e) {
|
||||
throw new StubNotFoundException(
|
||||
"Stub class not instance of RemoteStub: " + stubname, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate and return the Skeleton for the specified remote object
|
||||
*/
|
||||
static Skeleton createSkeleton(Remote object)
|
||||
throws SkeletonNotFoundException
|
||||
{
|
||||
Class<?> cl;
|
||||
try {
|
||||
cl = getRemoteClass(object.getClass());
|
||||
} catch (ClassNotFoundException ex ) {
|
||||
throw new SkeletonNotFoundException(
|
||||
"object does not implement a remote interface: " +
|
||||
object.getClass().getName());
|
||||
}
|
||||
|
||||
// now try to load the skeleton based ont he name of the class
|
||||
String skelname = cl.getName() + "_Skel";
|
||||
try {
|
||||
Class<?> skelcl = Class.forName(skelname, false, cl.getClassLoader());
|
||||
|
||||
return (Skeleton)skelcl.newInstance();
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new SkeletonNotFoundException("Skeleton class not found: " +
|
||||
skelname, ex);
|
||||
} catch (InstantiationException ex) {
|
||||
throw new SkeletonNotFoundException("Can't create skeleton: " +
|
||||
skelname, ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new SkeletonNotFoundException("No public constructor: " +
|
||||
skelname, ex);
|
||||
} catch (ClassCastException ex) {
|
||||
throw new SkeletonNotFoundException(
|
||||
"Skeleton not of correct class: " + skelname, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the "method hash" of a remote method. The method hash
|
||||
* is a long containing the first 64 bits of the SHA digest from
|
||||
* the UTF encoded string of the method name and descriptor.
|
||||
*/
|
||||
public static long computeMethodHash(Method m) {
|
||||
long hash = 0;
|
||||
ByteArrayOutputStream sink = new ByteArrayOutputStream(127);
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
DataOutputStream out = new DataOutputStream(
|
||||
new DigestOutputStream(sink, md));
|
||||
|
||||
String s = getMethodNameAndDescriptor(m);
|
||||
if (serverRefLog.isLoggable(Log.VERBOSE)) {
|
||||
serverRefLog.log(Log.VERBOSE,
|
||||
"string used for method hash: \"" + s + "\"");
|
||||
}
|
||||
out.writeUTF(s);
|
||||
|
||||
// use only the first 64 bits of the digest for the hash
|
||||
out.flush();
|
||||
byte hasharray[] = md.digest();
|
||||
for (int i = 0; i < Math.min(8, hasharray.length); i++) {
|
||||
hash += ((long) (hasharray[i] & 0xFF)) << (i * 8);
|
||||
}
|
||||
} catch (IOException ignore) {
|
||||
/* can't happen, but be deterministic anyway. */
|
||||
hash = -1;
|
||||
} catch (NoSuchAlgorithmException complain) {
|
||||
throw new SecurityException(complain.getMessage());
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string consisting of the given method's name followed by
|
||||
* its "method descriptor", as appropriate for use in the computation
|
||||
* of the "method hash".
|
||||
*
|
||||
* See section 4.3.3 of The Java Virtual Machine Specification for
|
||||
* the definition of a "method descriptor".
|
||||
*/
|
||||
private static String getMethodNameAndDescriptor(Method m) {
|
||||
StringBuffer desc = new StringBuffer(m.getName());
|
||||
desc.append('(');
|
||||
Class<?>[] paramTypes = m.getParameterTypes();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
desc.append(getTypeDescriptor(paramTypes[i]));
|
||||
}
|
||||
desc.append(')');
|
||||
Class<?> returnType = m.getReturnType();
|
||||
if (returnType == void.class) { // optimization: handle void here
|
||||
desc.append('V');
|
||||
} else {
|
||||
desc.append(getTypeDescriptor(returnType));
|
||||
}
|
||||
return desc.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the descriptor of a particular type, as appropriate for either
|
||||
* a parameter or return type in a method descriptor.
|
||||
*/
|
||||
private static String getTypeDescriptor(Class<?> type) {
|
||||
if (type.isPrimitive()) {
|
||||
if (type == int.class) {
|
||||
return "I";
|
||||
} else if (type == boolean.class) {
|
||||
return "Z";
|
||||
} else if (type == byte.class) {
|
||||
return "B";
|
||||
} else if (type == char.class) {
|
||||
return "C";
|
||||
} else if (type == short.class) {
|
||||
return "S";
|
||||
} else if (type == long.class) {
|
||||
return "J";
|
||||
} else if (type == float.class) {
|
||||
return "F";
|
||||
} else if (type == double.class) {
|
||||
return "D";
|
||||
} else if (type == void.class) {
|
||||
return "V";
|
||||
} else {
|
||||
throw new Error("unrecognized primitive type: " + type);
|
||||
}
|
||||
} else if (type.isArray()) {
|
||||
/*
|
||||
* According to JLS 20.3.2, the getName() method on Class does
|
||||
* return the VM type descriptor format for array classes (only);
|
||||
* using that should be quicker than the otherwise obvious code:
|
||||
*
|
||||
* return "[" + getTypeDescriptor(type.getComponentType());
|
||||
*/
|
||||
return type.getName().replace('.', '/');
|
||||
} else {
|
||||
return "L" + type.getName().replace('.', '/') + ";";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binary name of the given type without package
|
||||
* qualification. Nested types are treated no differently from
|
||||
* top-level types, so for a nested type, the returned name will
|
||||
* still be qualified with the simple name of its enclosing
|
||||
* top-level type (and perhaps other enclosing types), the
|
||||
* separator will be '$', etc.
|
||||
**/
|
||||
public static String getUnqualifiedName(Class<?> c) {
|
||||
String binaryName = c.getName();
|
||||
return binaryName.substring(binaryName.lastIndexOf('.') + 1);
|
||||
}
|
||||
}
|
||||
87
jdkSrc/jdk8/sun/rmi/server/WeakClassHashMap.java
Normal file
87
jdkSrc/jdk8/sun/rmi/server/WeakClassHashMap.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* Abstract class that maps Class objects to lazily-computed values of
|
||||
* type V. A concrete subclass must implement the computeValue method
|
||||
* to determine how the values are computed.
|
||||
*
|
||||
* The keys are only weakly reachable through this map, so this map
|
||||
* does not prevent a class (along with its class loader, etc.) from
|
||||
* being garbage collected if it is not otherwise strongly reachable.
|
||||
* The values are only softly reachable through this map, so that the
|
||||
* computed values generally persist while not otherwise strongly
|
||||
* reachable, but their storage may be reclaimed if necessary. Also,
|
||||
* note that if a key is strongly reachable from a value, then the key
|
||||
* is effectively softly reachable through this map, which may delay
|
||||
* garbage collection of classes (see 4429536).
|
||||
**/
|
||||
public abstract class WeakClassHashMap<V> {
|
||||
|
||||
private Map<Class<?>,ValueCell<V>> internalMap = new WeakHashMap<>();
|
||||
|
||||
protected WeakClassHashMap() { }
|
||||
|
||||
public V get(Class<?> remoteClass) {
|
||||
/*
|
||||
* Use a mutable cell (a one-element list) to hold the soft
|
||||
* reference to a value, to allow the lazy value computation
|
||||
* to be synchronized with entry-level granularity instead of
|
||||
* by locking the whole table.
|
||||
*/
|
||||
ValueCell<V> valueCell;
|
||||
synchronized (internalMap) {
|
||||
valueCell = internalMap.get(remoteClass);
|
||||
if (valueCell == null) {
|
||||
valueCell = new ValueCell<V>();
|
||||
internalMap.put(remoteClass, valueCell);
|
||||
}
|
||||
}
|
||||
synchronized (valueCell) {
|
||||
V value = null;
|
||||
if (valueCell.ref != null) {
|
||||
value = valueCell.ref.get();
|
||||
}
|
||||
if (value == null) {
|
||||
value = computeValue(remoteClass);
|
||||
valueCell.ref = new SoftReference<V>(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract V computeValue(Class<?> remoteClass);
|
||||
|
||||
private static class ValueCell<T> {
|
||||
Reference<T> ref = null;
|
||||
ValueCell() { }
|
||||
}
|
||||
}
|
||||
50
jdkSrc/jdk8/sun/rmi/transport/Channel.java
Normal file
50
jdkSrc/jdk8/sun/rmi/transport/Channel.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
public interface Channel {
|
||||
|
||||
/**
|
||||
* Generates a new connection to the endpoint of the address space
|
||||
* for which this is a channel.
|
||||
*/
|
||||
public Connection newConnection() throws RemoteException;
|
||||
|
||||
/**
|
||||
* Returns the endpoint of the address space for which this is a
|
||||
* channel.
|
||||
*/
|
||||
public Endpoint getEndpoint();
|
||||
|
||||
/**
|
||||
* Free the connection generated by this channel.
|
||||
* @param c The connection
|
||||
* @param reuse If true, the connection is in a state in which it
|
||||
* can be reused for another method call.
|
||||
*/
|
||||
public void free(Connection conn, boolean reuse) throws RemoteException;
|
||||
}
|
||||
64
jdkSrc/jdk8/sun/rmi/transport/Connection.java
Normal file
64
jdkSrc/jdk8/sun/rmi/transport/Connection.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public interface Connection {
|
||||
/**
|
||||
* Gets the input stream for this connection.
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException;
|
||||
|
||||
/*
|
||||
* Release the input stream for this connection.
|
||||
*/
|
||||
public void releaseInputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* Gets the output stream for this connection
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException;
|
||||
|
||||
/*
|
||||
* Release the output stream for this connection.
|
||||
*/
|
||||
public void releaseOutputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* Return true if channel can be used for multiple operations.
|
||||
*/
|
||||
public boolean isReusable();
|
||||
|
||||
/**
|
||||
* Close connection.
|
||||
*/
|
||||
public void close() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the channel for this connection.
|
||||
*/
|
||||
public Channel getChannel();
|
||||
}
|
||||
166
jdkSrc/jdk8/sun/rmi/transport/ConnectionInputStream.java
Normal file
166
jdkSrc/jdk8/sun/rmi/transport/ConnectionInputStream.java
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.server.UID;
|
||||
import sun.rmi.server.MarshalInputStream;
|
||||
import sun.rmi.runtime.Log;
|
||||
|
||||
/**
|
||||
* Special stream to keep track of refs being unmarshaled so that
|
||||
* refs can be ref-counted locally.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
*/
|
||||
class ConnectionInputStream extends MarshalInputStream {
|
||||
|
||||
/** indicates whether ack is required for DGC */
|
||||
private boolean dgcAckNeeded = false;
|
||||
|
||||
/** Hashtable mapping Endpoints to lists of LiveRefs to register */
|
||||
private Map<Endpoint, List<LiveRef>> incomingRefTable = new HashMap<>(5);
|
||||
|
||||
/** identifier for gc ack*/
|
||||
private UID ackID;
|
||||
|
||||
/**
|
||||
* Constructs a marshal input stream using the underlying
|
||||
* stream "in".
|
||||
*/
|
||||
ConnectionInputStream(InputStream in) throws IOException {
|
||||
super(in);
|
||||
}
|
||||
|
||||
void readID() throws IOException {
|
||||
ackID = UID.read((DataInput) this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save reference in order to send "dirty" call after all args/returns
|
||||
* have been unmarshaled. Save in hashtable incomingRefTable. This
|
||||
* table is keyed on endpoints, and holds objects of type
|
||||
* IncomingRefTableEntry.
|
||||
*/
|
||||
void saveRef(LiveRef ref) {
|
||||
Endpoint ep = ref.getEndpoint();
|
||||
|
||||
// check whether endpoint is already in the hashtable
|
||||
List<LiveRef> refList = incomingRefTable.get(ep);
|
||||
|
||||
if (refList == null) {
|
||||
refList = new ArrayList<LiveRef>();
|
||||
incomingRefTable.put(ep, refList);
|
||||
}
|
||||
|
||||
// add ref to list of refs for endpoint ep
|
||||
refList.add(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discard the saved incoming refs so there is nothing to register
|
||||
* when {@code registerRefs} is called.
|
||||
*/
|
||||
void discardRefs() {
|
||||
incomingRefTable.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add references to DGC table (and possibly send dirty call).
|
||||
* RegisterRefs now calls DGCClient.referenced on all
|
||||
* refs with the same endpoint at once to achieve batching of
|
||||
* calls to the DGC
|
||||
*/
|
||||
void registerRefs() throws IOException {
|
||||
if (!incomingRefTable.isEmpty()) {
|
||||
for (Map.Entry<Endpoint, List<LiveRef>> entry :
|
||||
incomingRefTable.entrySet()) {
|
||||
DGCClient.registerRefs(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that an ack is required to the distributed
|
||||
* collector.
|
||||
*/
|
||||
void setAckNeeded() {
|
||||
dgcAckNeeded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Done with input stream for remote call. Send DGC ack if necessary.
|
||||
* Allow sending of ack to fail without flagging an error.
|
||||
*/
|
||||
void done(Connection c) {
|
||||
/*
|
||||
* WARNING: The connection c may have already been freed. It
|
||||
* is only be safe to use c to obtain c's channel.
|
||||
*/
|
||||
|
||||
if (dgcAckNeeded) {
|
||||
Connection conn = null;
|
||||
Channel ch = null;
|
||||
boolean reuse = true;
|
||||
|
||||
DGCImpl.dgcLog.log(Log.VERBOSE, "send ack");
|
||||
|
||||
try {
|
||||
ch = c.getChannel();
|
||||
conn = ch.newConnection();
|
||||
DataOutputStream out =
|
||||
new DataOutputStream(conn.getOutputStream());
|
||||
out.writeByte(TransportConstants.DGCAck);
|
||||
if (ackID == null) {
|
||||
ackID = new UID();
|
||||
}
|
||||
ackID.write((DataOutput) out);
|
||||
conn.releaseOutputStream();
|
||||
|
||||
/*
|
||||
* Fix for 4221173: if this connection is on top of an
|
||||
* HttpSendSocket, the DGCAck won't actually get sent until a
|
||||
* read operation is attempted on the socket. Calling
|
||||
* available() is the most innocuous way of triggering the
|
||||
* write.
|
||||
*/
|
||||
conn.getInputStream().available();
|
||||
conn.releaseInputStream();
|
||||
} catch (RemoteException e) {
|
||||
reuse = false;
|
||||
} catch (IOException e) {
|
||||
reuse = false;
|
||||
}
|
||||
try {
|
||||
if (conn != null)
|
||||
ch.free(conn, reuse);
|
||||
} catch (RemoteException e){
|
||||
// eat exception
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
109
jdkSrc/jdk8/sun/rmi/transport/ConnectionOutputStream.java
Normal file
109
jdkSrc/jdk8/sun/rmi/transport/ConnectionOutputStream.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.rmi.server.UID;
|
||||
import sun.rmi.server.MarshalOutputStream;
|
||||
|
||||
/**
|
||||
* Special stream to keep track of refs being marshaled as return
|
||||
* results to determine whether a special ack needs to be sent
|
||||
* to the distributed collector.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
*/
|
||||
class ConnectionOutputStream extends MarshalOutputStream {
|
||||
|
||||
/** connection associated with ConnectionOutputStream */
|
||||
private final Connection conn;
|
||||
/** indicates whether output stream is used to marshal results */
|
||||
private final boolean resultStream;
|
||||
/** identifier for gc ack*/
|
||||
private final UID ackID;
|
||||
|
||||
/** to store refs to returned remote object until DGC ack is received */
|
||||
private DGCAckHandler dgcAckHandler = null;
|
||||
|
||||
/**
|
||||
* Constructs an marshal output stream using the underlying
|
||||
* stream associated with the connection, the parameter c.
|
||||
* @param c is the Connection object associated with the
|
||||
* ConnectionOutputStream object being constructed
|
||||
* @param resultStream indicates whether this stream is used
|
||||
* to marshal return results
|
||||
*/
|
||||
ConnectionOutputStream(Connection conn, boolean resultStream)
|
||||
throws IOException
|
||||
{
|
||||
super(conn.getOutputStream());
|
||||
this.conn = conn;
|
||||
this.resultStream = resultStream;
|
||||
ackID = resultStream ? new UID() : null;
|
||||
}
|
||||
|
||||
void writeID() throws IOException {
|
||||
assert resultStream;
|
||||
ackID.write(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this output stream is used to marshal return
|
||||
* results; otherwise returns false.
|
||||
*/
|
||||
boolean isResultStream() {
|
||||
return resultStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a reference to the specified object in this stream's
|
||||
* DGCAckHandler.
|
||||
**/
|
||||
void saveObject(Object obj) {
|
||||
// should always be accessed from same thread
|
||||
if (dgcAckHandler == null) {
|
||||
dgcAckHandler = new DGCAckHandler(ackID);
|
||||
}
|
||||
dgcAckHandler.add(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this stream's DGCAckHandler, or null if it doesn't have
|
||||
* one (saveObject was not invoked). This method should only be
|
||||
* invoked after all objects have been written to the stream,
|
||||
* because future objects written may yet cause a DGCAckHandler to
|
||||
* be created (by invoking saveObject).
|
||||
**/
|
||||
DGCAckHandler getDGCAckHandler() {
|
||||
return dgcAckHandler;
|
||||
}
|
||||
|
||||
void done() {
|
||||
if (dgcAckHandler != null) {
|
||||
dgcAckHandler.startTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
151
jdkSrc/jdk8/sun/rmi/transport/DGCAckHandler.java
Normal file
151
jdkSrc/jdk8/sun/rmi/transport/DGCAckHandler.java
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.rmi.server.UID;
|
||||
import java.security.AccessController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import sun.rmi.runtime.RuntimeUtil;
|
||||
import sun.security.action.GetLongAction;
|
||||
|
||||
/**
|
||||
* Holds strong references to a set of remote objects, or live remote
|
||||
* references to remote objects, after they have been marshalled (as
|
||||
* remote references) as parts of the arguments or the result of a
|
||||
* remote invocation. The purpose is to prevent remote objects or
|
||||
* live remote references that might otherwise be determined to be
|
||||
* unreachable in this VM from being locally garbage collected before
|
||||
* the receiver has had an opportunity to register the unmarshalled
|
||||
* remote references for DGC.
|
||||
*
|
||||
* The references are held strongly until an acknowledgment has been
|
||||
* received that the receiver has had an opportunity to process the
|
||||
* remote references or until a timeout has expired. For remote
|
||||
* references sent as parts of the arguments of a remote invocation,
|
||||
* the acknowledgment is the beginning of the response indicating
|
||||
* completion of the remote invocation. For remote references sent as
|
||||
* parts of the result of a remote invocation, a UID is included as
|
||||
* part of the result, and the acknowledgment is a transport-level
|
||||
* "DGCAck" message containing that UID.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
* @author Peter Jones
|
||||
**/
|
||||
public class DGCAckHandler {
|
||||
|
||||
/** timeout for holding references without receiving an acknowledgment */
|
||||
private static final long dgcAckTimeout = // default 5 minutes
|
||||
AccessController.doPrivileged(
|
||||
new GetLongAction("sun.rmi.dgc.ackTimeout", 300000));
|
||||
|
||||
/** thread pool for scheduling delayed tasks */
|
||||
private static final ScheduledExecutorService scheduler =
|
||||
AccessController.doPrivileged(
|
||||
new RuntimeUtil.GetInstanceAction()).getScheduler();
|
||||
|
||||
/** table mapping ack ID to handler */
|
||||
private static final Map<UID,DGCAckHandler> idTable =
|
||||
Collections.synchronizedMap(new HashMap<UID,DGCAckHandler>());
|
||||
|
||||
private final UID id;
|
||||
private List<Object> objList = new ArrayList<>(); // null if released
|
||||
private Future<?> task = null;
|
||||
|
||||
/**
|
||||
* Creates a new DGCAckHandler, associated with the specified UID
|
||||
* if the argument is not null.
|
||||
*
|
||||
* References added to this DGCAckHandler will be held strongly
|
||||
* until its "release" method is invoked or (after the
|
||||
* "startTimer" method has been invoked) the timeout has expired.
|
||||
* If the argument is not null, then invoking the static
|
||||
* "received" method with the specified UID is equivalent to
|
||||
* invoking this instance's "release" method.
|
||||
**/
|
||||
DGCAckHandler(UID id) {
|
||||
this.id = id;
|
||||
if (id != null) {
|
||||
assert !idTable.containsKey(id);
|
||||
idTable.put(id, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified reference to this DGCAckHandler.
|
||||
**/
|
||||
synchronized void add(Object obj) {
|
||||
if (objList != null) {
|
||||
objList.add(obj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the timer for this DGCAckHandler. After the timeout has
|
||||
* expired, the references are released even if the acknowledgment
|
||||
* has not been received.
|
||||
**/
|
||||
synchronized void startTimer() {
|
||||
if (objList != null && task == null) {
|
||||
task = scheduler.schedule(new Runnable() {
|
||||
public void run() {
|
||||
if (id != null) {
|
||||
idTable.remove(id);
|
||||
}
|
||||
release();
|
||||
}
|
||||
}, dgcAckTimeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the references held by this DGCAckHandler.
|
||||
**/
|
||||
synchronized void release() {
|
||||
if (task != null) {
|
||||
task.cancel(false);
|
||||
task = null;
|
||||
}
|
||||
objList = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes the DGCAckHandler associated with the specified UID to
|
||||
* release its references.
|
||||
**/
|
||||
public static void received(UID id) {
|
||||
DGCAckHandler h = idTable.remove(id);
|
||||
if (h != null) {
|
||||
h.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
841
jdkSrc/jdk8/sun/rmi/transport/DGCClient.java
Normal file
841
jdkSrc/jdk8/sun/rmi/transport/DGCClient.java
Normal file
@@ -0,0 +1,841 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.io.InvalidClassException;
|
||||
import java.lang.ref.PhantomReference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.net.SocketPermission;
|
||||
import java.rmi.UnmarshalException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.rmi.ConnectException;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.dgc.DGC;
|
||||
import java.rmi.dgc.Lease;
|
||||
import java.rmi.dgc.VMID;
|
||||
import java.rmi.server.ObjID;
|
||||
|
||||
import sun.misc.GC;
|
||||
import sun.rmi.runtime.Log;
|
||||
import sun.rmi.runtime.NewThreadAction;
|
||||
import sun.rmi.server.UnicastRef;
|
||||
import sun.rmi.server.Util;
|
||||
import sun.security.action.GetLongAction;
|
||||
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.Permissions;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
/**
|
||||
* DGCClient implements the client-side of the RMI distributed garbage
|
||||
* collection system.
|
||||
*
|
||||
* The external interface to DGCClient is the "registerRefs" method.
|
||||
* When a LiveRef to a remote object enters the VM, it needs to be
|
||||
* registered with the DGCClient to participate in distributed garbage
|
||||
* collection.
|
||||
*
|
||||
* When the first LiveRef to a particular remote object is registered,
|
||||
* a "dirty" call is made to the server-side distributed garbage
|
||||
* collector for the remote object, which returns a lease guaranteeing
|
||||
* that the server-side DGC will not collect the remote object for a
|
||||
* certain period of time. While LiveRef instances to remote objects
|
||||
* on a particular server exist, the DGCClient periodically sends more
|
||||
* "dirty" calls to renew its lease.
|
||||
*
|
||||
* The DGCClient tracks the local reachability of registered LiveRef
|
||||
* instances (using phantom references). When the LiveRef instance
|
||||
* for a particular remote object becomes garbage collected locally,
|
||||
* a "clean" call is made to the server-side distributed garbage
|
||||
* collector, indicating that the server no longer needs to keep the
|
||||
* remote object alive for this client.
|
||||
*
|
||||
* @see java.rmi.dgc.DGC, sun.rmi.transport.DGCImpl
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
* @author Peter Jones
|
||||
*/
|
||||
final class DGCClient {
|
||||
|
||||
/** next sequence number for DGC calls (access synchronized on class) */
|
||||
private static long nextSequenceNum = Long.MIN_VALUE;
|
||||
|
||||
/** unique identifier for this VM as a client of DGC */
|
||||
private static VMID vmid = new VMID();
|
||||
|
||||
/** lease duration to request (usually ignored by server) */
|
||||
private static final long leaseValue = // default 10 minutes
|
||||
AccessController.doPrivileged(
|
||||
new GetLongAction("java.rmi.dgc.leaseValue",
|
||||
600000)).longValue();
|
||||
|
||||
/** maximum interval between retries of failed clean calls */
|
||||
private static final long cleanInterval = // default 3 minutes
|
||||
AccessController.doPrivileged(
|
||||
new GetLongAction("sun.rmi.dgc.cleanInterval",
|
||||
180000)).longValue();
|
||||
|
||||
/** maximum interval between complete garbage collections of local heap */
|
||||
private static final long gcInterval = // default 1 hour
|
||||
AccessController.doPrivileged(
|
||||
new GetLongAction("sun.rmi.dgc.client.gcInterval",
|
||||
3600000)).longValue();
|
||||
|
||||
/** minimum retry count for dirty calls that fail */
|
||||
private static final int dirtyFailureRetries = 5;
|
||||
|
||||
/** retry count for clean calls that fail with ConnectException */
|
||||
private static final int cleanFailureRetries = 5;
|
||||
|
||||
/** constant empty ObjID array for lease renewal optimization */
|
||||
private static final ObjID[] emptyObjIDArray = new ObjID[0];
|
||||
|
||||
/** ObjID for server-side DGC object */
|
||||
private static final ObjID dgcID = new ObjID(ObjID.DGC_ID);
|
||||
|
||||
/**
|
||||
* An AccessControlContext with only socket permissions,
|
||||
* suitable for an RMIClientSocketFactory.
|
||||
*/
|
||||
private static final AccessControlContext SOCKET_ACC;
|
||||
static {
|
||||
Permissions perms = new Permissions();
|
||||
perms.add(new SocketPermission("*", "connect,resolve"));
|
||||
ProtectionDomain[] pd = { new ProtectionDomain(null, perms) };
|
||||
SOCKET_ACC = new AccessControlContext(pd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disallow anyone from creating one of these.
|
||||
*/
|
||||
private DGCClient() {}
|
||||
|
||||
/**
|
||||
* Register the LiveRef instances in the supplied list to participate
|
||||
* in distributed garbage collection.
|
||||
*
|
||||
* All of the LiveRefs in the list must be for remote objects at the
|
||||
* given endpoint.
|
||||
*/
|
||||
static void registerRefs(Endpoint ep, List<LiveRef> refs) {
|
||||
/*
|
||||
* Look up the given endpoint and register the refs with it.
|
||||
* The retrieved entry may get removed from the global endpoint
|
||||
* table before EndpointEntry.registerRefs() is able to acquire
|
||||
* its lock; in this event, it returns false, and we loop and
|
||||
* try again.
|
||||
*/
|
||||
EndpointEntry epEntry;
|
||||
do {
|
||||
epEntry = EndpointEntry.lookup(ep);
|
||||
} while (!epEntry.registerRefs(refs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next sequence number to be used for a dirty or clean
|
||||
* operation from this VM. This method should only be called while
|
||||
* synchronized on the EndpointEntry whose data structures the
|
||||
* operation affects.
|
||||
*/
|
||||
private static synchronized long getNextSequenceNum() {
|
||||
return nextSequenceNum++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the length of a lease and the time that it was granted,
|
||||
* compute the absolute time at which it should be renewed, giving
|
||||
* room for reasonable computational and communication delays.
|
||||
*/
|
||||
private static long computeRenewTime(long grantTime, long duration) {
|
||||
/*
|
||||
* REMIND: This algorithm should be more sophisticated, waiting
|
||||
* a longer fraction of the lease duration for longer leases.
|
||||
*/
|
||||
return grantTime + (duration / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* EndpointEntry encapsulates the client-side DGC information specific
|
||||
* to a particular Endpoint. Of most significance is the table that
|
||||
* maps LiveRef value to RefEntry objects and the renew/clean thread
|
||||
* that handles asynchronous client-side DGC operations.
|
||||
*/
|
||||
private static class EndpointEntry {
|
||||
|
||||
/** the endpoint that this entry is for */
|
||||
private Endpoint endpoint;
|
||||
/** synthesized reference to the remote server-side DGC */
|
||||
private DGC dgc;
|
||||
|
||||
/** table of refs held for endpoint: maps LiveRef to RefEntry */
|
||||
private Map<LiveRef, RefEntry> refTable = new HashMap<>(5);
|
||||
/** set of RefEntry instances from last (failed) dirty call */
|
||||
private Set<RefEntry> invalidRefs = new HashSet<>(5);
|
||||
|
||||
/** true if this entry has been removed from the global table */
|
||||
private boolean removed = false;
|
||||
|
||||
/** absolute time to renew current lease to this endpoint */
|
||||
private long renewTime = Long.MAX_VALUE;
|
||||
/** absolute time current lease to this endpoint will expire */
|
||||
private long expirationTime = Long.MIN_VALUE;
|
||||
/** count of recent dirty calls that have failed */
|
||||
private int dirtyFailures = 0;
|
||||
/** absolute time of first recent failed dirty call */
|
||||
private long dirtyFailureStartTime;
|
||||
/** (average) elapsed time for recent failed dirty calls */
|
||||
private long dirtyFailureDuration;
|
||||
|
||||
/** renew/clean thread for handling lease renewals and clean calls */
|
||||
private Thread renewCleanThread;
|
||||
/** true if renew/clean thread may be interrupted */
|
||||
private boolean interruptible = false;
|
||||
|
||||
/** reference queue for phantom references */
|
||||
private ReferenceQueue<LiveRef> refQueue = new ReferenceQueue<>();
|
||||
/** set of clean calls that need to be made */
|
||||
private Set<CleanRequest> pendingCleans = new HashSet<>(5);
|
||||
|
||||
/** global endpoint table: maps Endpoint to EndpointEntry */
|
||||
private static Map<Endpoint,EndpointEntry> endpointTable = new HashMap<>(5);
|
||||
/** handle for GC latency request (for future cancellation) */
|
||||
private static GC.LatencyRequest gcLatencyRequest = null;
|
||||
|
||||
/**
|
||||
* Look up the EndpointEntry for the given Endpoint. An entry is
|
||||
* created if one does not already exist.
|
||||
*/
|
||||
public static EndpointEntry lookup(Endpoint ep) {
|
||||
synchronized (endpointTable) {
|
||||
EndpointEntry entry = endpointTable.get(ep);
|
||||
if (entry == null) {
|
||||
entry = new EndpointEntry(ep);
|
||||
endpointTable.put(ep, entry);
|
||||
/*
|
||||
* While we are tracking live remote references registered
|
||||
* in this VM, request a maximum latency for inspecting the
|
||||
* entire heap from the local garbage collector, to place
|
||||
* an upper bound on the time to discover remote references
|
||||
* that have become unreachable (see bugid 4171278).
|
||||
*/
|
||||
if (gcLatencyRequest == null) {
|
||||
gcLatencyRequest = GC.requestLatency(gcInterval);
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
private EndpointEntry(final Endpoint endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
try {
|
||||
LiveRef dgcRef = new LiveRef(dgcID, endpoint, false);
|
||||
dgc = (DGC) Util.createProxy(DGCImpl.class,
|
||||
new UnicastRef(dgcRef), true);
|
||||
} catch (RemoteException e) {
|
||||
throw new Error("internal error creating DGC stub");
|
||||
}
|
||||
renewCleanThread = AccessController.doPrivileged(
|
||||
new NewThreadAction(new RenewCleanThread(),
|
||||
"RenewClean-" + endpoint, true));
|
||||
renewCleanThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the LiveRef instances in the supplied list to participate
|
||||
* in distributed garbage collection.
|
||||
*
|
||||
* This method returns false if this entry was removed from the
|
||||
* global endpoint table (because it was empty) before these refs
|
||||
* could be registered. In that case, a new EndpointEntry needs
|
||||
* to be looked up.
|
||||
*
|
||||
* This method must NOT be called while synchronized on this entry.
|
||||
*/
|
||||
public boolean registerRefs(List<LiveRef> refs) {
|
||||
assert !Thread.holdsLock(this);
|
||||
|
||||
Set<RefEntry> refsToDirty = null; // entries for refs needing dirty
|
||||
long sequenceNum; // sequence number for dirty call
|
||||
|
||||
synchronized (this) {
|
||||
if (removed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Iterator<LiveRef> iter = refs.iterator();
|
||||
while (iter.hasNext()) {
|
||||
LiveRef ref = iter.next();
|
||||
assert ref.getEndpoint().equals(endpoint);
|
||||
|
||||
RefEntry refEntry = refTable.get(ref);
|
||||
if (refEntry == null) {
|
||||
LiveRef refClone = (LiveRef) ref.clone();
|
||||
refEntry = new RefEntry(refClone);
|
||||
refTable.put(refClone, refEntry);
|
||||
if (refsToDirty == null) {
|
||||
refsToDirty = new HashSet<>(5);
|
||||
}
|
||||
refsToDirty.add(refEntry);
|
||||
}
|
||||
|
||||
refEntry.addInstanceToRefSet(ref);
|
||||
}
|
||||
|
||||
if (refsToDirty == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
refsToDirty.addAll(invalidRefs);
|
||||
invalidRefs.clear();
|
||||
|
||||
sequenceNum = getNextSequenceNum();
|
||||
}
|
||||
|
||||
makeDirtyCall(refsToDirty, sequenceNum);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given RefEntry from the ref table. If that makes
|
||||
* the ref table empty, remove this entry from the global endpoint
|
||||
* table.
|
||||
*
|
||||
* This method must ONLY be called while synchronized on this entry.
|
||||
*/
|
||||
private void removeRefEntry(RefEntry refEntry) {
|
||||
assert Thread.holdsLock(this);
|
||||
assert !removed;
|
||||
assert refTable.containsKey(refEntry.getRef());
|
||||
|
||||
refTable.remove(refEntry.getRef());
|
||||
invalidRefs.remove(refEntry);
|
||||
if (refTable.isEmpty()) {
|
||||
synchronized (endpointTable) {
|
||||
endpointTable.remove(endpoint);
|
||||
Transport transport = endpoint.getOutboundTransport();
|
||||
transport.free(endpoint);
|
||||
/*
|
||||
* If there are no longer any live remote references
|
||||
* registered, we are no longer concerned with the
|
||||
* latency of local garbage collection here.
|
||||
*/
|
||||
if (endpointTable.isEmpty()) {
|
||||
assert gcLatencyRequest != null;
|
||||
gcLatencyRequest.cancel();
|
||||
gcLatencyRequest = null;
|
||||
}
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a DGC dirty call to this entry's endpoint, for the ObjIDs
|
||||
* corresponding to the given set of refs and with the given
|
||||
* sequence number.
|
||||
*
|
||||
* This method must NOT be called while synchronized on this entry.
|
||||
*/
|
||||
private void makeDirtyCall(Set<RefEntry> refEntries, long sequenceNum) {
|
||||
assert !Thread.holdsLock(this);
|
||||
|
||||
ObjID[] ids;
|
||||
if (refEntries != null) {
|
||||
ids = createObjIDArray(refEntries);
|
||||
} else {
|
||||
ids = emptyObjIDArray;
|
||||
}
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
Lease lease =
|
||||
dgc.dirty(ids, sequenceNum, new Lease(vmid, leaseValue));
|
||||
long duration = lease.getValue();
|
||||
|
||||
long newRenewTime = computeRenewTime(startTime, duration);
|
||||
long newExpirationTime = startTime + duration;
|
||||
|
||||
synchronized (this) {
|
||||
dirtyFailures = 0;
|
||||
setRenewTime(newRenewTime);
|
||||
expirationTime = newExpirationTime;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
long endTime = System.currentTimeMillis();
|
||||
|
||||
synchronized (this) {
|
||||
dirtyFailures++;
|
||||
|
||||
if (e instanceof UnmarshalException
|
||||
&& e.getCause() instanceof InvalidClassException) {
|
||||
DGCImpl.dgcLog.log(Log.BRIEF, "InvalidClassException exception in DGC dirty call", e);
|
||||
return; // protocol error, do not register these refs
|
||||
}
|
||||
|
||||
if (dirtyFailures == 1) {
|
||||
/*
|
||||
* If this was the first recent failed dirty call,
|
||||
* reschedule another one immediately, in case there
|
||||
* was just a transient network problem, and remember
|
||||
* the start time and duration of this attempt for
|
||||
* future calculations of the delays between retries.
|
||||
*/
|
||||
dirtyFailureStartTime = startTime;
|
||||
dirtyFailureDuration = endTime - startTime;
|
||||
setRenewTime(endTime);
|
||||
} else {
|
||||
/*
|
||||
* For each successive failed dirty call, wait for a
|
||||
* (binary) exponentially increasing delay before
|
||||
* retrying, to avoid network congestion.
|
||||
*/
|
||||
int n = dirtyFailures - 2;
|
||||
if (n == 0) {
|
||||
/*
|
||||
* Calculate the initial retry delay from the
|
||||
* average time elapsed for each of the first
|
||||
* two failed dirty calls. The result must be
|
||||
* at least 1000ms, to prevent a tight loop.
|
||||
*/
|
||||
dirtyFailureDuration =
|
||||
Math.max((dirtyFailureDuration +
|
||||
(endTime - startTime)) >> 1, 1000);
|
||||
}
|
||||
long newRenewTime =
|
||||
endTime + (dirtyFailureDuration << n);
|
||||
|
||||
/*
|
||||
* Continue if the last known held lease has not
|
||||
* expired, or else at least a fixed number of times,
|
||||
* or at least until we've tried for a fixed amount
|
||||
* of time (the default lease value we request).
|
||||
*/
|
||||
if (newRenewTime < expirationTime ||
|
||||
dirtyFailures < dirtyFailureRetries ||
|
||||
newRenewTime < dirtyFailureStartTime + leaseValue)
|
||||
{
|
||||
setRenewTime(newRenewTime);
|
||||
} else {
|
||||
/*
|
||||
* Give up: postpone lease renewals until next
|
||||
* ref is registered for this endpoint.
|
||||
*/
|
||||
setRenewTime(Long.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
if (refEntries != null) {
|
||||
/*
|
||||
* Add all of these refs to the set of refs for this
|
||||
* endpoint that may be invalid (this VM may not be in
|
||||
* the server's referenced set), so that we will
|
||||
* attempt to explicitly dirty them again in the
|
||||
* future.
|
||||
*/
|
||||
invalidRefs.addAll(refEntries);
|
||||
|
||||
/*
|
||||
* Record that a dirty call has failed for all of these
|
||||
* refs, so that clean calls for them in the future
|
||||
* will be strong.
|
||||
*/
|
||||
Iterator<RefEntry> iter = refEntries.iterator();
|
||||
while (iter.hasNext()) {
|
||||
RefEntry refEntry = iter.next();
|
||||
refEntry.markDirtyFailed();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the last known held lease will have expired before
|
||||
* the next renewal, all refs might be invalid.
|
||||
*/
|
||||
if (renewTime >= expirationTime) {
|
||||
invalidRefs.addAll(refTable.values());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the absolute time at which the lease for this entry should
|
||||
* be renewed.
|
||||
*
|
||||
* This method must ONLY be called while synchronized on this entry.
|
||||
*/
|
||||
private void setRenewTime(long newRenewTime) {
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
if (newRenewTime < renewTime) {
|
||||
renewTime = newRenewTime;
|
||||
if (interruptible) {
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
renewCleanThread.interrupt();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
renewTime = newRenewTime;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RenewCleanThread handles the asynchronous client-side DGC activity
|
||||
* for this entry: renewing the leases and making clean calls.
|
||||
*/
|
||||
private class RenewCleanThread implements Runnable {
|
||||
|
||||
public void run() {
|
||||
do {
|
||||
long timeToWait;
|
||||
RefEntry.PhantomLiveRef phantom = null;
|
||||
boolean needRenewal = false;
|
||||
Set<RefEntry> refsToDirty = null;
|
||||
long sequenceNum = Long.MIN_VALUE;
|
||||
|
||||
synchronized (EndpointEntry.this) {
|
||||
/*
|
||||
* Calculate time to block (waiting for phantom
|
||||
* reference notifications). It is the time until the
|
||||
* lease renewal should be done, bounded on the low
|
||||
* end by 1 ms so that the reference queue will always
|
||||
* get processed, and if there are pending clean
|
||||
* requests (remaining because some clean calls
|
||||
* failed), bounded on the high end by the maximum
|
||||
* clean call retry interval.
|
||||
*/
|
||||
long timeUntilRenew =
|
||||
renewTime - System.currentTimeMillis();
|
||||
timeToWait = Math.max(timeUntilRenew, 1);
|
||||
if (!pendingCleans.isEmpty()) {
|
||||
timeToWait = Math.min(timeToWait, cleanInterval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set flag indicating that it is OK to interrupt this
|
||||
* thread now, such as if a earlier lease renewal time
|
||||
* is set, because we are only going to be blocking
|
||||
* and can deal with interrupts.
|
||||
*/
|
||||
interruptible = true;
|
||||
}
|
||||
|
||||
try {
|
||||
/*
|
||||
* Wait for the duration calculated above for any of
|
||||
* our phantom references to be enqueued.
|
||||
*/
|
||||
phantom = (RefEntry.PhantomLiveRef)
|
||||
refQueue.remove(timeToWait);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
synchronized (EndpointEntry.this) {
|
||||
/*
|
||||
* Set flag indicating that it is NOT OK to interrupt
|
||||
* this thread now, because we may be undertaking I/O
|
||||
* operations that should not be interrupted (and we
|
||||
* will not be blocking arbitrarily).
|
||||
*/
|
||||
interruptible = false;
|
||||
Thread.interrupted(); // clear interrupted state
|
||||
|
||||
/*
|
||||
* If there was a phantom reference enqueued, process
|
||||
* it and all the rest on the queue, generating
|
||||
* clean requests as necessary.
|
||||
*/
|
||||
if (phantom != null) {
|
||||
processPhantomRefs(phantom);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if it is time to renew this entry's lease.
|
||||
*/
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (currentTime > renewTime) {
|
||||
needRenewal = true;
|
||||
if (!invalidRefs.isEmpty()) {
|
||||
refsToDirty = invalidRefs;
|
||||
invalidRefs = new HashSet<>(5);
|
||||
}
|
||||
sequenceNum = getNextSequenceNum();
|
||||
}
|
||||
}
|
||||
|
||||
boolean needRenewal_ = needRenewal;
|
||||
Set<RefEntry> refsToDirty_ = refsToDirty;
|
||||
long sequenceNum_ = sequenceNum;
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
if (needRenewal_) {
|
||||
makeDirtyCall(refsToDirty_, sequenceNum_);
|
||||
}
|
||||
|
||||
if (!pendingCleans.isEmpty()) {
|
||||
makeCleanCalls();
|
||||
}
|
||||
return null;
|
||||
}}, SOCKET_ACC);
|
||||
} while (!removed || !pendingCleans.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the notification of the given phantom reference and any
|
||||
* others that are on this entry's reference queue. Each phantom
|
||||
* reference is removed from its RefEntry's ref set. All ref
|
||||
* entries that have no more registered instances are collected
|
||||
* into up to two batched clean call requests: one for refs
|
||||
* requiring a "strong" clean call, and one for the rest.
|
||||
*
|
||||
* This method must ONLY be called while synchronized on this entry.
|
||||
*/
|
||||
private void processPhantomRefs(RefEntry.PhantomLiveRef phantom) {
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
Set<RefEntry> strongCleans = null;
|
||||
Set<RefEntry> normalCleans = null;
|
||||
|
||||
do {
|
||||
RefEntry refEntry = phantom.getRefEntry();
|
||||
refEntry.removeInstanceFromRefSet(phantom);
|
||||
if (refEntry.isRefSetEmpty()) {
|
||||
if (refEntry.hasDirtyFailed()) {
|
||||
if (strongCleans == null) {
|
||||
strongCleans = new HashSet<>(5);
|
||||
}
|
||||
strongCleans.add(refEntry);
|
||||
} else {
|
||||
if (normalCleans == null) {
|
||||
normalCleans = new HashSet<>(5);
|
||||
}
|
||||
normalCleans.add(refEntry);
|
||||
}
|
||||
removeRefEntry(refEntry);
|
||||
}
|
||||
} while ((phantom =
|
||||
(RefEntry.PhantomLiveRef) refQueue.poll()) != null);
|
||||
|
||||
if (strongCleans != null) {
|
||||
pendingCleans.add(
|
||||
new CleanRequest(createObjIDArray(strongCleans),
|
||||
getNextSequenceNum(), true));
|
||||
}
|
||||
if (normalCleans != null) {
|
||||
pendingCleans.add(
|
||||
new CleanRequest(createObjIDArray(normalCleans),
|
||||
getNextSequenceNum(), false));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CleanRequest holds the data for the parameters of a clean call
|
||||
* that needs to be made.
|
||||
*/
|
||||
private static class CleanRequest {
|
||||
|
||||
final ObjID[] objIDs;
|
||||
final long sequenceNum;
|
||||
final boolean strong;
|
||||
|
||||
/** how many times this request has failed */
|
||||
int failures = 0;
|
||||
|
||||
CleanRequest(ObjID[] objIDs, long sequenceNum, boolean strong) {
|
||||
this.objIDs = objIDs;
|
||||
this.sequenceNum = sequenceNum;
|
||||
this.strong = strong;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make all of the clean calls described by the clean requests in
|
||||
* this entry's set of "pending cleans". Clean requests for clean
|
||||
* calls that succeed are removed from the "pending cleans" set.
|
||||
*
|
||||
* This method must NOT be called while synchronized on this entry.
|
||||
*/
|
||||
private void makeCleanCalls() {
|
||||
assert !Thread.holdsLock(this);
|
||||
|
||||
Iterator<CleanRequest> iter = pendingCleans.iterator();
|
||||
while (iter.hasNext()) {
|
||||
CleanRequest request = iter.next();
|
||||
try {
|
||||
dgc.clean(request.objIDs, request.sequenceNum, vmid,
|
||||
request.strong);
|
||||
iter.remove();
|
||||
} catch (Exception e) {
|
||||
/*
|
||||
* Many types of exceptions here could have been
|
||||
* caused by a transient failure, so try again a
|
||||
* few times, but not forever.
|
||||
*/
|
||||
if (++request.failures >= cleanFailureRetries) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an array of ObjIDs (needed for the DGC remote calls)
|
||||
* from the ids in the given set of refs.
|
||||
*/
|
||||
private static ObjID[] createObjIDArray(Set<RefEntry> refEntries) {
|
||||
ObjID[] ids = new ObjID[refEntries.size()];
|
||||
Iterator<RefEntry> iter = refEntries.iterator();
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
ids[i] = iter.next().getRef().getObjID();
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* RefEntry encapsulates the client-side DGC information specific
|
||||
* to a particular LiveRef value. In particular, it contains a
|
||||
* set of phantom references to all of the instances of the LiveRef
|
||||
* value registered in the system (but not garbage collected
|
||||
* locally).
|
||||
*/
|
||||
private class RefEntry {
|
||||
|
||||
/** LiveRef value for this entry (not a registered instance) */
|
||||
private LiveRef ref;
|
||||
/** set of phantom references to registered instances */
|
||||
private Set<PhantomLiveRef> refSet = new HashSet<>(5);
|
||||
/** true if a dirty call containing this ref has failed */
|
||||
private boolean dirtyFailed = false;
|
||||
|
||||
public RefEntry(LiveRef ref) {
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the LiveRef value for this entry (not a registered
|
||||
* instance).
|
||||
*/
|
||||
public LiveRef getRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a LiveRef to the set of registered instances for this entry.
|
||||
*
|
||||
* This method must ONLY be invoked while synchronized on this
|
||||
* RefEntry's EndpointEntry.
|
||||
*/
|
||||
public void addInstanceToRefSet(LiveRef ref) {
|
||||
assert Thread.holdsLock(EndpointEntry.this);
|
||||
assert ref.equals(this.ref);
|
||||
|
||||
/*
|
||||
* Only keep a phantom reference to the registered instance,
|
||||
* so that it can be garbage collected normally (and we can be
|
||||
* notified when that happens).
|
||||
*/
|
||||
refSet.add(new PhantomLiveRef(ref));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a PhantomLiveRef from the set of registered instances.
|
||||
*
|
||||
* This method must ONLY be invoked while synchronized on this
|
||||
* RefEntry's EndpointEntry.
|
||||
*/
|
||||
public void removeInstanceFromRefSet(PhantomLiveRef phantom) {
|
||||
assert Thread.holdsLock(EndpointEntry.this);
|
||||
assert refSet.contains(phantom);
|
||||
refSet.remove(phantom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no registered LiveRef instances for
|
||||
* this entry still reachable in this VM.
|
||||
*
|
||||
* This method must ONLY be invoked while synchronized on this
|
||||
* RefEntry's EndpointEntry.
|
||||
*/
|
||||
public boolean isRefSetEmpty() {
|
||||
assert Thread.holdsLock(EndpointEntry.this);
|
||||
return refSet.size() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that a dirty call that explicitly contained this
|
||||
* entry's ref has failed.
|
||||
*
|
||||
* This method must ONLY be invoked while synchronized on this
|
||||
* RefEntry's EndpointEntry.
|
||||
*/
|
||||
public void markDirtyFailed() {
|
||||
assert Thread.holdsLock(EndpointEntry.this);
|
||||
dirtyFailed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a dirty call that explicitly contained this
|
||||
* entry's ref has failed (and therefore a clean call for this
|
||||
* ref needs to be marked "strong").
|
||||
*
|
||||
* This method must ONLY be invoked while synchronized on this
|
||||
* RefEntry's EndpointEntry.
|
||||
*/
|
||||
public boolean hasDirtyFailed() {
|
||||
assert Thread.holdsLock(EndpointEntry.this);
|
||||
return dirtyFailed;
|
||||
}
|
||||
|
||||
/**
|
||||
* PhantomLiveRef is a PhantomReference to a LiveRef instance,
|
||||
* used to detect when the LiveRef becomes permanently
|
||||
* unreachable in this VM.
|
||||
*/
|
||||
private class PhantomLiveRef extends PhantomReference<LiveRef> {
|
||||
|
||||
public PhantomLiveRef(LiveRef ref) {
|
||||
super(ref, EndpointEntry.this.refQueue);
|
||||
}
|
||||
|
||||
public RefEntry getRefEntry() {
|
||||
return RefEntry.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
448
jdkSrc/jdk8/sun/rmi/transport/DGCImpl.java
Normal file
448
jdkSrc/jdk8/sun/rmi/transport/DGCImpl.java
Normal file
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.net.SocketPermission;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.dgc.DGC;
|
||||
import java.rmi.dgc.Lease;
|
||||
import java.rmi.dgc.VMID;
|
||||
import java.rmi.server.LogStream;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.RemoteServer;
|
||||
import java.rmi.server.ServerNotActiveException;
|
||||
import java.rmi.server.UID;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.Permissions;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.Security;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import sun.misc.ObjectInputFilter;
|
||||
|
||||
import sun.rmi.runtime.Log;
|
||||
import sun.rmi.runtime.RuntimeUtil;
|
||||
import sun.rmi.server.UnicastRef;
|
||||
import sun.rmi.server.UnicastServerRef;
|
||||
import sun.rmi.server.Util;
|
||||
import sun.security.action.GetLongAction;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* This class implements the guts of the server-side distributed GC
|
||||
* algorithm
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
final class DGCImpl implements DGC {
|
||||
|
||||
/* dgc system log */
|
||||
static final Log dgcLog = Log.getLog("sun.rmi.dgc", "dgc",
|
||||
LogStream.parseLevel(AccessController.doPrivileged(
|
||||
new GetPropertyAction("sun.rmi.dgc.logLevel"))));
|
||||
|
||||
/** lease duration to grant to clients */
|
||||
private static final long leaseValue = // default 10 minutes
|
||||
AccessController.doPrivileged(
|
||||
new GetLongAction("java.rmi.dgc.leaseValue", 600000));
|
||||
|
||||
/** lease check interval; default is half of lease grant duration */
|
||||
private static final long leaseCheckInterval =
|
||||
AccessController.doPrivileged(
|
||||
new GetLongAction("sun.rmi.dgc.checkInterval", leaseValue / 2));
|
||||
|
||||
/** thread pool for scheduling delayed tasks */
|
||||
private static final ScheduledExecutorService scheduler =
|
||||
AccessController.doPrivileged(
|
||||
new RuntimeUtil.GetInstanceAction()).getScheduler();
|
||||
|
||||
/** remote implementation of DGC interface for this VM */
|
||||
private static DGCImpl dgc;
|
||||
/** table that maps VMID to LeaseInfo */
|
||||
private Map<VMID,LeaseInfo> leaseTable = new HashMap<>();
|
||||
/** checks for lease expiration */
|
||||
private Future<?> checker = null;
|
||||
|
||||
/**
|
||||
* Return the remote implementation of the DGC interface for
|
||||
* this VM.
|
||||
*/
|
||||
static DGCImpl getDGCImpl() {
|
||||
return dgc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property name of the DGC serial filter to augment
|
||||
* the built-in list of allowed types.
|
||||
* Setting the property in the {@code lib/security/java.security} file
|
||||
* will enable the augmented filter.
|
||||
*/
|
||||
private static final String DGC_FILTER_PROPNAME = "sun.rmi.transport.dgcFilter";
|
||||
|
||||
/** Registry max depth of remote invocations. **/
|
||||
private static int DGC_MAX_DEPTH = 5;
|
||||
|
||||
/** Registry maximum array size in remote invocations. **/
|
||||
private static int DGC_MAX_ARRAY_SIZE = 10000;
|
||||
/**
|
||||
* The dgcFilter created from the value of the {@code "sun.rmi.transport.dgcFilter"}
|
||||
* property.
|
||||
*/
|
||||
private static final ObjectInputFilter dgcFilter =
|
||||
AccessController.doPrivileged((PrivilegedAction<ObjectInputFilter>)DGCImpl::initDgcFilter);
|
||||
|
||||
/**
|
||||
* Initialize the dgcFilter from the security properties or system property; if any
|
||||
* @return an ObjectInputFilter, or null
|
||||
*/
|
||||
private static ObjectInputFilter initDgcFilter() {
|
||||
ObjectInputFilter filter = null;
|
||||
String props = System.getProperty(DGC_FILTER_PROPNAME);
|
||||
if (props == null) {
|
||||
props = Security.getProperty(DGC_FILTER_PROPNAME);
|
||||
}
|
||||
if (props != null) {
|
||||
filter = ObjectInputFilter.Config.createFilter(props);
|
||||
if (dgcLog.isLoggable(Log.BRIEF)) {
|
||||
dgcLog.log(Log.BRIEF, "dgcFilter = " + filter);
|
||||
}
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new server-side remote object collector at
|
||||
* a particular port. Disallow construction from outside.
|
||||
*/
|
||||
private DGCImpl() {}
|
||||
|
||||
/**
|
||||
* The dirty call adds the VMID "vmid" to the set of clients
|
||||
* that hold references to the object associated with the ObjID
|
||||
* id. The long "sequenceNum" is used to detect late dirty calls. If
|
||||
* the VMID "vmid" is null, a VMID will be generated on the
|
||||
* server (for use by the client in subsequent calls) and
|
||||
* returned.
|
||||
*
|
||||
* The client must call the "dirty" method to renew the lease
|
||||
* before the "lease" time expires or all references to remote
|
||||
* objects in this VM that the client holds are considered
|
||||
* "unreferenced".
|
||||
*/
|
||||
public Lease dirty(ObjID[] ids, long sequenceNum, Lease lease) {
|
||||
VMID vmid = lease.getVMID();
|
||||
/*
|
||||
* The server specifies the lease value; the client has
|
||||
* no say in the matter.
|
||||
*/
|
||||
long duration = leaseValue;
|
||||
|
||||
if (dgcLog.isLoggable(Log.VERBOSE)) {
|
||||
dgcLog.log(Log.VERBOSE, "vmid = " + vmid);
|
||||
}
|
||||
|
||||
// create a VMID if one wasn't supplied
|
||||
if (vmid == null) {
|
||||
vmid = new VMID();
|
||||
|
||||
if (dgcLog.isLoggable(Log.BRIEF)) {
|
||||
String clientHost;
|
||||
try {
|
||||
clientHost = RemoteServer.getClientHost();
|
||||
} catch (ServerNotActiveException e) {
|
||||
clientHost = "<unknown host>";
|
||||
}
|
||||
dgcLog.log(Log.BRIEF, " assigning vmid " + vmid +
|
||||
" to client " + clientHost);
|
||||
}
|
||||
}
|
||||
|
||||
lease = new Lease(vmid, duration);
|
||||
// record lease information
|
||||
synchronized (leaseTable) {
|
||||
LeaseInfo info = leaseTable.get(vmid);
|
||||
if (info == null) {
|
||||
leaseTable.put(vmid, new LeaseInfo(vmid, duration));
|
||||
if (checker == null) {
|
||||
checker = scheduler.scheduleWithFixedDelay(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
checkLeases();
|
||||
}
|
||||
},
|
||||
leaseCheckInterval,
|
||||
leaseCheckInterval, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
} else {
|
||||
info.renew(duration);
|
||||
}
|
||||
}
|
||||
|
||||
for (ObjID id : ids) {
|
||||
if (dgcLog.isLoggable(Log.VERBOSE)) {
|
||||
dgcLog.log(Log.VERBOSE, "id = " + id +
|
||||
", vmid = " + vmid + ", duration = " + duration);
|
||||
}
|
||||
|
||||
ObjectTable.referenced(id, sequenceNum, vmid);
|
||||
}
|
||||
|
||||
// return the VMID used
|
||||
return lease;
|
||||
}
|
||||
|
||||
/**
|
||||
* The clean call removes the VMID from the set of clients
|
||||
* that hold references to the object associated with the LiveRef
|
||||
* ref. The sequence number is used to detect late clean calls. If the
|
||||
* argument "strong" is true, then the clean call is a result of a
|
||||
* failed "dirty" call, thus the sequence number for the VMID needs
|
||||
* to be remembered until the client goes away.
|
||||
*/
|
||||
public void clean(ObjID[] ids, long sequenceNum, VMID vmid, boolean strong)
|
||||
{
|
||||
for (ObjID id : ids) {
|
||||
if (dgcLog.isLoggable(Log.VERBOSE)) {
|
||||
dgcLog.log(Log.VERBOSE, "id = " + id +
|
||||
", vmid = " + vmid + ", strong = " + strong);
|
||||
}
|
||||
|
||||
ObjectTable.unreferenced(id, sequenceNum, vmid, strong);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register interest in receiving a callback when this VMID
|
||||
* becomes inaccessible.
|
||||
*/
|
||||
void registerTarget(VMID vmid, Target target) {
|
||||
synchronized (leaseTable) {
|
||||
LeaseInfo info = leaseTable.get(vmid);
|
||||
if (info == null) {
|
||||
target.vmidDead(vmid);
|
||||
} else {
|
||||
info.notifySet.add(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove notification request.
|
||||
*/
|
||||
void unregisterTarget(VMID vmid, Target target) {
|
||||
synchronized (leaseTable) {
|
||||
LeaseInfo info = leaseTable.get(vmid);
|
||||
if (info != null) {
|
||||
info.notifySet.remove(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if leases have expired. If a lease has expired, remove
|
||||
* it from the table and notify all interested parties that the
|
||||
* VMID is essentially "dead".
|
||||
*
|
||||
* @return if true, there are leases outstanding; otherwise leases
|
||||
* no longer need to be checked
|
||||
*/
|
||||
private void checkLeases() {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
/* List of vmids that need to be removed from the leaseTable */
|
||||
List<LeaseInfo> toUnregister = new ArrayList<>();
|
||||
|
||||
/* Build a list of leaseInfo objects that need to have
|
||||
* targets removed from their notifySet. Remove expired
|
||||
* leases from leaseTable.
|
||||
*/
|
||||
synchronized (leaseTable) {
|
||||
Iterator<LeaseInfo> iter = leaseTable.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
LeaseInfo info = iter.next();
|
||||
if (info.expired(time)) {
|
||||
toUnregister.add(info);
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (leaseTable.isEmpty()) {
|
||||
checker.cancel(false);
|
||||
checker = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* Notify and unegister targets without holding the lock on
|
||||
* the leaseTable so we avoid deadlock.
|
||||
*/
|
||||
for (LeaseInfo info : toUnregister) {
|
||||
for (Target target : info.notifySet) {
|
||||
target.vmidDead(info.vmid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
/*
|
||||
* "Export" the singleton DGCImpl in a context isolated from
|
||||
* the arbitrary current thread context.
|
||||
*/
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
ClassLoader savedCcl =
|
||||
Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
Thread.currentThread().setContextClassLoader(
|
||||
ClassLoader.getSystemClassLoader());
|
||||
|
||||
/*
|
||||
* Put remote collector object in table by hand to prevent
|
||||
* listen on port. (UnicastServerRef.exportObject would
|
||||
* cause transport to listen.)
|
||||
*/
|
||||
try {
|
||||
dgc = new DGCImpl();
|
||||
ObjID dgcID = new ObjID(ObjID.DGC_ID);
|
||||
LiveRef ref = new LiveRef(dgcID, 0);
|
||||
UnicastServerRef disp = new UnicastServerRef(ref,
|
||||
DGCImpl::checkInput);
|
||||
Remote stub =
|
||||
Util.createProxy(DGCImpl.class,
|
||||
new UnicastRef(ref), true);
|
||||
disp.setSkeleton(dgc);
|
||||
|
||||
Permissions perms = new Permissions();
|
||||
perms.add(new SocketPermission("*", "accept,resolve"));
|
||||
ProtectionDomain[] pd = { new ProtectionDomain(null, perms) };
|
||||
AccessControlContext acceptAcc = new AccessControlContext(pd);
|
||||
|
||||
Target target = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Target>() {
|
||||
public Target run() {
|
||||
return new Target(dgc, disp, stub, dgcID, true);
|
||||
}
|
||||
}, acceptAcc);
|
||||
|
||||
ObjectTable.putTarget(target);
|
||||
} catch (RemoteException e) {
|
||||
throw new Error(
|
||||
"exception initializing server-side DGC", e);
|
||||
}
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(savedCcl);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ObjectInputFilter to filter DGC input objects.
|
||||
* The list of acceptable classes is very short and explicit.
|
||||
* The depth and array sizes are limited.
|
||||
*
|
||||
* @param filterInfo access to class, arrayLength, etc.
|
||||
* @return {@link ObjectInputFilter.Status#ALLOWED} if allowed,
|
||||
* {@link ObjectInputFilter.Status#REJECTED} if rejected,
|
||||
* otherwise {@link ObjectInputFilter.Status#UNDECIDED}
|
||||
*/
|
||||
private static ObjectInputFilter.Status checkInput(ObjectInputFilter.FilterInfo filterInfo) {
|
||||
if (dgcFilter != null) {
|
||||
ObjectInputFilter.Status status = dgcFilter.checkInput(filterInfo);
|
||||
if (status != ObjectInputFilter.Status.UNDECIDED) {
|
||||
// The DGC filter can override the built-in white-list
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (filterInfo.depth() > DGC_MAX_DEPTH) {
|
||||
return ObjectInputFilter.Status.REJECTED;
|
||||
}
|
||||
Class<?> clazz = filterInfo.serialClass();
|
||||
if (clazz != null) {
|
||||
while (clazz.isArray()) {
|
||||
if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > DGC_MAX_ARRAY_SIZE) {
|
||||
return ObjectInputFilter.Status.REJECTED;
|
||||
}
|
||||
// Arrays are allowed depending on the component type
|
||||
clazz = clazz.getComponentType();
|
||||
}
|
||||
if (clazz.isPrimitive()) {
|
||||
// Arrays of primitives are allowed
|
||||
return ObjectInputFilter.Status.ALLOWED;
|
||||
}
|
||||
return (clazz == ObjID.class ||
|
||||
clazz == UID.class ||
|
||||
clazz == VMID.class ||
|
||||
clazz == Lease.class)
|
||||
? ObjectInputFilter.Status.ALLOWED
|
||||
: ObjectInputFilter.Status.REJECTED;
|
||||
}
|
||||
// Not a class, not size limited
|
||||
return ObjectInputFilter.Status.UNDECIDED;
|
||||
}
|
||||
|
||||
|
||||
private static class LeaseInfo {
|
||||
VMID vmid;
|
||||
long expiration;
|
||||
Set<Target> notifySet = new HashSet<>();
|
||||
|
||||
LeaseInfo(VMID vmid, long lease) {
|
||||
this.vmid = vmid;
|
||||
expiration = System.currentTimeMillis() + lease;
|
||||
}
|
||||
|
||||
synchronized void renew(long lease) {
|
||||
long newExpiration = System.currentTimeMillis() + lease;
|
||||
if (newExpiration > expiration)
|
||||
expiration = newExpiration;
|
||||
}
|
||||
|
||||
boolean expired(long time) {
|
||||
if (expiration < time) {
|
||||
if (dgcLog.isLoggable(Log.BRIEF)) {
|
||||
dgcLog.log(Log.BRIEF, vmid.toString());
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
jdkSrc/jdk8/sun/rmi/transport/DGCImpl_Skel.java
Normal file
113
jdkSrc/jdk8/sun/rmi/transport/DGCImpl_Skel.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Skeleton to dispatch DGC methods.
|
||||
* Originally generated by RMIC but frozen to match the stubs.
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "serial"})
|
||||
public final class DGCImpl_Skel
|
||||
implements java.rmi.server.Skeleton {
|
||||
private static final java.rmi.server.Operation[] operations = {
|
||||
new java.rmi.server.Operation("void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)"),
|
||||
new java.rmi.server.Operation("java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)")
|
||||
};
|
||||
|
||||
private static final long interfaceHash = -669196253586618813L;
|
||||
|
||||
public java.rmi.server.Operation[] getOperations() {
|
||||
return operations.clone();
|
||||
}
|
||||
|
||||
public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall remoteCall, int opnum, long hash)
|
||||
throws java.lang.Exception {
|
||||
if (hash != interfaceHash)
|
||||
throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch");
|
||||
|
||||
sun.rmi.transport.DGCImpl server = (sun.rmi.transport.DGCImpl) obj;
|
||||
StreamRemoteCall call = (StreamRemoteCall) remoteCall;
|
||||
switch (opnum) {
|
||||
case 0: // clean(ObjID[], long, VMID, boolean)
|
||||
{
|
||||
java.rmi.server.ObjID[] $param_arrayOf_ObjID_1;
|
||||
long $param_long_2;
|
||||
java.rmi.dgc.VMID $param_VMID_3;
|
||||
boolean $param_boolean_4;
|
||||
try {
|
||||
java.io.ObjectInput in = call.getInputStream();
|
||||
$param_arrayOf_ObjID_1 = (java.rmi.server.ObjID[]) in.readObject();
|
||||
$param_long_2 = in.readLong();
|
||||
$param_VMID_3 = (java.rmi.dgc.VMID) in.readObject();
|
||||
$param_boolean_4 = in.readBoolean();
|
||||
} catch (ClassCastException | IOException | ClassNotFoundException e) {
|
||||
call.discardPendingRefs();
|
||||
throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
|
||||
} finally {
|
||||
call.releaseInputStream();
|
||||
}
|
||||
server.clean($param_arrayOf_ObjID_1, $param_long_2, $param_VMID_3, $param_boolean_4);
|
||||
try {
|
||||
call.getResultStream(true);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling return", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: // dirty(ObjID[], long, Lease)
|
||||
{
|
||||
java.rmi.server.ObjID[] $param_arrayOf_ObjID_1;
|
||||
long $param_long_2;
|
||||
java.rmi.dgc.Lease $param_Lease_3;
|
||||
try {
|
||||
java.io.ObjectInput in = call.getInputStream();
|
||||
$param_arrayOf_ObjID_1 = (java.rmi.server.ObjID[]) in.readObject();
|
||||
$param_long_2 = in.readLong();
|
||||
$param_Lease_3 = (java.rmi.dgc.Lease) in.readObject();
|
||||
} catch (ClassCastException | IOException | ClassNotFoundException e) {
|
||||
call.discardPendingRefs();
|
||||
throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
|
||||
} finally {
|
||||
call.releaseInputStream();
|
||||
}
|
||||
java.rmi.dgc.Lease $result = server.dirty($param_arrayOf_ObjID_1, $param_long_2, $param_Lease_3);
|
||||
try {
|
||||
java.io.ObjectOutput out = call.getResultStream(true);
|
||||
out.writeObject($result);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling return", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new java.rmi.UnmarshalException("invalid method number");
|
||||
}
|
||||
}
|
||||
}
|
||||
191
jdkSrc/jdk8/sun/rmi/transport/DGCImpl_Stub.java
Normal file
191
jdkSrc/jdk8/sun/rmi/transport/DGCImpl_Stub.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.transport;
|
||||
|
||||
import sun.rmi.transport.tcp.TCPConnection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.rmi.dgc.Lease;
|
||||
import java.rmi.dgc.VMID;
|
||||
import java.rmi.server.UID;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import sun.misc.ObjectInputFilter;
|
||||
|
||||
/**
|
||||
* Stubs to invoke DGC remote methods.
|
||||
* Originally generated from RMIC but frozen to insert serialFilter.
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "serial"})
|
||||
public final class DGCImpl_Stub
|
||||
extends java.rmi.server.RemoteStub
|
||||
implements java.rmi.dgc.DGC {
|
||||
private static final java.rmi.server.Operation[] operations = {
|
||||
new java.rmi.server.Operation("void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)"),
|
||||
new java.rmi.server.Operation("java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)")
|
||||
};
|
||||
|
||||
private static final long interfaceHash = -669196253586618813L;
|
||||
|
||||
/** Registry max depth of remote invocations. **/
|
||||
private static int DGCCLIENT_MAX_DEPTH = 6;
|
||||
|
||||
/** Registry maximum array size in remote invocations. **/
|
||||
private static int DGCCLIENT_MAX_ARRAY_SIZE = 10000;
|
||||
|
||||
// constructors
|
||||
public DGCImpl_Stub() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DGCImpl_Stub(java.rmi.server.RemoteRef ref) {
|
||||
super(ref);
|
||||
}
|
||||
|
||||
// methods from remote interfaces
|
||||
|
||||
// implementation of clean(ObjID[], long, VMID, boolean)
|
||||
public void clean(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.VMID $param_VMID_3, boolean $param_boolean_4)
|
||||
throws java.rmi.RemoteException {
|
||||
try {
|
||||
StreamRemoteCall call = (StreamRemoteCall)ref.newCall((java.rmi.server.RemoteObject) this,
|
||||
operations, 0, interfaceHash);
|
||||
call.setObjectInputFilter(DGCImpl_Stub::leaseFilter);
|
||||
try {
|
||||
java.io.ObjectOutput out = call.getOutputStream();
|
||||
out.writeObject($param_arrayOf_ObjID_1);
|
||||
out.writeLong($param_long_2);
|
||||
out.writeObject($param_VMID_3);
|
||||
out.writeBoolean($param_boolean_4);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling arguments", e);
|
||||
}
|
||||
ref.invoke(call);
|
||||
ref.done(call);
|
||||
} catch (java.lang.RuntimeException e) {
|
||||
throw e;
|
||||
} catch (java.rmi.RemoteException e) {
|
||||
throw e;
|
||||
} catch (java.lang.Exception e) {
|
||||
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
// implementation of dirty(ObjID[], long, Lease)
|
||||
public java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.Lease $param_Lease_3)
|
||||
throws java.rmi.RemoteException {
|
||||
try {
|
||||
StreamRemoteCall call =
|
||||
(StreamRemoteCall)ref.newCall((java.rmi.server.RemoteObject) this,
|
||||
operations, 1, interfaceHash);
|
||||
call.setObjectInputFilter(DGCImpl_Stub::leaseFilter);
|
||||
try {
|
||||
java.io.ObjectOutput out = call.getOutputStream();
|
||||
out.writeObject($param_arrayOf_ObjID_1);
|
||||
out.writeLong($param_long_2);
|
||||
out.writeObject($param_Lease_3);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new java.rmi.MarshalException("error marshalling arguments", e);
|
||||
}
|
||||
ref.invoke(call);
|
||||
java.rmi.dgc.Lease $result;
|
||||
Connection connection = call.getConnection();
|
||||
try {
|
||||
java.io.ObjectInput in = call.getInputStream();
|
||||
|
||||
$result = (java.rmi.dgc.Lease) in.readObject();
|
||||
} catch (ClassCastException | IOException | ClassNotFoundException e) {
|
||||
if (connection instanceof TCPConnection) {
|
||||
// Modified to prevent re-use of the connection after an exception
|
||||
((TCPConnection) connection).getChannel().free(connection, false);
|
||||
}
|
||||
call.discardPendingRefs();
|
||||
throw new java.rmi.UnmarshalException("error unmarshalling return", e);
|
||||
} finally {
|
||||
ref.done(call);
|
||||
}
|
||||
return $result;
|
||||
} catch (java.lang.RuntimeException e) {
|
||||
throw e;
|
||||
} catch (java.rmi.RemoteException e) {
|
||||
throw e;
|
||||
} catch (java.lang.Exception e) {
|
||||
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ObjectInputFilter to filter DGCClient return value (a Lease).
|
||||
* The list of acceptable classes is very short and explicit.
|
||||
* The depth and array sizes are limited.
|
||||
* <p>
|
||||
* The filter must accept normal and exception returns.
|
||||
* A DGC server may throw exceptions that may have a cause
|
||||
* and suppressed exceptions.
|
||||
*
|
||||
* @param filterInfo access to class, arrayLength, etc.
|
||||
* @return {@link ObjectInputFilter.Status#ALLOWED} if allowed,
|
||||
* {@link ObjectInputFilter.Status#REJECTED} if rejected,
|
||||
* otherwise {@link ObjectInputFilter.Status#UNDECIDED}
|
||||
*/
|
||||
private static ObjectInputFilter.Status leaseFilter(ObjectInputFilter.FilterInfo filterInfo) {
|
||||
|
||||
if (filterInfo.depth() > DGCCLIENT_MAX_DEPTH) {
|
||||
return ObjectInputFilter.Status.REJECTED;
|
||||
}
|
||||
Class<?> clazz = filterInfo.serialClass();
|
||||
if (clazz != null) {
|
||||
while (clazz.isArray()) {
|
||||
if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > DGCCLIENT_MAX_ARRAY_SIZE) {
|
||||
return ObjectInputFilter.Status.REJECTED;
|
||||
}
|
||||
// Arrays are allowed depending on the component type
|
||||
clazz = clazz.getComponentType();
|
||||
}
|
||||
if (clazz.isPrimitive()) {
|
||||
// Arrays of primitives are allowed
|
||||
return ObjectInputFilter.Status.ALLOWED;
|
||||
}
|
||||
return (clazz == UID.class ||
|
||||
clazz == VMID.class ||
|
||||
clazz == Lease.class ||
|
||||
(Throwable.class.isAssignableFrom(clazz) &&
|
||||
clazz.getClassLoader() ==
|
||||
Object.class.getClassLoader()) ||
|
||||
clazz == StackTraceElement.class ||
|
||||
clazz == ArrayList.class || // for suppressed exceptions, if any
|
||||
clazz == Object.class ||
|
||||
clazz.getName().equals("java.util.Collections$UnmodifiableList") ||
|
||||
clazz.getName().equals("java.util.Collections$UnmodifiableCollection") ||
|
||||
clazz.getName().equals("java.util.Collections$UnmodifiableRandomAccessList"))
|
||||
? ObjectInputFilter.Status.ALLOWED
|
||||
: ObjectInputFilter.Status.REJECTED;
|
||||
}
|
||||
// Not a class, not size limited
|
||||
return ObjectInputFilter.Status.UNDECIDED;
|
||||
}
|
||||
|
||||
}
|
||||
55
jdkSrc/jdk8/sun/rmi/transport/Endpoint.java
Normal file
55
jdkSrc/jdk8/sun/rmi/transport/Endpoint.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.RemoteServer;
|
||||
|
||||
public interface Endpoint {
|
||||
/**
|
||||
* Return a channel that generates connections to the remote
|
||||
* endpoint.
|
||||
*/
|
||||
Channel getChannel();
|
||||
|
||||
/**
|
||||
* Export the object so that it can accept incoming calls at
|
||||
* the endpoint.
|
||||
*/
|
||||
void exportObject(Target target)
|
||||
throws RemoteException;
|
||||
|
||||
/**
|
||||
* Returns the transport for incoming connections to this endpoint.
|
||||
**/
|
||||
Transport getInboundTransport();
|
||||
|
||||
/**
|
||||
* Returns transport for making connections to remote endpoints.
|
||||
**/
|
||||
Transport getOutboundTransport();
|
||||
}
|
||||
317
jdkSrc/jdk8/sun/rmi/transport/LiveRef.java
Normal file
317
jdkSrc/jdk8/sun/rmi/transport/LiveRef.java
Normal file
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.RMIClientSocketFactory;
|
||||
import java.rmi.server.RMIServerSocketFactory;
|
||||
import java.util.Arrays;
|
||||
import sun.rmi.transport.tcp.TCPEndpoint;
|
||||
|
||||
/**
|
||||
* NOTE: There is a JDK-internal dependency on the existence of this
|
||||
* class and its getClientSocketFactory method in the implementation
|
||||
* of javax.management.remote.rmi.RMIConnector.
|
||||
**/
|
||||
public class LiveRef implements Cloneable {
|
||||
/** wire representation for the object*/
|
||||
private final Endpoint ep;
|
||||
private final ObjID id;
|
||||
|
||||
/** cached connection service for the object */
|
||||
private transient Channel ch;
|
||||
|
||||
/** flag to indicate whether this ref specifies a local server or
|
||||
* is a ref for a remote object (surrogate)
|
||||
*/
|
||||
private final boolean isLocal;
|
||||
|
||||
/**
|
||||
* Construct a "well-known" live reference to a remote object
|
||||
* @param isLocalServer If true, indicates this ref specifies a local
|
||||
* server in this address space; if false, the ref is for a remote
|
||||
* object (hence a surrogate or proxy) in another address space.
|
||||
*/
|
||||
public LiveRef(ObjID objID, Endpoint endpoint, boolean isLocal) {
|
||||
ep = endpoint;
|
||||
id = objID;
|
||||
this.isLocal = isLocal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new live reference for a server object in the local
|
||||
* address space.
|
||||
*/
|
||||
public LiveRef(int port) {
|
||||
this((new ObjID()), port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new live reference for a server object in the local
|
||||
* address space, to use sockets of the specified type.
|
||||
*/
|
||||
public LiveRef(int port,
|
||||
RMIClientSocketFactory csf,
|
||||
RMIServerSocketFactory ssf)
|
||||
{
|
||||
this((new ObjID()), port, csf, ssf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new live reference for a "well-known" server object
|
||||
* in the local address space.
|
||||
*/
|
||||
public LiveRef(ObjID objID, int port) {
|
||||
this(objID, TCPEndpoint.getLocalEndpoint(port), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new live reference for a "well-known" server object
|
||||
* in the local address space, to use sockets of the specified type.
|
||||
*/
|
||||
public LiveRef(ObjID objID, int port, RMIClientSocketFactory csf,
|
||||
RMIServerSocketFactory ssf)
|
||||
{
|
||||
this(objID, TCPEndpoint.getLocalEndpoint(port, csf, ssf), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a shallow copy of this ref.
|
||||
*/
|
||||
public Object clone() {
|
||||
try {
|
||||
LiveRef newRef = (LiveRef) super.clone();
|
||||
return newRef;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new InternalError(e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the port number associated with this ref.
|
||||
*/
|
||||
public int getPort() {
|
||||
return ((TCPEndpoint) ep).getPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client socket factory associated with this ref.
|
||||
*
|
||||
* NOTE: There is a JDK-internal dependency on the existence of
|
||||
* this method in the implementation of
|
||||
* javax.management.remote.rmi.RMIConnector.
|
||||
**/
|
||||
public RMIClientSocketFactory getClientSocketFactory() {
|
||||
return ((TCPEndpoint) ep).getClientSocketFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server socket factory associated with this ref.
|
||||
*/
|
||||
public RMIServerSocketFactory getServerSocketFactory() {
|
||||
return ((TCPEndpoint) ep).getServerSocketFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the object to accept incoming calls.
|
||||
*/
|
||||
public void exportObject(Target target) throws RemoteException {
|
||||
ep.exportObject(target);
|
||||
}
|
||||
|
||||
public Channel getChannel() throws RemoteException {
|
||||
if (ch == null) {
|
||||
ch = ep.getChannel();
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
public ObjID getObjID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
Endpoint getEndpoint() {
|
||||
return ep;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String type;
|
||||
|
||||
if (isLocal)
|
||||
type = "local";
|
||||
else
|
||||
type = "remote";
|
||||
return "[endpoint:" + ep + "(" + type + ")," +
|
||||
"objID:" + id + "]";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj != null && obj instanceof LiveRef) {
|
||||
LiveRef ref = (LiveRef) obj;
|
||||
|
||||
return (ep.equals(ref.ep) && id.equals(ref.id) &&
|
||||
isLocal == ref.isLocal);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean remoteEquals(Object obj) {
|
||||
if (obj != null && obj instanceof LiveRef) {
|
||||
LiveRef ref = (LiveRef) obj;
|
||||
|
||||
TCPEndpoint thisEp = ((TCPEndpoint) ep);
|
||||
TCPEndpoint refEp = ((TCPEndpoint) ref.ep);
|
||||
|
||||
RMIClientSocketFactory thisClientFactory =
|
||||
thisEp.getClientSocketFactory();
|
||||
RMIClientSocketFactory refClientFactory =
|
||||
refEp.getClientSocketFactory();
|
||||
|
||||
/**
|
||||
* Fix for 4254103: LiveRef.remoteEquals should not fail
|
||||
* if one of the objects in the comparison has a null
|
||||
* server socket. Comparison should only consider the
|
||||
* following criteria:
|
||||
*
|
||||
* hosts, ports, client socket factories and object IDs.
|
||||
*/
|
||||
if (thisEp.getPort() != refEp.getPort() ||
|
||||
!thisEp.getHost().equals(refEp.getHost()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((thisClientFactory == null) ^ (refClientFactory == null)) {
|
||||
return false;
|
||||
}
|
||||
if ((thisClientFactory != null) &&
|
||||
!((thisClientFactory.getClass() ==
|
||||
refClientFactory.getClass()) &&
|
||||
(thisClientFactory.equals(refClientFactory))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (id.equals(ref.id));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void write(ObjectOutput out, boolean useNewFormat)
|
||||
throws IOException
|
||||
{
|
||||
boolean isResultStream = false;
|
||||
if (out instanceof ConnectionOutputStream) {
|
||||
ConnectionOutputStream stream = (ConnectionOutputStream) out;
|
||||
isResultStream = stream.isResultStream();
|
||||
/*
|
||||
* Ensure that referential integrity is not broken while
|
||||
* this LiveRef is in transit. If it is being marshalled
|
||||
* as part of a result, it may not otherwise be strongly
|
||||
* reachable after the remote call has completed; even if
|
||||
* it is being marshalled as part of an argument, the VM
|
||||
* may determine that the reference on the stack is no
|
||||
* longer reachable after marshalling (see 6181943)--
|
||||
* therefore, tell the stream to save a reference until a
|
||||
* timeout expires or, for results, a DGCAck message has
|
||||
* been received from the caller, or for arguments, the
|
||||
* remote call has completed. For a "local" LiveRef, save
|
||||
* a reference to the impl directly, because the impl is
|
||||
* not reachable from the LiveRef (see 4114579);
|
||||
* otherwise, save a reference to the LiveRef, for the
|
||||
* client-side DGC to watch over. (Also see 4017232.)
|
||||
*/
|
||||
if (isLocal) {
|
||||
ObjectEndpoint oe =
|
||||
new ObjectEndpoint(id, ep.getInboundTransport());
|
||||
Target target = ObjectTable.getTarget(oe);
|
||||
|
||||
if (target != null) {
|
||||
Remote impl = target.getImpl();
|
||||
if (impl != null) {
|
||||
stream.saveObject(impl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stream.saveObject(this);
|
||||
}
|
||||
}
|
||||
// All together now write out the endpoint, id, and flag
|
||||
|
||||
// (need to choose whether or not to use old JDK1.1 endpoint format)
|
||||
if (useNewFormat) {
|
||||
((TCPEndpoint) ep).write(out);
|
||||
} else {
|
||||
((TCPEndpoint) ep).writeHostPortFormat(out);
|
||||
}
|
||||
id.write(out);
|
||||
out.writeBoolean(isResultStream);
|
||||
}
|
||||
|
||||
public static LiveRef read(ObjectInput in, boolean useNewFormat)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
Endpoint ep;
|
||||
ObjID id;
|
||||
|
||||
// Now read in the endpoint, id, and result flag
|
||||
// (need to choose whether or not to read old JDK1.1 endpoint format)
|
||||
if (useNewFormat) {
|
||||
ep = TCPEndpoint.read(in);
|
||||
} else {
|
||||
ep = TCPEndpoint.readHostPortFormat(in);
|
||||
}
|
||||
id = ObjID.read(in);
|
||||
boolean isResultStream = in.readBoolean();
|
||||
|
||||
LiveRef ref = new LiveRef(id, ep, false);
|
||||
|
||||
if (in instanceof ConnectionInputStream) {
|
||||
ConnectionInputStream stream = (ConnectionInputStream)in;
|
||||
// save ref to send "dirty" call after all args/returns
|
||||
// have been unmarshaled.
|
||||
stream.saveRef(ref);
|
||||
if (isResultStream) {
|
||||
// set flag in stream indicating that remote objects were
|
||||
// unmarshaled. A DGC ack should be sent by the transport.
|
||||
stream.setAckNeeded();
|
||||
}
|
||||
} else {
|
||||
DGCClient.registerRefs(ep, Arrays.asList(new LiveRef[] { ref }));
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
90
jdkSrc/jdk8/sun/rmi/transport/ObjectEndpoint.java
Normal file
90
jdkSrc/jdk8/sun/rmi/transport/ObjectEndpoint.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.rmi.server.ObjID;
|
||||
|
||||
/**
|
||||
* An object used as a key to the object table that maps an
|
||||
* instance of this class to a Target.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
**/
|
||||
class ObjectEndpoint {
|
||||
|
||||
private final ObjID id;
|
||||
private final Transport transport;
|
||||
|
||||
/**
|
||||
* Constructs a new ObjectEndpoint instance with the specified id and
|
||||
* transport. The specified id must be non-null, and the specified
|
||||
* transport must either be non-null or the specified id must be
|
||||
* equivalent to an ObjID constructed with ObjID.DGC_ID.
|
||||
*
|
||||
* @param id the object identifier
|
||||
* @param transport the transport
|
||||
* @throws NullPointerException if id is null
|
||||
**/
|
||||
ObjectEndpoint(ObjID id, Transport transport) {
|
||||
if (id == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
assert transport != null || id.equals(new ObjID(ObjID.DGC_ID));
|
||||
|
||||
this.id = id;
|
||||
this.transport = transport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the specified object with this object endpoint for
|
||||
* equality.
|
||||
*
|
||||
* This method returns true if and only if the specified object is an
|
||||
* ObjectEndpoint instance with the same object identifier and
|
||||
* transport as this object.
|
||||
**/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof ObjectEndpoint) {
|
||||
ObjectEndpoint oe = (ObjectEndpoint) obj;
|
||||
return id.equals(oe.id) && transport == oe.transport;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code value for this object endpoint.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return id.hashCode() ^ (transport != null ? transport.hashCode() : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation for this object endpoint.
|
||||
*/
|
||||
public String toString() {
|
||||
return id.toString();
|
||||
}
|
||||
}
|
||||
371
jdkSrc/jdk8/sun/rmi/transport/ObjectTable.java
Normal file
371
jdkSrc/jdk8/sun/rmi/transport/ObjectTable.java
Normal file
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.dgc.VMID;
|
||||
import java.rmi.server.ExportException;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import sun.misc.GC;
|
||||
import sun.rmi.runtime.Log;
|
||||
import sun.rmi.runtime.NewThreadAction;
|
||||
import sun.security.action.GetLongAction;
|
||||
|
||||
/**
|
||||
* Object table shared by all implementors of the Transport interface.
|
||||
* This table maps object ids to remote object targets in this address
|
||||
* space.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
* @author Peter Jones
|
||||
*/
|
||||
public final class ObjectTable {
|
||||
|
||||
/** maximum interval between complete garbage collections of local heap */
|
||||
private final static long gcInterval = // default 1 hour
|
||||
AccessController.doPrivileged(
|
||||
new GetLongAction("sun.rmi.dgc.server.gcInterval", 3600000));
|
||||
|
||||
/**
|
||||
* lock guarding objTable and implTable.
|
||||
* Holders MAY acquire a Target instance's lock or keepAliveLock.
|
||||
*/
|
||||
private static final Object tableLock = new Object();
|
||||
|
||||
/** tables mapping to Target, keyed from ObjectEndpoint and impl object */
|
||||
private static final Map<ObjectEndpoint,Target> objTable =
|
||||
new HashMap<>();
|
||||
private static final Map<WeakRef,Target> implTable =
|
||||
new HashMap<>();
|
||||
|
||||
/**
|
||||
* lock guarding keepAliveCount, reaper, and gcLatencyRequest.
|
||||
* Holders may NOT acquire a Target instance's lock or tableLock.
|
||||
*/
|
||||
private static final Object keepAliveLock = new Object();
|
||||
|
||||
/** count of non-permanent objects in table or still processing calls */
|
||||
private static int keepAliveCount = 0;
|
||||
|
||||
/** thread to collect unreferenced objects from table */
|
||||
private static Thread reaper = null;
|
||||
|
||||
/** queue notified when weak refs in the table are cleared */
|
||||
static final ReferenceQueue<Object> reapQueue = new ReferenceQueue<>();
|
||||
|
||||
/** handle for GC latency request (for future cancellation) */
|
||||
private static GC.LatencyRequest gcLatencyRequest = null;
|
||||
|
||||
/*
|
||||
* Disallow anyone from creating one of these.
|
||||
*/
|
||||
private ObjectTable() {}
|
||||
|
||||
/**
|
||||
* Returns the target associated with the object id.
|
||||
*/
|
||||
static Target getTarget(ObjectEndpoint oe) {
|
||||
synchronized (tableLock) {
|
||||
return objTable.get(oe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target associated with the remote object
|
||||
*/
|
||||
public static Target getTarget(Remote impl) {
|
||||
synchronized (tableLock) {
|
||||
return implTable.get(new WeakRef(impl));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stub for the remote object <b>obj</b> passed
|
||||
* as a parameter. This operation is only valid <i>after</i>
|
||||
* the object has been exported.
|
||||
*
|
||||
* @return the stub for the remote object, <b>obj</b>.
|
||||
* @exception NoSuchObjectException if the stub for the
|
||||
* remote object could not be found.
|
||||
*/
|
||||
public static Remote getStub(Remote impl)
|
||||
throws NoSuchObjectException
|
||||
{
|
||||
Target target = getTarget(impl);
|
||||
if (target == null) {
|
||||
throw new NoSuchObjectException("object not exported");
|
||||
} else {
|
||||
return target.getStub();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the remote object, obj, from the RMI runtime. If
|
||||
* successful, the object can no longer accept incoming RMI calls.
|
||||
* If the force parameter is true, the object is forcibly unexported
|
||||
* even if there are pending calls to the remote object or the
|
||||
* remote object still has calls in progress. If the force
|
||||
* parameter is false, the object is only unexported if there are
|
||||
* no pending or in progress calls to the object.
|
||||
*
|
||||
* @param obj the remote object to be unexported
|
||||
* @param force if true, unexports the object even if there are
|
||||
* pending or in-progress calls; if false, only unexports the object
|
||||
* if there are no pending or in-progress calls
|
||||
* @return true if operation is successful, false otherwise
|
||||
* @exception NoSuchObjectException if the remote object is not
|
||||
* currently exported
|
||||
*/
|
||||
public static boolean unexportObject(Remote obj, boolean force)
|
||||
throws java.rmi.NoSuchObjectException
|
||||
{
|
||||
synchronized (tableLock) {
|
||||
Target target = getTarget(obj);
|
||||
if (target == null) {
|
||||
throw new NoSuchObjectException("object not exported");
|
||||
} else {
|
||||
if (target.unexport(force)) {
|
||||
removeTarget(target);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add target to object table. If it is not a permanent entry, then
|
||||
* make sure that reaper thread is running to remove collected entries
|
||||
* and keep VM alive.
|
||||
*/
|
||||
static void putTarget(Target target) throws ExportException {
|
||||
ObjectEndpoint oe = target.getObjectEndpoint();
|
||||
WeakRef weakImpl = target.getWeakImpl();
|
||||
|
||||
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
|
||||
DGCImpl.dgcLog.log(Log.VERBOSE, "add object " + oe);
|
||||
}
|
||||
|
||||
synchronized (tableLock) {
|
||||
/**
|
||||
* Do nothing if impl has already been collected (see 6597112). Check while
|
||||
* holding tableLock to ensure that Reaper cannot process weakImpl in between
|
||||
* null check and put/increment effects.
|
||||
*/
|
||||
if (target.getImpl() != null) {
|
||||
if (objTable.containsKey(oe)) {
|
||||
throw new ExportException(
|
||||
"internal error: ObjID already in use");
|
||||
} else if (implTable.containsKey(weakImpl)) {
|
||||
throw new ExportException("object already exported");
|
||||
}
|
||||
|
||||
objTable.put(oe, target);
|
||||
implTable.put(weakImpl, target);
|
||||
|
||||
if (!target.isPermanent()) {
|
||||
incrementKeepAliveCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove target from object table.
|
||||
*
|
||||
* NOTE: This method must only be invoked while synchronized on
|
||||
* the "tableLock" object, because it does not do so itself.
|
||||
*/
|
||||
private static void removeTarget(Target target) {
|
||||
// assert Thread.holdsLock(tableLock);
|
||||
|
||||
ObjectEndpoint oe = target.getObjectEndpoint();
|
||||
WeakRef weakImpl = target.getWeakImpl();
|
||||
|
||||
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
|
||||
DGCImpl.dgcLog.log(Log.VERBOSE, "remove object " + oe);
|
||||
}
|
||||
|
||||
objTable.remove(oe);
|
||||
implTable.remove(weakImpl);
|
||||
|
||||
target.markRemoved(); // handles decrementing keep-alive count
|
||||
}
|
||||
|
||||
/**
|
||||
* Process client VM signalling reference for given ObjID: forward to
|
||||
* corresponding Target entry. If ObjID is not found in table,
|
||||
* no action is taken.
|
||||
*/
|
||||
static void referenced(ObjID id, long sequenceNum, VMID vmid) {
|
||||
synchronized (tableLock) {
|
||||
ObjectEndpoint oe =
|
||||
new ObjectEndpoint(id, Transport.currentTransport());
|
||||
Target target = objTable.get(oe);
|
||||
if (target != null) {
|
||||
target.referenced(sequenceNum, vmid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process client VM dropping reference for given ObjID: forward to
|
||||
* corresponding Target entry. If ObjID is not found in table,
|
||||
* no action is taken.
|
||||
*/
|
||||
static void unreferenced(ObjID id, long sequenceNum, VMID vmid,
|
||||
boolean strong)
|
||||
{
|
||||
synchronized (tableLock) {
|
||||
ObjectEndpoint oe =
|
||||
new ObjectEndpoint(id, Transport.currentTransport());
|
||||
Target target = objTable.get(oe);
|
||||
if (target != null)
|
||||
target.unreferenced(sequenceNum, vmid, strong);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the "keep-alive count".
|
||||
*
|
||||
* The "keep-alive count" is the number of non-permanent remote objects
|
||||
* that are either in the object table or still have calls in progress.
|
||||
* Therefore, this method should be invoked exactly once for every
|
||||
* non-permanent remote object exported (a remote object must be
|
||||
* exported before it can have any calls in progress).
|
||||
*
|
||||
* The VM is "kept alive" while the keep-alive count is greater than
|
||||
* zero; this is accomplished by keeping a non-daemon thread running.
|
||||
*
|
||||
* Because non-permanent objects are those that can be garbage
|
||||
* collected while exported, and thus those for which the "reaper"
|
||||
* thread operates, the reaper thread also serves as the non-daemon
|
||||
* VM keep-alive thread; a new reaper thread is created if necessary.
|
||||
*/
|
||||
static void incrementKeepAliveCount() {
|
||||
synchronized (keepAliveLock) {
|
||||
keepAliveCount++;
|
||||
|
||||
if (reaper == null) {
|
||||
reaper = AccessController.doPrivileged(
|
||||
new NewThreadAction(new Reaper(), "Reaper", false));
|
||||
reaper.start();
|
||||
}
|
||||
|
||||
/*
|
||||
* While there are non-"permanent" objects in the object table,
|
||||
* request a maximum latency for inspecting the entire heap
|
||||
* from the local garbage collector, to place an upper bound
|
||||
* on the time to discover remote objects that have become
|
||||
* unreachable (and thus can be removed from the table).
|
||||
*/
|
||||
if (gcLatencyRequest == null) {
|
||||
gcLatencyRequest = GC.requestLatency(gcInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the "keep-alive count".
|
||||
*
|
||||
* The "keep-alive count" is the number of non-permanent remote objects
|
||||
* that are either in the object table or still have calls in progress.
|
||||
* Therefore, this method should be invoked exactly once for every
|
||||
* previously-exported non-permanent remote object that both has been
|
||||
* removed from the object table and has no calls still in progress.
|
||||
*
|
||||
* If the keep-alive count is decremented to zero, then the current
|
||||
* reaper thread is terminated to cease keeping the VM alive (and
|
||||
* because there are no more non-permanent remote objects to reap).
|
||||
*/
|
||||
static void decrementKeepAliveCount() {
|
||||
synchronized (keepAliveLock) {
|
||||
keepAliveCount--;
|
||||
|
||||
if (keepAliveCount == 0) {
|
||||
if (!(reaper != null)) { throw new AssertionError(); }
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
reaper.interrupt();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
reaper = null;
|
||||
|
||||
/*
|
||||
* If there are no longer any non-permanent objects in the
|
||||
* object table, we are no longer concerned with the latency
|
||||
* of local garbage collection here.
|
||||
*/
|
||||
gcLatencyRequest.cancel();
|
||||
gcLatencyRequest = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Reaper thread waits for notifications that weak references in the
|
||||
* object table have been cleared. When it receives a notification, it
|
||||
* removes the corresponding entry from the table.
|
||||
*
|
||||
* Since the Reaper is created as a non-daemon thread, it also serves
|
||||
* to keep the VM from exiting while there are objects in the table
|
||||
* (other than permanent entries that should neither be reaped nor
|
||||
* keep the VM alive).
|
||||
*/
|
||||
private static class Reaper implements Runnable {
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
do {
|
||||
// wait for next cleared weak reference
|
||||
WeakRef weakImpl = (WeakRef) reapQueue.remove();
|
||||
|
||||
synchronized (tableLock) {
|
||||
Target target = implTable.get(weakImpl);
|
||||
if (target != null) {
|
||||
if (!target.isEmpty()) {
|
||||
throw new Error(
|
||||
"object with known references collected");
|
||||
} else if (target.isPermanent()) {
|
||||
throw new Error("permanent object collected");
|
||||
}
|
||||
removeTarget(target);
|
||||
}
|
||||
}
|
||||
} while (!Thread.interrupted());
|
||||
} catch (InterruptedException e) {
|
||||
// pass away if interrupted
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
342
jdkSrc/jdk8/sun/rmi/transport/StreamRemoteCall.java
Normal file
342
jdkSrc/jdk8/sun/rmi/transport/StreamRemoteCall.java
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.StreamCorruptedException;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.MarshalException;
|
||||
import java.rmi.UnmarshalException;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.RemoteCall;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import sun.misc.ObjectInputFilter;
|
||||
import sun.rmi.runtime.Log;
|
||||
import sun.rmi.server.UnicastRef;
|
||||
import sun.rmi.transport.tcp.TCPEndpoint;
|
||||
|
||||
/**
|
||||
* Stream-based implementation of the RemoteCall interface.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class StreamRemoteCall implements RemoteCall {
|
||||
private ConnectionInputStream in = null;
|
||||
private ConnectionOutputStream out = null;
|
||||
private Connection conn;
|
||||
private ObjectInputFilter filter = null;
|
||||
private boolean resultStarted = false;
|
||||
private Exception serverException = null;
|
||||
|
||||
public StreamRemoteCall(Connection c) {
|
||||
conn = c;
|
||||
}
|
||||
|
||||
public StreamRemoteCall(Connection c, ObjID id, int op, long hash)
|
||||
throws RemoteException
|
||||
{
|
||||
try {
|
||||
conn = c;
|
||||
Transport.transportLog.log(Log.VERBOSE,
|
||||
"write remote call header...");
|
||||
|
||||
// write out remote call header info...
|
||||
// call header, part 1 (read by Transport)
|
||||
conn.getOutputStream().write(TransportConstants.Call);
|
||||
getOutputStream(); // creates a MarshalOutputStream
|
||||
id.write(out); // object id (target of call)
|
||||
// call header, part 2 (read by Dispatcher)
|
||||
out.writeInt(op); // method number (operation index)
|
||||
out.writeLong(hash); // stub/skeleton hash
|
||||
} catch (IOException e) {
|
||||
throw new MarshalException("Error marshaling call header", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the connection associated with this call.
|
||||
*/
|
||||
public Connection getConnection() {
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the output stream the stub/skeleton should put arguments/results
|
||||
* into.
|
||||
*/
|
||||
public ObjectOutput getOutputStream() throws IOException {
|
||||
return getOutputStream(false);
|
||||
}
|
||||
|
||||
private ObjectOutput getOutputStream(boolean resultStream)
|
||||
throws IOException
|
||||
{
|
||||
if (out == null) {
|
||||
Transport.transportLog.log(Log.VERBOSE, "getting output stream");
|
||||
|
||||
out = new ConnectionOutputStream(conn, resultStream);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the outputStream Currently, will not complain if the
|
||||
* output stream is released more than once.
|
||||
*/
|
||||
public void releaseOutputStream() throws IOException {
|
||||
try {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.flush();
|
||||
} finally {
|
||||
out.done(); // always start DGC ack timer
|
||||
}
|
||||
}
|
||||
conn.releaseOutputStream();
|
||||
} finally {
|
||||
out = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setObjectInputFilter(ObjectInputFilter filter) {
|
||||
if (in != null) {
|
||||
throw new IllegalStateException("set filter must occur before calling getInputStream");
|
||||
}
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the InputStream the stub/skeleton should get results/arguments
|
||||
* from.
|
||||
*/
|
||||
public ObjectInput getInputStream() throws IOException {
|
||||
if (in == null) {
|
||||
Transport.transportLog.log(Log.VERBOSE, "getting input stream");
|
||||
|
||||
in = new ConnectionInputStream(conn.getInputStream());
|
||||
if (filter != null) {
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||
ObjectInputFilter.Config.setObjectInputFilter(in, filter);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the input stream, this would allow some transports to release
|
||||
* the channel early.
|
||||
*/
|
||||
public void releaseInputStream() throws IOException {
|
||||
/* WARNING: Currently, the UnicastRef.java invoke methods rely
|
||||
* upon this method not throwing an IOException.
|
||||
*/
|
||||
|
||||
try {
|
||||
if (in != null) {
|
||||
// execute MarshalInputStream "done" callbacks
|
||||
try {
|
||||
in.done();
|
||||
} catch (RuntimeException e) {
|
||||
}
|
||||
|
||||
// add saved references to DGC table
|
||||
in.registerRefs();
|
||||
|
||||
/* WARNING: The connection being passed to done may have
|
||||
* already been freed.
|
||||
*/
|
||||
in.done(conn);
|
||||
}
|
||||
conn.releaseInputStream();
|
||||
} finally {
|
||||
in = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discard any post-processing of refs the InputStream.
|
||||
*/
|
||||
public void discardPendingRefs() {
|
||||
in.discardRefs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an output stream (may put out header information
|
||||
* relating to the success of the call).
|
||||
* @param success If true, indicates normal return, else indicates
|
||||
* exceptional return.
|
||||
* @exception StreamCorruptedException If result stream previously
|
||||
* acquired
|
||||
* @exception IOException For any other problem with I/O.
|
||||
*/
|
||||
public ObjectOutput getResultStream(boolean success) throws IOException {
|
||||
/* make sure result code only marshaled once. */
|
||||
if (resultStarted)
|
||||
throw new StreamCorruptedException("result already in progress");
|
||||
else
|
||||
resultStarted = true;
|
||||
|
||||
// write out return header
|
||||
// return header, part 1 (read by Transport)
|
||||
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
|
||||
wr.writeByte(TransportConstants.Return);// transport op
|
||||
getOutputStream(true); // creates a MarshalOutputStream
|
||||
// return header, part 2 (read by client-side RemoteCall)
|
||||
if (success) //
|
||||
out.writeByte(TransportConstants.NormalReturn);
|
||||
else
|
||||
out.writeByte(TransportConstants.ExceptionalReturn);
|
||||
out.writeID(); // write id for gcAck
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do whatever it takes to execute the call.
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
public void executeCall() throws Exception {
|
||||
byte returnType;
|
||||
|
||||
// read result header
|
||||
DGCAckHandler ackHandler = null;
|
||||
try {
|
||||
if (out != null) {
|
||||
ackHandler = out.getDGCAckHandler();
|
||||
}
|
||||
releaseOutputStream();
|
||||
DataInputStream rd = new DataInputStream(conn.getInputStream());
|
||||
byte op = rd.readByte();
|
||||
if (op != TransportConstants.Return) {
|
||||
if (Transport.transportLog.isLoggable(Log.BRIEF)) {
|
||||
Transport.transportLog.log(Log.BRIEF,
|
||||
"transport return code invalid: " + op);
|
||||
}
|
||||
throw new UnmarshalException("Transport return code invalid");
|
||||
}
|
||||
getInputStream();
|
||||
returnType = in.readByte();
|
||||
in.readID(); // id for DGC acknowledgement
|
||||
} catch (UnmarshalException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new UnmarshalException("Error unmarshaling return header",
|
||||
e);
|
||||
} finally {
|
||||
if (ackHandler != null) {
|
||||
ackHandler.release();
|
||||
}
|
||||
}
|
||||
|
||||
// read return value
|
||||
switch (returnType) {
|
||||
case TransportConstants.NormalReturn:
|
||||
break;
|
||||
|
||||
case TransportConstants.ExceptionalReturn:
|
||||
Object ex;
|
||||
try {
|
||||
ex = in.readObject();
|
||||
} catch (Exception e) {
|
||||
discardPendingRefs();
|
||||
throw new UnmarshalException("Error unmarshaling return", e);
|
||||
}
|
||||
|
||||
// An exception should have been received,
|
||||
// if so throw it, else flag error
|
||||
if (ex instanceof Exception) {
|
||||
exceptionReceivedFromServer((Exception) ex);
|
||||
} else {
|
||||
discardPendingRefs();
|
||||
throw new UnmarshalException("Return type not Exception");
|
||||
}
|
||||
// Exception is thrown before fallthrough can occur
|
||||
default:
|
||||
if (Transport.transportLog.isLoggable(Log.BRIEF)) {
|
||||
Transport.transportLog.log(Log.BRIEF,
|
||||
"return code invalid: " + returnType);
|
||||
}
|
||||
throw new UnmarshalException("Return code invalid");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Routine that causes the stack traces of remote exceptions to be
|
||||
* filled in with the current stack trace on the client. Detail
|
||||
* exceptions are filled in iteratively.
|
||||
*/
|
||||
protected void exceptionReceivedFromServer(Exception ex) throws Exception {
|
||||
serverException = ex;
|
||||
|
||||
StackTraceElement[] serverTrace = ex.getStackTrace();
|
||||
StackTraceElement[] clientTrace = (new Throwable()).getStackTrace();
|
||||
StackTraceElement[] combinedTrace =
|
||||
new StackTraceElement[serverTrace.length + clientTrace.length];
|
||||
System.arraycopy(serverTrace, 0, combinedTrace, 0,
|
||||
serverTrace.length);
|
||||
System.arraycopy(clientTrace, 0, combinedTrace, serverTrace.length,
|
||||
clientTrace.length);
|
||||
ex.setStackTrace(combinedTrace);
|
||||
|
||||
/*
|
||||
* Log the details of a server exception thrown as a result of a
|
||||
* remote method invocation.
|
||||
*/
|
||||
if (UnicastRef.clientCallLog.isLoggable(Log.BRIEF)) {
|
||||
/* log call exception returned from server before it is rethrown */
|
||||
TCPEndpoint ep = (TCPEndpoint) conn.getChannel().getEndpoint();
|
||||
UnicastRef.clientCallLog.log(Log.BRIEF, "outbound call " +
|
||||
"received exception: [" + ep.getHost() + ":" +
|
||||
ep.getPort() + "] exception: ", ex);
|
||||
}
|
||||
|
||||
throw ex;
|
||||
}
|
||||
|
||||
/*
|
||||
* method to retrieve possible server side exceptions (which will
|
||||
* be throw from exceptionReceivedFromServer(...) )
|
||||
*/
|
||||
public Exception getServerException() {
|
||||
return serverException;
|
||||
}
|
||||
|
||||
public void done() throws IOException {
|
||||
/* WARNING: Currently, the UnicastRef.java invoke methods rely
|
||||
* upon this method not throwing an IOException.
|
||||
*/
|
||||
|
||||
releaseInputStream();
|
||||
}
|
||||
}
|
||||
461
jdkSrc/jdk8/sun/rmi/transport/Target.java
Normal file
461
jdkSrc/jdk8/sun/rmi/transport/Target.java
Normal file
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
import java.rmi.dgc.VMID;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.Unreferenced;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.*;
|
||||
import sun.rmi.runtime.Log;
|
||||
import sun.rmi.runtime.NewThreadAction;
|
||||
import sun.rmi.server.Dispatcher;
|
||||
|
||||
/**
|
||||
* A target contains information pertaining to a remote object that
|
||||
* resides in this address space. Targets are located via the
|
||||
* ObjectTable.
|
||||
*/
|
||||
public final class Target {
|
||||
/** object id for target */
|
||||
private final ObjID id;
|
||||
/** flag indicating whether target is subject to collection */
|
||||
private final boolean permanent;
|
||||
/** weak reference to remote object implementation */
|
||||
private final WeakRef weakImpl;
|
||||
/** dispatcher for remote object */
|
||||
private volatile Dispatcher disp;
|
||||
/** stub for remote object */
|
||||
private final Remote stub;
|
||||
/** set of clients that hold references to this target */
|
||||
private final Vector<VMID> refSet = new Vector<>();
|
||||
/** table that maps client endpoints to sequence numbers */
|
||||
private final Hashtable<VMID, SequenceEntry> sequenceTable =
|
||||
new Hashtable<>(5);
|
||||
/** access control context in which target was created */
|
||||
private final AccessControlContext acc;
|
||||
/** context class loader in which target was created */
|
||||
private final ClassLoader ccl;
|
||||
/** number of pending/executing calls */
|
||||
private int callCount = 0;
|
||||
/** true if this target has been removed from the object table */
|
||||
private boolean removed = false;
|
||||
/**
|
||||
* the transport through which this target was exported and
|
||||
* through which remote calls will be allowed
|
||||
*/
|
||||
private volatile Transport exportedTransport = null;
|
||||
|
||||
/** number to identify next callback thread created here */
|
||||
private static int nextThreadNum = 0;
|
||||
|
||||
/**
|
||||
* Construct a Target for a remote object "impl" with
|
||||
* a specific object id.
|
||||
*
|
||||
* If "permanent" is true, then the impl is pinned permanently
|
||||
* (the impl will not be collected via distributed and/or local
|
||||
* GC). If "on" is false, than the impl is subject to
|
||||
* collection. Permanent objects do not keep a server from
|
||||
* exiting.
|
||||
*/
|
||||
public Target(Remote impl, Dispatcher disp, Remote stub, ObjID id,
|
||||
boolean permanent)
|
||||
{
|
||||
this.weakImpl = new WeakRef(impl, ObjectTable.reapQueue);
|
||||
this.disp = disp;
|
||||
this.stub = stub;
|
||||
this.id = id;
|
||||
this.acc = AccessController.getContext();
|
||||
|
||||
/*
|
||||
* Fix for 4149366: so that downloaded parameter types unmarshalled
|
||||
* for this impl will be compatible with types known only to the
|
||||
* impl class's class loader (when it's not identical to the
|
||||
* exporting thread's context class loader), mark the impl's class
|
||||
* loader as the loader to use as the context class loader in the
|
||||
* server's dispatch thread while a call to this impl is being
|
||||
* processed (unless this exporting thread's context class loader is
|
||||
* a child of the impl's class loader, such as when a registry is
|
||||
* exported by an application, in which case this thread's context
|
||||
* class loader is preferred).
|
||||
*/
|
||||
ClassLoader threadContextLoader =
|
||||
Thread.currentThread().getContextClassLoader();
|
||||
ClassLoader serverLoader = impl.getClass().getClassLoader();
|
||||
if (checkLoaderAncestry(threadContextLoader, serverLoader)) {
|
||||
this.ccl = threadContextLoader;
|
||||
} else {
|
||||
this.ccl = serverLoader;
|
||||
}
|
||||
|
||||
this.permanent = permanent;
|
||||
if (permanent) {
|
||||
pinImpl();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the first class loader is a child of (or identical
|
||||
* to) the second class loader. Either loader may be "null", which is
|
||||
* considered to be the parent of any non-null class loader.
|
||||
*
|
||||
* (utility method added for the 1.2beta4 fix for 4149366)
|
||||
*/
|
||||
private static boolean checkLoaderAncestry(ClassLoader child,
|
||||
ClassLoader ancestor)
|
||||
{
|
||||
if (ancestor == null) {
|
||||
return true;
|
||||
} else if (child == null) {
|
||||
return false;
|
||||
} else {
|
||||
for (ClassLoader parent = child;
|
||||
parent != null;
|
||||
parent = parent.getParent())
|
||||
{
|
||||
if (parent == ancestor) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the stub (proxy) object for this target
|
||||
*/
|
||||
public Remote getStub() {
|
||||
return stub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object endpoint for the target.
|
||||
*/
|
||||
ObjectEndpoint getObjectEndpoint() {
|
||||
return new ObjectEndpoint(id, exportedTransport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the weak reference for the Impl of this target.
|
||||
*/
|
||||
WeakRef getWeakImpl() {
|
||||
return weakImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dispatcher for this remote object target.
|
||||
*/
|
||||
Dispatcher getDispatcher() {
|
||||
return disp;
|
||||
}
|
||||
|
||||
AccessControlContext getAccessControlContext() {
|
||||
return acc;
|
||||
}
|
||||
|
||||
ClassLoader getContextClassLoader() {
|
||||
return ccl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the impl for this target.
|
||||
* Note: this may return null if the impl has been garbage collected.
|
||||
* (currently, there is no need to make this method public)
|
||||
*/
|
||||
Remote getImpl() {
|
||||
return (Remote)weakImpl.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the target is permanent.
|
||||
*/
|
||||
boolean isPermanent() {
|
||||
return permanent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin impl in target. Pin the WeakRef object so it holds a strong
|
||||
* reference to the object to it will not be garbage collected locally.
|
||||
* This way there is a single object responsible for the weak ref
|
||||
* mechanism.
|
||||
*/
|
||||
synchronized void pinImpl() {
|
||||
weakImpl.pin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpin impl in target. Weaken the reference to impl so that it
|
||||
* can be garbage collected locally. But only if there the refSet
|
||||
* is empty. All of the weak/strong handling is in WeakRef
|
||||
*/
|
||||
synchronized void unpinImpl() {
|
||||
/* only unpin if:
|
||||
* a) impl is not permanent, and
|
||||
* b) impl is not already unpinned, and
|
||||
* c) there are no external references (outside this
|
||||
* address space) for the impl
|
||||
*/
|
||||
if (!permanent && refSet.isEmpty()) {
|
||||
weakImpl.unpin();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the transport through which remote calls to this target
|
||||
* are allowed to be set if it has not already been set.
|
||||
*/
|
||||
void setExportedTransport(Transport exportedTransport) {
|
||||
if (this.exportedTransport == null) {
|
||||
this.exportedTransport = exportedTransport;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an endpoint to the remembered set. Also adds a notifier
|
||||
* to call back if the address space associated with the endpoint
|
||||
* dies.
|
||||
*/
|
||||
synchronized void referenced(long sequenceNum, VMID vmid) {
|
||||
// check sequence number for vmid
|
||||
SequenceEntry entry = sequenceTable.get(vmid);
|
||||
if (entry == null) {
|
||||
sequenceTable.put(vmid, new SequenceEntry(sequenceNum));
|
||||
} else if (entry.sequenceNum < sequenceNum) {
|
||||
entry.update(sequenceNum);
|
||||
} else {
|
||||
// late dirty call; ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!refSet.contains(vmid)) {
|
||||
/*
|
||||
* A Target must be pinned while its refSet is not empty. It may
|
||||
* have become unpinned if external LiveRefs only existed in
|
||||
* serialized form for some period of time, or if a client failed
|
||||
* to renew its lease due to a transient network failure. So,
|
||||
* make sure that it is pinned here; this fixes bugid 4069644.
|
||||
*/
|
||||
pinImpl();
|
||||
if (getImpl() == null) // too late if impl was collected
|
||||
return;
|
||||
|
||||
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
|
||||
DGCImpl.dgcLog.log(Log.VERBOSE, "add to dirty set: " + vmid);
|
||||
}
|
||||
|
||||
refSet.addElement(vmid);
|
||||
|
||||
DGCImpl.getDGCImpl().registerTarget(vmid, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove endpoint from remembered set. If set becomes empty,
|
||||
* remove server from Transport's object table.
|
||||
*/
|
||||
synchronized void unreferenced(long sequenceNum, VMID vmid, boolean strong)
|
||||
{
|
||||
// check sequence number for vmid
|
||||
SequenceEntry entry = sequenceTable.get(vmid);
|
||||
if (entry == null || entry.sequenceNum > sequenceNum) {
|
||||
// late clean call; ignore
|
||||
return;
|
||||
} else if (strong) {
|
||||
// strong clean call; retain sequenceNum
|
||||
entry.retain(sequenceNum);
|
||||
} else if (entry.keep == false) {
|
||||
// get rid of sequence number
|
||||
sequenceTable.remove(vmid);
|
||||
}
|
||||
|
||||
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
|
||||
DGCImpl.dgcLog.log(Log.VERBOSE, "remove from dirty set: " + vmid);
|
||||
}
|
||||
|
||||
refSetRemove(vmid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove endpoint from the reference set.
|
||||
*/
|
||||
synchronized private void refSetRemove(VMID vmid) {
|
||||
// remove notification request
|
||||
DGCImpl.getDGCImpl().unregisterTarget(vmid, this);
|
||||
|
||||
if (refSet.removeElement(vmid) && refSet.isEmpty()) {
|
||||
// reference set is empty, so server can be garbage collected.
|
||||
// remove object from table.
|
||||
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
|
||||
DGCImpl.dgcLog.log(Log.VERBOSE,
|
||||
"reference set is empty: target = " + this);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the remote object implements the Unreferenced interface,
|
||||
* invoke its unreferenced callback in a separate thread.
|
||||
*/
|
||||
Remote obj = getImpl();
|
||||
if (obj instanceof Unreferenced) {
|
||||
final Unreferenced unrefObj = (Unreferenced) obj;
|
||||
AccessController.doPrivileged(
|
||||
new NewThreadAction(() -> {
|
||||
Thread.currentThread().setContextClassLoader(ccl);
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||
unrefObj.unreferenced();
|
||||
return null;
|
||||
}, acc);
|
||||
}, "Unreferenced-" + nextThreadNum++, false, true)).start();
|
||||
// REMIND: access to nextThreadNum not synchronized; you care?
|
||||
}
|
||||
|
||||
unpinImpl();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this target as not accepting new calls if any of the
|
||||
* following conditions exist: a) the force parameter is true,
|
||||
* b) the target's call count is zero, or c) the object is already
|
||||
* not accepting calls. Returns true if target is marked as not
|
||||
* accepting new calls; returns false otherwise.
|
||||
*/
|
||||
synchronized boolean unexport(boolean force) {
|
||||
|
||||
if ((force == true) || (callCount == 0) || (disp == null)) {
|
||||
disp = null;
|
||||
/*
|
||||
* Fix for 4331349: unpin object so that it may be gc'd.
|
||||
* Also, unregister all vmids referencing this target
|
||||
* so target can be gc'd.
|
||||
*/
|
||||
unpinImpl();
|
||||
DGCImpl dgc = DGCImpl.getDGCImpl();
|
||||
Enumeration<VMID> enum_ = refSet.elements();
|
||||
while (enum_.hasMoreElements()) {
|
||||
VMID vmid = enum_.nextElement();
|
||||
dgc.unregisterTarget(vmid, this);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this target as having been removed from the object table.
|
||||
*/
|
||||
synchronized void markRemoved() {
|
||||
if (!(!removed)) { throw new AssertionError(); }
|
||||
|
||||
removed = true;
|
||||
if (!permanent && callCount == 0) {
|
||||
ObjectTable.decrementKeepAliveCount();
|
||||
}
|
||||
|
||||
if (exportedTransport != null) {
|
||||
exportedTransport.targetUnexported();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment call count.
|
||||
*/
|
||||
synchronized void incrementCallCount() throws NoSuchObjectException {
|
||||
|
||||
if (disp != null) {
|
||||
callCount ++;
|
||||
} else {
|
||||
throw new NoSuchObjectException("object not accepting new calls");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement call count.
|
||||
*/
|
||||
synchronized void decrementCallCount() {
|
||||
|
||||
if (--callCount < 0) {
|
||||
throw new Error("internal error: call count less than zero");
|
||||
}
|
||||
|
||||
/*
|
||||
* The "keep-alive count" is the number of non-permanent remote
|
||||
* objects that are either in the object table or still have calls
|
||||
* in progress. Therefore, this state change may affect the
|
||||
* keep-alive count: if this target is for a non-permanent remote
|
||||
* object that has been removed from the object table and now has a
|
||||
* call count of zero, it needs to be decremented.
|
||||
*/
|
||||
if (!permanent && removed && callCount == 0) {
|
||||
ObjectTable.decrementKeepAliveCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if remembered set is empty; otherwise returns
|
||||
* false
|
||||
*/
|
||||
boolean isEmpty() {
|
||||
return refSet.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called if the address space associated with the
|
||||
* vmid dies. In that case, the vmid should be removed
|
||||
* from the reference set.
|
||||
*/
|
||||
synchronized public void vmidDead(VMID vmid) {
|
||||
if (DGCImpl.dgcLog.isLoggable(Log.BRIEF)) {
|
||||
DGCImpl.dgcLog.log(Log.BRIEF, "removing endpoint " +
|
||||
vmid + " from reference set");
|
||||
}
|
||||
|
||||
sequenceTable.remove(vmid);
|
||||
refSetRemove(vmid);
|
||||
}
|
||||
}
|
||||
|
||||
class SequenceEntry {
|
||||
long sequenceNum;
|
||||
boolean keep;
|
||||
|
||||
SequenceEntry(long sequenceNum) {
|
||||
this.sequenceNum = sequenceNum;
|
||||
keep = false;
|
||||
}
|
||||
|
||||
void retain(long sequenceNum) {
|
||||
this.sequenceNum = sequenceNum;
|
||||
keep = true;
|
||||
}
|
||||
|
||||
void update(long sequenceNum) {
|
||||
this.sequenceNum = sequenceNum;
|
||||
}
|
||||
}
|
||||
258
jdkSrc/jdk8/sun/rmi/transport/Transport.java
Normal file
258
jdkSrc/jdk8/sun/rmi/transport/Transport.java
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutput;
|
||||
import java.rmi.MarshalException;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.server.LogStream;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.RemoteCall;
|
||||
import java.rmi.server.RemoteServer;
|
||||
import java.rmi.server.ServerNotActiveException;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.Permissions;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import sun.rmi.runtime.Log;
|
||||
import sun.rmi.server.Dispatcher;
|
||||
import sun.rmi.server.UnicastServerRef;
|
||||
|
||||
/**
|
||||
* Transport abstraction for enabling communication between different
|
||||
* VMs.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class Transport {
|
||||
|
||||
/** "transport" package log level */
|
||||
static final int logLevel = LogStream.parseLevel(getLogLevel());
|
||||
|
||||
private static String getLogLevel() {
|
||||
return java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("sun.rmi.transport.logLevel"));
|
||||
}
|
||||
|
||||
/* transport package log */
|
||||
static final Log transportLog =
|
||||
Log.getLog("sun.rmi.transport.misc", "transport", Transport.logLevel);
|
||||
|
||||
/** References the current transport when a call is being serviced */
|
||||
private static final ThreadLocal<Transport> currentTransport = new ThreadLocal<>();
|
||||
|
||||
/** ObjID for DGCImpl */
|
||||
private static final ObjID dgcID = new ObjID(ObjID.DGC_ID);
|
||||
|
||||
/** AccessControlContext for setting context ClassLoader */
|
||||
private static final AccessControlContext SETCCL_ACC;
|
||||
static {
|
||||
Permissions perms = new Permissions();
|
||||
perms.add(new RuntimePermission("setContextClassLoader"));
|
||||
ProtectionDomain[] pd = { new ProtectionDomain(null, perms) };
|
||||
SETCCL_ACC = new AccessControlContext(pd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <I>Channel</I> that generates connections to the
|
||||
* endpoint <I>ep</I>. A Channel is an object that creates and
|
||||
* manages connections of a particular type to some particular
|
||||
* address space.
|
||||
* @param ep the endpoint to which connections will be generated.
|
||||
* @return the channel or null if the transport cannot
|
||||
* generate connections to this endpoint
|
||||
*/
|
||||
public abstract Channel getChannel(Endpoint ep);
|
||||
|
||||
/**
|
||||
* Removes the <I>Channel</I> that generates connections to the
|
||||
* endpoint <I>ep</I>.
|
||||
*/
|
||||
public abstract void free(Endpoint ep);
|
||||
|
||||
/**
|
||||
* Export the object so that it can accept incoming calls.
|
||||
*/
|
||||
public void exportObject(Target target) throws RemoteException {
|
||||
target.setExportedTransport(this);
|
||||
ObjectTable.putTarget(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when an object that was exported on this transport has
|
||||
* become unexported, either by being garbage collected or by
|
||||
* being explicitly unexported.
|
||||
**/
|
||||
protected void targetUnexported() { }
|
||||
|
||||
/**
|
||||
* Returns the current transport if a call is being serviced, otherwise
|
||||
* returns null.
|
||||
**/
|
||||
static Transport currentTransport() {
|
||||
return currentTransport.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the current access control context has permission to accept
|
||||
* the connection being dispatched by the current thread. The current
|
||||
* access control context is passed as a parameter to avoid the overhead of
|
||||
* an additional call to AccessController.getContext.
|
||||
*/
|
||||
protected abstract void checkAcceptPermission(AccessControlContext acc);
|
||||
|
||||
/**
|
||||
* Sets the context class loader for the current thread.
|
||||
*/
|
||||
private static void setContextClassLoader(ClassLoader ccl) {
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
|
||||
Thread.currentThread().setContextClassLoader(ccl);
|
||||
return null;
|
||||
}, SETCCL_ACC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Service an incoming remote call. When a message arrives on the
|
||||
* connection indicating the beginning of a remote call, the
|
||||
* threads are required to call the <I>serviceCall</I> method of
|
||||
* their transport. The default implementation of this method
|
||||
* locates and calls the dispatcher object. Ordinarily a
|
||||
* transport implementation will not need to override this method.
|
||||
* At the entry to <I>tr.serviceCall(conn)</I>, the connection's
|
||||
* input stream is positioned at the start of the incoming
|
||||
* message. The <I>serviceCall</I> method processes the incoming
|
||||
* remote invocation and sends the result on the connection's
|
||||
* output stream. If it returns "true", then the remote
|
||||
* invocation was processed without error and the transport can
|
||||
* cache the connection. If it returns "false", a protocol error
|
||||
* occurred during the call, and the transport should destroy the
|
||||
* connection.
|
||||
*/
|
||||
public boolean serviceCall(final RemoteCall call) {
|
||||
try {
|
||||
/* read object id */
|
||||
final Remote impl;
|
||||
ObjID id;
|
||||
|
||||
try {
|
||||
id = ObjID.read(call.getInputStream());
|
||||
} catch (java.io.IOException e) {
|
||||
throw new MarshalException("unable to read objID", e);
|
||||
}
|
||||
|
||||
/* get the remote object */
|
||||
Transport transport = id.equals(dgcID) ? null : this;
|
||||
Target target =
|
||||
ObjectTable.getTarget(new ObjectEndpoint(id, transport));
|
||||
|
||||
if (target == null || (impl = target.getImpl()) == null) {
|
||||
throw new NoSuchObjectException("no such object in table");
|
||||
}
|
||||
|
||||
final Dispatcher disp = target.getDispatcher();
|
||||
target.incrementCallCount();
|
||||
try {
|
||||
/* call the dispatcher */
|
||||
transportLog.log(Log.VERBOSE, "call dispatcher");
|
||||
|
||||
final AccessControlContext acc =
|
||||
target.getAccessControlContext();
|
||||
ClassLoader ccl = target.getContextClassLoader();
|
||||
|
||||
ClassLoader savedCcl = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
try {
|
||||
setContextClassLoader(ccl);
|
||||
currentTransport.set(this);
|
||||
try {
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedExceptionAction<Void>() {
|
||||
public Void run() throws IOException {
|
||||
checkAcceptPermission(acc);
|
||||
disp.dispatch(impl, call);
|
||||
return null;
|
||||
}
|
||||
}, acc);
|
||||
} catch (java.security.PrivilegedActionException pae) {
|
||||
throw (IOException) pae.getException();
|
||||
}
|
||||
} finally {
|
||||
setContextClassLoader(savedCcl);
|
||||
currentTransport.set(null);
|
||||
}
|
||||
|
||||
} catch (IOException ex) {
|
||||
transportLog.log(Log.BRIEF,
|
||||
"exception thrown by dispatcher: ", ex);
|
||||
return false;
|
||||
} finally {
|
||||
target.decrementCallCount();
|
||||
}
|
||||
|
||||
} catch (RemoteException e) {
|
||||
|
||||
// if calls are being logged, write out exception
|
||||
if (UnicastServerRef.callLog.isLoggable(Log.BRIEF)) {
|
||||
// include client host name if possible
|
||||
String clientHost = "";
|
||||
try {
|
||||
clientHost = "[" +
|
||||
RemoteServer.getClientHost() + "] ";
|
||||
} catch (ServerNotActiveException ex) {
|
||||
}
|
||||
String message = clientHost + "exception: ";
|
||||
UnicastServerRef.callLog.log(Log.BRIEF, message, e);
|
||||
}
|
||||
|
||||
/* We will get a RemoteException if either a) the objID is
|
||||
* not readable, b) the target is not in the object table, or
|
||||
* c) the object is in the midst of being unexported (note:
|
||||
* NoSuchObjectException is thrown by the incrementCallCount
|
||||
* method if the object is being unexported). Here it is
|
||||
* relatively safe to marshal an exception to the client
|
||||
* since the client will not have seen a return value yet.
|
||||
*/
|
||||
try {
|
||||
ObjectOutput out = call.getResultStream(false);
|
||||
UnicastServerRef.clearStackTraces(e);
|
||||
out.writeObject(e);
|
||||
call.releaseOutputStream();
|
||||
|
||||
} catch (IOException ie) {
|
||||
transportLog.log(Log.BRIEF,
|
||||
"exception thrown marshalling exception: ", ie);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
61
jdkSrc/jdk8/sun/rmi/transport/TransportConstants.java
Normal file
61
jdkSrc/jdk8/sun/rmi/transport/TransportConstants.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.transport;
|
||||
|
||||
public class TransportConstants {
|
||||
/** Transport magic number: "JRMI"*/
|
||||
public static final int Magic = 0x4a524d49;
|
||||
/** Transport version number */
|
||||
public static final short Version = 2;
|
||||
|
||||
/** Connection uses stream protocol */
|
||||
public static final byte StreamProtocol = 0x4b;
|
||||
/** Protocol for single operation per connection; no ack required */
|
||||
public static final byte SingleOpProtocol = 0x4c;
|
||||
/** Connection uses multiplex protocol */
|
||||
public static final byte MultiplexProtocol = 0x4d;
|
||||
|
||||
/** Ack for transport protocol */
|
||||
public static final byte ProtocolAck = 0x4e;
|
||||
/** Negative ack for transport protocol (protocol not supported) */
|
||||
public static final byte ProtocolNack = 0x4f;
|
||||
|
||||
/** RMI call */
|
||||
public static final byte Call = 0x50;
|
||||
/** RMI return */
|
||||
public static final byte Return = 0x51;
|
||||
/** Ping operation */
|
||||
public static final byte Ping = 0x52;
|
||||
/** Acknowledgment for Ping operation */
|
||||
public static final byte PingAck = 0x53;
|
||||
/** Acknowledgment for distributed GC */
|
||||
public static final byte DGCAck = 0x54;
|
||||
|
||||
/** Normal return (with or without return value) */
|
||||
public static final byte NormalReturn = 0x01;
|
||||
/** Exceptional return */
|
||||
public static final byte ExceptionalReturn = 0x02;
|
||||
}
|
||||
139
jdkSrc/jdk8/sun/rmi/transport/WeakRef.java
Normal file
139
jdkSrc/jdk8/sun/rmi/transport/WeakRef.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport;
|
||||
|
||||
import java.lang.ref.*;
|
||||
import sun.rmi.runtime.Log;
|
||||
|
||||
/**
|
||||
* WeakRef objects are used by the RMI runtime to hold potentially weak
|
||||
* references to exported remote objects in the local object table.
|
||||
*
|
||||
* This class extends the functionality of java.lang.ref.WeakReference in
|
||||
* several ways. The methods pin() and unpin() can be used to set
|
||||
* whether the contained reference is strong or weak (it is weak upon
|
||||
* construction). The hashCode() and equals() methods are overridden so
|
||||
* that WeakRef objects hash and compare to each other according to the
|
||||
* object identity of their referents.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
* @author Peter Jones
|
||||
*/
|
||||
class WeakRef extends WeakReference<Object> {
|
||||
|
||||
/** value of the referent's "identity" hash code */
|
||||
private int hashValue;
|
||||
|
||||
/** strong reference to the referent, for when this WeakRef is "pinned" */
|
||||
private Object strongRef = null;
|
||||
|
||||
/**
|
||||
* Create a new WeakRef to the given object.
|
||||
*/
|
||||
public WeakRef(Object obj) {
|
||||
super(obj);
|
||||
setHashValue(obj); // cache object's "identity" hash code
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new WeakRef to the given object, registered with a queue.
|
||||
*/
|
||||
public WeakRef(Object obj, ReferenceQueue<Object> q) {
|
||||
super(obj, q);
|
||||
setHashValue(obj); // cache object's "identity" hash code
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin the contained reference (make this a strong reference).
|
||||
*/
|
||||
public synchronized void pin() {
|
||||
if (strongRef == null) {
|
||||
strongRef = get();
|
||||
|
||||
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
|
||||
DGCImpl.dgcLog.log(Log.VERBOSE,
|
||||
"strongRef = " + strongRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpin the contained reference (make this a weak reference).
|
||||
*/
|
||||
public synchronized void unpin() {
|
||||
if (strongRef != null) {
|
||||
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
|
||||
DGCImpl.dgcLog.log(Log.VERBOSE,
|
||||
"strongRef = " + strongRef);
|
||||
}
|
||||
|
||||
strongRef = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache referent's "identity" hash code (so that we still have the
|
||||
* value after the referent gets cleared).
|
||||
*
|
||||
* We cannot use the value from the object's hashCode() method, since
|
||||
* if the object is of a remote class not extended from RemoteObject
|
||||
* and it is trying to implement hashCode() and equals() so that it
|
||||
* can be compared to stub objects, its own hash code could not have
|
||||
* been initialized yet (see bugid 4102938). Also, object table keys
|
||||
* based on server objects are indeed matched on object identity, so
|
||||
* this is the correct hash technique regardless.
|
||||
*/
|
||||
private void setHashValue(Object obj) {
|
||||
if (obj != null) {
|
||||
hashValue = System.identityHashCode(obj);
|
||||
} else {
|
||||
hashValue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always return the "identity" hash code of the original referent.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if "obj" is this identical WeakRef object, or, if the
|
||||
* contained reference has not been cleared, if "obj" is another WeakRef
|
||||
* object with the identical non-null referent. Otherwise, return false.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof WeakRef) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
|
||||
Object referent = get();
|
||||
return (referent != null) && (referent == ((WeakRef) obj).get());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
423
jdkSrc/jdk8/sun/rmi/transport/proxy/CGIHandler.java
Normal file
423
jdkSrc/jdk8/sun/rmi/transport/proxy/CGIHandler.java
Normal file
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport.proxy;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* CGIClientException is thrown when an error is detected
|
||||
* in a client's request.
|
||||
*/
|
||||
class CGIClientException extends Exception {
|
||||
private static final long serialVersionUID = 8147981687059865216L;
|
||||
|
||||
public CGIClientException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public CGIClientException(String s, Throwable cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CGIServerException is thrown when an error occurs here on the server.
|
||||
*/
|
||||
class CGIServerException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 6928425456704527017L;
|
||||
|
||||
public CGIServerException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public CGIServerException(String s, Throwable cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CGICommandHandler is the interface to an object that handles a
|
||||
* particular supported command.
|
||||
*/
|
||||
interface CGICommandHandler {
|
||||
|
||||
/**
|
||||
* Return the string form of the command
|
||||
* to be recognized in the query string.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Execute the command with the given string as parameter.
|
||||
*/
|
||||
public void execute(String param) throws CGIClientException, CGIServerException;
|
||||
}
|
||||
|
||||
/**
|
||||
* The CGIHandler class contains methods for executing as a CGI program.
|
||||
* The main function interprets the query string as a command of the form
|
||||
* "<command>=<parameters>".
|
||||
*
|
||||
* This class depends on the CGI 1.0 environment variables being set as
|
||||
* properties of the same name in this Java VM.
|
||||
*
|
||||
* All data and methods of this class are static because they are specific
|
||||
* to this particular CGI process.
|
||||
*/
|
||||
public final class CGIHandler {
|
||||
|
||||
/* get CGI parameters that we need */
|
||||
static int ContentLength;
|
||||
static String QueryString;
|
||||
static String RequestMethod;
|
||||
static String ServerName;
|
||||
static int ServerPort;
|
||||
|
||||
static {
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
ContentLength =
|
||||
Integer.getInteger("CONTENT_LENGTH", 0).intValue();
|
||||
QueryString = System.getProperty("QUERY_STRING", "");
|
||||
RequestMethod = System.getProperty("REQUEST_METHOD", "");
|
||||
ServerName = System.getProperty("SERVER_NAME", "");
|
||||
ServerPort = Integer.getInteger("SERVER_PORT", 0).intValue();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* list of handlers for supported commands */
|
||||
private static CGICommandHandler commands[] = {
|
||||
new CGIForwardCommand(),
|
||||
new CGIGethostnameCommand(),
|
||||
new CGIPingCommand(),
|
||||
new CGITryHostnameCommand()
|
||||
};
|
||||
|
||||
/* construct table mapping command strings to handlers */
|
||||
private static Hashtable<String, CGICommandHandler> commandLookup;
|
||||
static {
|
||||
commandLookup = new Hashtable<>();
|
||||
for (int i = 0; i < commands.length; ++ i)
|
||||
commandLookup.put(commands[i].getName(), commands[i]);
|
||||
}
|
||||
|
||||
/* prevent instantiation of this class */
|
||||
private CGIHandler() {}
|
||||
|
||||
/**
|
||||
* Execute command given in query string on URL. The string before
|
||||
* the first '=' is interpreted as the command name, and the string
|
||||
* after the first '=' is the parameters to the command.
|
||||
*/
|
||||
public static void main(String args[])
|
||||
{
|
||||
try {
|
||||
String command, param;
|
||||
int delim = QueryString.indexOf("=");
|
||||
if (delim == -1) {
|
||||
command = QueryString;
|
||||
param = "";
|
||||
}
|
||||
else {
|
||||
command = QueryString.substring(0, delim);
|
||||
param = QueryString.substring(delim + 1);
|
||||
}
|
||||
CGICommandHandler handler =
|
||||
commandLookup.get(command);
|
||||
if (handler != null)
|
||||
try {
|
||||
handler.execute(param);
|
||||
} catch (CGIClientException e) {
|
||||
e.printStackTrace();
|
||||
returnClientError(e.getMessage());
|
||||
} catch (CGIServerException e) {
|
||||
e.printStackTrace();
|
||||
returnServerError(e.getMessage());
|
||||
}
|
||||
else
|
||||
returnClientError("invalid command.");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
returnServerError("internal error: " + e.getMessage());
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an HTML error message indicating there was error in
|
||||
* the client's request.
|
||||
*/
|
||||
private static void returnClientError(String message)
|
||||
{
|
||||
System.out.println("Status: 400 Bad Request: " + message);
|
||||
System.out.println("Content-type: text/html");
|
||||
System.out.println("");
|
||||
System.out.println("<HTML>" +
|
||||
"<HEAD><TITLE>Java RMI Client Error" +
|
||||
"</TITLE></HEAD>" +
|
||||
"<BODY>");
|
||||
System.out.println("<H1>Java RMI Client Error</H1>");
|
||||
System.out.println("");
|
||||
System.out.println(message);
|
||||
System.out.println("</BODY></HTML>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an HTML error message indicating an error occurred
|
||||
* here on the server.
|
||||
*/
|
||||
private static void returnServerError(String message)
|
||||
{
|
||||
System.out.println("Status: 500 Server Error: " + message);
|
||||
System.out.println("Content-type: text/html");
|
||||
System.out.println("");
|
||||
System.out.println("<HTML>" +
|
||||
"<HEAD><TITLE>Java RMI Server Error" +
|
||||
"</TITLE></HEAD>" +
|
||||
"<BODY>");
|
||||
System.out.println("<H1>Java RMI Server Error</H1>");
|
||||
System.out.println("");
|
||||
System.out.println(message);
|
||||
System.out.println("</BODY></HTML>");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "forward" command: Forward request body to local port on the server,
|
||||
* and send response back to client.
|
||||
*/
|
||||
final class CGIForwardCommand implements CGICommandHandler {
|
||||
|
||||
public String getName() {
|
||||
return "forward";
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private String getLine (DataInputStream socketIn) throws IOException {
|
||||
return socketIn.readLine();
|
||||
}
|
||||
|
||||
public void execute(String param) throws CGIClientException, CGIServerException
|
||||
{
|
||||
if (!CGIHandler.RequestMethod.equals("POST"))
|
||||
throw new CGIClientException("can only forward POST requests");
|
||||
|
||||
int port;
|
||||
try {
|
||||
port = Integer.parseInt(param);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new CGIClientException("invalid port number.", e);
|
||||
}
|
||||
if (port <= 0 || port > 0xFFFF)
|
||||
throw new CGIClientException("invalid port: " + port);
|
||||
if (port < 1024)
|
||||
throw new CGIClientException("permission denied for port: " +
|
||||
port);
|
||||
|
||||
byte buffer[];
|
||||
Socket socket;
|
||||
try {
|
||||
socket = new Socket(InetAddress.getLocalHost(), port);
|
||||
} catch (IOException e) {
|
||||
throw new CGIServerException("could not connect to local port", e);
|
||||
}
|
||||
|
||||
/*
|
||||
* read client's request body
|
||||
*/
|
||||
DataInputStream clientIn = new DataInputStream(System.in);
|
||||
buffer = new byte[CGIHandler.ContentLength];
|
||||
try {
|
||||
clientIn.readFully(buffer);
|
||||
} catch (EOFException e) {
|
||||
throw new CGIClientException("unexpected EOF reading request body", e);
|
||||
} catch (IOException e) {
|
||||
throw new CGIClientException("error reading request body", e);
|
||||
}
|
||||
|
||||
/*
|
||||
* send to local server in HTTP
|
||||
*/
|
||||
try {
|
||||
DataOutputStream socketOut =
|
||||
new DataOutputStream(socket.getOutputStream());
|
||||
socketOut.writeBytes("POST / HTTP/1.0\r\n");
|
||||
socketOut.writeBytes("Content-length: " +
|
||||
CGIHandler.ContentLength + "\r\n\r\n");
|
||||
socketOut.write(buffer);
|
||||
socketOut.flush();
|
||||
} catch (IOException e) {
|
||||
throw new CGIServerException("error writing to server", e);
|
||||
}
|
||||
|
||||
/*
|
||||
* read response
|
||||
*/
|
||||
DataInputStream socketIn;
|
||||
try {
|
||||
socketIn = new DataInputStream(socket.getInputStream());
|
||||
} catch (IOException e) {
|
||||
throw new CGIServerException("error reading from server", e);
|
||||
}
|
||||
String key = "Content-length:".toLowerCase();
|
||||
boolean contentLengthFound = false;
|
||||
String line;
|
||||
int responseContentLength = -1;
|
||||
do {
|
||||
try {
|
||||
line = getLine(socketIn);
|
||||
} catch (IOException e) {
|
||||
throw new CGIServerException("error reading from server", e);
|
||||
}
|
||||
if (line == null)
|
||||
throw new CGIServerException(
|
||||
"unexpected EOF reading server response");
|
||||
|
||||
if (line.toLowerCase().startsWith(key)) {
|
||||
if (contentLengthFound) {
|
||||
throw new CGIServerException(
|
||||
"Multiple Content-length entries found.");
|
||||
} else {
|
||||
responseContentLength =
|
||||
Integer.parseInt(line.substring(key.length()).trim());
|
||||
contentLengthFound = true;
|
||||
}
|
||||
}
|
||||
} while ((line.length() != 0) &&
|
||||
(line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
|
||||
|
||||
if (!contentLengthFound || responseContentLength < 0)
|
||||
throw new CGIServerException(
|
||||
"missing or invalid content length in server response");
|
||||
buffer = new byte[responseContentLength];
|
||||
try {
|
||||
socketIn.readFully(buffer);
|
||||
} catch (EOFException e) {
|
||||
throw new CGIServerException(
|
||||
"unexpected EOF reading server response", e);
|
||||
} catch (IOException e) {
|
||||
throw new CGIServerException("error reading from server", e);
|
||||
}
|
||||
|
||||
/*
|
||||
* send response back to client
|
||||
*/
|
||||
System.out.println("Status: 200 OK");
|
||||
System.out.println("Content-type: application/octet-stream");
|
||||
System.out.println("");
|
||||
try {
|
||||
System.out.write(buffer);
|
||||
} catch (IOException e) {
|
||||
throw new CGIServerException("error writing response", e);
|
||||
}
|
||||
System.out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "gethostname" command: Return the host name of the server as the
|
||||
* response body
|
||||
*/
|
||||
final class CGIGethostnameCommand implements CGICommandHandler {
|
||||
|
||||
public String getName() {
|
||||
return "gethostname";
|
||||
}
|
||||
|
||||
public void execute(String param)
|
||||
{
|
||||
System.out.println("Status: 200 OK");
|
||||
System.out.println("Content-type: application/octet-stream");
|
||||
System.out.println("Content-length: " +
|
||||
CGIHandler.ServerName.length());
|
||||
System.out.println("");
|
||||
System.out.print(CGIHandler.ServerName);
|
||||
System.out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "ping" command: Return an OK status to indicate that connection
|
||||
* was successful.
|
||||
*/
|
||||
final class CGIPingCommand implements CGICommandHandler {
|
||||
|
||||
public String getName() {
|
||||
return "ping";
|
||||
}
|
||||
|
||||
public void execute(String param)
|
||||
{
|
||||
System.out.println("Status: 200 OK");
|
||||
System.out.println("Content-type: application/octet-stream");
|
||||
System.out.println("Content-length: 0");
|
||||
System.out.println("");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "tryhostname" command: Return a human readable message describing
|
||||
* what host name is available to local Java VMs.
|
||||
*/
|
||||
final class CGITryHostnameCommand implements CGICommandHandler {
|
||||
|
||||
public String getName() {
|
||||
return "tryhostname";
|
||||
}
|
||||
|
||||
public void execute(String param)
|
||||
{
|
||||
System.out.println("Status: 200 OK");
|
||||
System.out.println("Content-type: text/html");
|
||||
System.out.println("");
|
||||
System.out.println("<HTML>" +
|
||||
"<HEAD><TITLE>Java RMI Server Hostname Info" +
|
||||
"</TITLE></HEAD>" +
|
||||
"<BODY>");
|
||||
System.out.println("<H1>Java RMI Server Hostname Info</H1>");
|
||||
System.out.println("<H2>Local host name available to Java VM:</H2>");
|
||||
System.out.print("<P>InetAddress.getLocalHost().getHostName()");
|
||||
try {
|
||||
String localHostName = InetAddress.getLocalHost().getHostName();
|
||||
|
||||
System.out.println(" = " + localHostName);
|
||||
} catch (UnknownHostException e) {
|
||||
System.out.println(" threw java.net.UnknownHostException");
|
||||
}
|
||||
|
||||
System.out.println("<H2>Server host information obtained through CGI interface from HTTP server:</H2>");
|
||||
System.out.println("<P>SERVER_NAME = " + CGIHandler.ServerName);
|
||||
System.out.println("<P>SERVER_PORT = " + CGIHandler.ServerPort);
|
||||
System.out.println("</BODY></HTML>");
|
||||
}
|
||||
}
|
||||
114
jdkSrc/jdk8/sun/rmi/transport/proxy/HttpAwareServerSocket.java
Normal file
114
jdkSrc/jdk8/sun/rmi/transport/proxy/HttpAwareServerSocket.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport.proxy;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import sun.rmi.runtime.Log;
|
||||
|
||||
/**
|
||||
* The HttpAwareServerSocket class extends the java.net.ServerSocket
|
||||
* class. It behaves like a ServerSocket, except that if
|
||||
* the first four bytes of an accepted socket are the letters "POST",
|
||||
* then it returns an HttpReceiveSocket instead of a java.net.Socket.
|
||||
* This means that the accept method blocks until four bytes have been
|
||||
* read from the new socket's input stream.
|
||||
*/
|
||||
class HttpAwareServerSocket extends ServerSocket {
|
||||
|
||||
/**
|
||||
* Create a server socket on a specified port.
|
||||
* @param port the port
|
||||
* @exception IOException IO error when opening the socket.
|
||||
*/
|
||||
public HttpAwareServerSocket(int port) throws IOException
|
||||
{
|
||||
super(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a server socket, bind it to the specified local port
|
||||
* and listen to it. You can connect to an annonymous port by
|
||||
* specifying the port number to be 0. <i>backlog</i> specifies
|
||||
* how many connection requests the system will queue up while waiting
|
||||
* for the ServerSocket to execute accept().
|
||||
* @param port the specified port
|
||||
* @param backlog the number of queued connect requests pending accept
|
||||
*/
|
||||
public HttpAwareServerSocket(int port, int backlog) throws IOException
|
||||
{
|
||||
super(port, backlog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept a connection. This method will block until the connection
|
||||
* is made and four bytes can be read from the input stream.
|
||||
* If the first four bytes are "POST", then an HttpReceiveSocket is
|
||||
* returned, which will handle the HTTP protocol wrapping.
|
||||
* Otherwise, a WrappedSocket is returned. The input stream will be
|
||||
* reset to the beginning of the transmission.
|
||||
* In either case, a BufferedInputStream will already be on top of
|
||||
* the underlying socket's input stream.
|
||||
* @exception IOException IO error when waiting for the connection.
|
||||
*/
|
||||
public Socket accept() throws IOException
|
||||
{
|
||||
Socket socket = super.accept();
|
||||
BufferedInputStream in =
|
||||
new BufferedInputStream(socket.getInputStream());
|
||||
|
||||
RMIMasterSocketFactory.proxyLog.log(Log.BRIEF,
|
||||
"socket accepted (checking for POST)");
|
||||
|
||||
in.mark(4);
|
||||
boolean isHttp = (in.read() == 'P') &&
|
||||
(in.read() == 'O') &&
|
||||
(in.read() == 'S') &&
|
||||
(in.read() == 'T');
|
||||
in.reset();
|
||||
|
||||
if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.BRIEF)) {
|
||||
RMIMasterSocketFactory.proxyLog.log(Log.BRIEF,
|
||||
(isHttp ? "POST found, HTTP socket returned" :
|
||||
"POST not found, direct socket returned"));
|
||||
}
|
||||
|
||||
if (isHttp)
|
||||
return new HttpReceiveSocket(socket, in, null);
|
||||
else
|
||||
return new WrappedSocket(socket, in, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the implementation address and implementation port of
|
||||
* the HttpAwareServerSocket as a String.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return "HttpAware" + super.toString();
|
||||
}
|
||||
}
|
||||
204
jdkSrc/jdk8/sun/rmi/transport/proxy/HttpInputStream.java
Normal file
204
jdkSrc/jdk8/sun/rmi/transport/proxy/HttpInputStream.java
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport.proxy;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import sun.rmi.runtime.Log;
|
||||
|
||||
/**
|
||||
* The HttpInputStream class assists the HttpSendSocket and HttpReceiveSocket
|
||||
* classes by filtering out the header for the message as well as any
|
||||
* data after its proper content length.
|
||||
*/
|
||||
class HttpInputStream extends FilterInputStream {
|
||||
|
||||
/** bytes remaining to be read from proper content of message */
|
||||
protected int bytesLeft;
|
||||
|
||||
/** bytes remaining to be read at time of last mark */
|
||||
protected int bytesLeftAtMark;
|
||||
|
||||
/**
|
||||
* Create new filter on a given input stream.
|
||||
* @param in the InputStream to filter from
|
||||
*/
|
||||
public HttpInputStream(InputStream in) throws IOException
|
||||
{
|
||||
super(in);
|
||||
|
||||
if (in.markSupported())
|
||||
in.mark(0); // prevent resetting back to old marks
|
||||
|
||||
// pull out header, looking for content length
|
||||
|
||||
DataInputStream dis = new DataInputStream(in);
|
||||
String key = "Content-length:".toLowerCase();
|
||||
boolean contentLengthFound = false;
|
||||
String line;
|
||||
do {
|
||||
line = dis.readLine();
|
||||
|
||||
if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
|
||||
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
||||
"received header line: \"" + line + "\"");
|
||||
}
|
||||
|
||||
if (line == null)
|
||||
throw new EOFException();
|
||||
|
||||
if (line.toLowerCase().startsWith(key)) {
|
||||
if (contentLengthFound) {
|
||||
throw new IOException(
|
||||
"Multiple Content-length entries found.");
|
||||
} else {
|
||||
bytesLeft =
|
||||
Integer.parseInt(line.substring(key.length()).trim());
|
||||
contentLengthFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
// The idea here is to go past the first blank line.
|
||||
// Some DataInputStream.readLine() documentation specifies that
|
||||
// it does include the line-terminating character(s) in the
|
||||
// returned string, but it actually doesn't, so we'll cover
|
||||
// all cases here...
|
||||
} while ((line.length() != 0) &&
|
||||
(line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
|
||||
|
||||
if (!contentLengthFound || bytesLeft < 0) {
|
||||
// This really shouldn't happen, but if it does, shoud we fail??
|
||||
// For now, just give up and let a whole lot of bytes through...
|
||||
bytesLeft = Integer.MAX_VALUE;
|
||||
}
|
||||
bytesLeftAtMark = bytesLeft;
|
||||
|
||||
if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
|
||||
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
||||
"content length: " + bytesLeft);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that can be read with blocking.
|
||||
* Make sure that this does not exceed the number of bytes remaining
|
||||
* in the proper content of the message.
|
||||
*/
|
||||
public int available() throws IOException
|
||||
{
|
||||
int bytesAvailable = in.available();
|
||||
if (bytesAvailable > bytesLeft)
|
||||
bytesAvailable = bytesLeft;
|
||||
|
||||
return bytesAvailable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte of data from the stream. Make sure that one is available
|
||||
* from the proper content of the message, else -1 is returned to
|
||||
* indicate to the user that the end of the stream has been reached.
|
||||
*/
|
||||
public int read() throws IOException
|
||||
{
|
||||
if (bytesLeft > 0) {
|
||||
int data = in.read();
|
||||
if (data != -1)
|
||||
-- bytesLeft;
|
||||
|
||||
if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
|
||||
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
||||
"received byte: '" +
|
||||
((data & 0x7F) < ' ' ? " " : String.valueOf((char) data)) +
|
||||
"' " + data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
else {
|
||||
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
||||
"read past content length");
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int read(byte b[], int off, int len) throws IOException
|
||||
{
|
||||
if (bytesLeft == 0 && len > 0) {
|
||||
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
||||
"read past content length");
|
||||
|
||||
return -1;
|
||||
}
|
||||
if (len > bytesLeft)
|
||||
len = bytesLeft;
|
||||
int bytesRead = in.read(b, off, len);
|
||||
bytesLeft -= bytesRead;
|
||||
|
||||
if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
|
||||
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
||||
"read " + bytesRead + " bytes, " + bytesLeft + " remaining");
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the current position in the stream (for future calls to reset).
|
||||
* Remember where we are within the proper content of the message, so
|
||||
* that a reset method call can recreate our state properly.
|
||||
* @param readlimit how many bytes can be read before mark becomes invalid
|
||||
*/
|
||||
public void mark(int readlimit)
|
||||
{
|
||||
in.mark(readlimit);
|
||||
if (in.markSupported())
|
||||
bytesLeftAtMark = bytesLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repositions the stream to the last marked position. Make sure to
|
||||
* adjust our position within the proper content accordingly.
|
||||
*/
|
||||
public void reset() throws IOException
|
||||
{
|
||||
in.reset();
|
||||
bytesLeft = bytesLeftAtMark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips bytes of the stream. Make sure to adjust our
|
||||
* position within the proper content accordingly.
|
||||
* @param n number of bytes to be skipped
|
||||
*/
|
||||
public long skip(long n) throws IOException
|
||||
{
|
||||
if (n > bytesLeft)
|
||||
n = bytesLeft;
|
||||
long bytesSkipped = in.skip(n);
|
||||
bytesLeft -= bytesSkipped;
|
||||
return bytesSkipped;
|
||||
}
|
||||
}
|
||||
80
jdkSrc/jdk8/sun/rmi/transport/proxy/HttpOutputStream.java
Normal file
80
jdkSrc/jdk8/sun/rmi/transport/proxy/HttpOutputStream.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport.proxy;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* The HttpOutputStream class assists the HttpSendSocket and HttpReceiveSocket
|
||||
* classes by providing an output stream that buffers its entire input until
|
||||
* closed, and then it sends the complete transmission prefixed by the end of
|
||||
* an HTTP header that specifies the content length.
|
||||
*/
|
||||
class HttpOutputStream extends ByteArrayOutputStream {
|
||||
|
||||
/** the output stream to send response to */
|
||||
protected OutputStream out;
|
||||
|
||||
/** true if HTTP response has been sent */
|
||||
boolean responseSent = false;
|
||||
|
||||
/**
|
||||
* Begin buffering new HTTP response to be sent to a given stream.
|
||||
* @param out the OutputStream to send response to
|
||||
*/
|
||||
public HttpOutputStream(OutputStream out) {
|
||||
super();
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* On close, send HTTP-packaged response.
|
||||
*/
|
||||
public synchronized void close() throws IOException {
|
||||
if (!responseSent) {
|
||||
/*
|
||||
* If response would have zero content length, then make it
|
||||
* have some arbitrary data so that certain clients will not
|
||||
* fail because the "document contains no data".
|
||||
*/
|
||||
if (size() == 0)
|
||||
write(emptyData);
|
||||
|
||||
DataOutputStream dos = new DataOutputStream(out);
|
||||
dos.writeBytes("Content-type: application/octet-stream\r\n");
|
||||
dos.writeBytes("Content-length: " + size() + "\r\n");
|
||||
dos.writeBytes("\r\n");
|
||||
writeTo(dos);
|
||||
dos.flush();
|
||||
// Do not close the underlying stream here, because that would
|
||||
// close the underlying socket and prevent reading a response.
|
||||
reset(); // reset byte array
|
||||
responseSent = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** data to send if the response would otherwise be empty */
|
||||
private static byte[] emptyData = { 0 };
|
||||
}
|
||||
128
jdkSrc/jdk8/sun/rmi/transport/proxy/HttpReceiveSocket.java
Normal file
128
jdkSrc/jdk8/sun/rmi/transport/proxy/HttpReceiveSocket.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport.proxy;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* The HttpReceiveSocket class extends the WrappedSocket class
|
||||
* by removing the HTTP protocol packaging from the input stream and
|
||||
* formatting the output stream as an HTTP response.
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
* The output stream must be explicitly closed for the output to be
|
||||
* sent, since the HttpResponseOutputStream needs to buffer the entire
|
||||
* transmission to be able to fill in the content-length field of
|
||||
* the HTTP header. Closing this socket will do this.
|
||||
*
|
||||
* The constructor blocks until the HTTP protocol header
|
||||
* is received. This could be fixed, but I don't think it should be a
|
||||
* problem because this object would not be created unless the
|
||||
* HttpAwareServerSocket has detected the beginning of the header
|
||||
* anyway, so the rest should be there.
|
||||
*
|
||||
* This socket can only be used to process one POST and reply to it.
|
||||
* Another message would be received on a newly accepted socket anyway.
|
||||
*/
|
||||
public class HttpReceiveSocket extends WrappedSocket implements RMISocketInfo {
|
||||
|
||||
/** true if the HTTP header has pushed through the output stream yet */
|
||||
private boolean headerSent = false;
|
||||
|
||||
/**
|
||||
* Layer on top of a pre-existing Socket object, and use specified
|
||||
* input and output streams.
|
||||
* @param socket the pre-existing socket to use
|
||||
* @param in the InputStream to use for this socket (can be null)
|
||||
* @param out the OutputStream to use for this socket (can be null)
|
||||
*/
|
||||
public HttpReceiveSocket(Socket socket, InputStream in, OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
super(socket, in, out);
|
||||
|
||||
this.in = new HttpInputStream(in != null ? in :
|
||||
socket.getInputStream());
|
||||
this.out = (out != null ? out :
|
||||
socket.getOutputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that this socket is not reusable.
|
||||
*/
|
||||
public boolean isReusable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address to which this socket is connected. "null" is always
|
||||
* returned (to indicate an unknown address) because the originating
|
||||
* host's IP address cannot be reliably determined: both because the
|
||||
* request probably went through a proxy server, and because if it was
|
||||
* delivered by a local forwarder (CGI script or servlet), we do NOT
|
||||
* want it to appear as if the call is coming from the local host (in
|
||||
* case the remote object makes access control decisions based on the
|
||||
* "client host" of a remote call; see bugid 4399040).
|
||||
*/
|
||||
public InetAddress getInetAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an OutputStream for this socket.
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException
|
||||
{
|
||||
if (!headerSent) { // could this be done in constructor??
|
||||
DataOutputStream dos = new DataOutputStream(out);
|
||||
dos.writeBytes("HTTP/1.0 200 OK\r\n");
|
||||
dos.flush();
|
||||
headerSent = true;
|
||||
out = new HttpOutputStream(out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the socket.
|
||||
*/
|
||||
public synchronized void close() throws IOException
|
||||
{
|
||||
getOutputStream().close(); // make sure response is sent
|
||||
socket.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string representation of the socket.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return "HttpReceive" + socket.toString();
|
||||
}
|
||||
}
|
||||
161
jdkSrc/jdk8/sun/rmi/transport/proxy/HttpSendInputStream.java
Normal file
161
jdkSrc/jdk8/sun/rmi/transport/proxy/HttpSendInputStream.java
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.rmi.transport.proxy;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* The HttpSendInputStream class is used by the HttpSendSocket class as
|
||||
* a layer on the top of the InputStream it returns so that it can be
|
||||
* notified of attempts to read from it. This allows the HttpSendSocket
|
||||
* to know when it should push across its output message.
|
||||
*/
|
||||
class HttpSendInputStream extends FilterInputStream {
|
||||
|
||||
/** the HttpSendSocket object that is providing this stream */
|
||||
HttpSendSocket owner;
|
||||
|
||||
/**
|
||||
* Create new filter on a given input stream.
|
||||
* @param in the InputStream to filter from
|
||||
* @param owner the HttpSendSocket that is providing this stream
|
||||
*/
|
||||
public HttpSendInputStream(InputStream in, HttpSendSocket owner)
|
||||
throws IOException
|
||||
{
|
||||
super(in);
|
||||
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this stream as inactive for its owner socket, so the next time
|
||||
* a read is attempted, the owner will be notified and a new underlying
|
||||
* input stream obtained.
|
||||
*/
|
||||
public void deactivate()
|
||||
{
|
||||
in = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte of data from the stream.
|
||||
*/
|
||||
public int read() throws IOException
|
||||
{
|
||||
if (in == null)
|
||||
in = owner.readNotify();
|
||||
return in.read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read into an array of bytes.
|
||||
* @param b the buffer into which the data is to be read
|
||||
* @param off the start offset of the data
|
||||
* @param len the maximum number of bytes to read
|
||||
*/
|
||||
public int read(byte b[], int off, int len) throws IOException
|
||||
{
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (in == null)
|
||||
in = owner.readNotify();
|
||||
return in.read(b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip bytes of input.
|
||||
* @param n the number of bytes to be skipped
|
||||
*/
|
||||
public long skip(long n) throws IOException
|
||||
{
|
||||
if (n == 0)
|
||||
return 0;
|
||||
if (in == null)
|
||||
in = owner.readNotify();
|
||||
return in.skip(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of bytes that can be read without blocking.
|
||||
*/
|
||||
public int available() throws IOException
|
||||
{
|
||||
if (in == null)
|
||||
in = owner.readNotify();
|
||||
return in.available();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the stream.
|
||||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
owner.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the current position in the stream.
|
||||
* @param readlimit how many bytes can be read before mark becomes invalid
|
||||
*/
|
||||
public synchronized void mark(int readlimit)
|
||||
{
|
||||
if (in == null) {
|
||||
try {
|
||||
in = owner.readNotify();
|
||||
}
|
||||
catch (IOException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
in.mark(readlimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reposition the stream to the last marked position.
|
||||
*/
|
||||
public synchronized void reset() throws IOException
|
||||
{
|
||||
if (in == null)
|
||||
in = owner.readNotify();
|
||||
in.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this stream type supports mark/reset.
|
||||
*/
|
||||
public boolean markSupported()
|
||||
{
|
||||
if (in == null) {
|
||||
try {
|
||||
in = owner.readNotify();
|
||||
}
|
||||
catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return in.markSupported();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user