--- a/jdk/src/share/classes/com/sun/jndi/cosnaming/CNCtx.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/com/sun/jndi/cosnaming/CNCtx.java Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -58,8 +58,22 @@
private final static boolean debug = false;
+ /*
+ * Implement one shared ORB among all CNCtx. However, there is a public constructor
+ * accepting an ORB, so we need the option of using a given ORB.
+ */
+ private static ORB _defaultOrb;
ORB _orb; // used by ExceptionMapper and RMI/IIOP factory
public NamingContext _nc; // public for accessing underlying NamingContext
+
+ private synchronized static ORB getDefaultOrb() {
+ if (_defaultOrb == null) {
+ _defaultOrb = CorbaUtils.getOrb(null, -1,
+ new Hashtable<String, java.lang.Object>());
+ }
+ return _defaultOrb;
+ }
+
private NameComponent[] _name = null;
Hashtable<String, java.lang.Object> _env; // used by ExceptionMapper
@@ -114,8 +128,9 @@
// rest is the INS name
// Return the parsed form to prevent subsequent lookup
// from parsing the string as a composite name
- // The caller should be aware that a toString() of the name
- // will yield its INS syntax, rather than a composite syntax
+ // The caller should be aware that a toString() of the name,
+ // which came from the environment will yield its INS syntax,
+ // rather than a composite syntax
return new ResolveResult(ctx, parser.parse(rest));
}
@@ -135,10 +150,10 @@
if (orb == null || nctx == null)
throw new ConfigurationException(
"Must supply ORB or NamingContext");
- _orb = orb;
- orbTracker = tracker;
- if (orbTracker != null) {
- orbTracker.incRefCount();
+ if (orb != null) {
+ _orb = orb;
+ } else {
+ _orb = getDefaultOrb();
}
_nc = nctx;
_env = env;
@@ -212,10 +227,13 @@
org.omg.CORBA.ORB inOrb = null;
String ncIor = null;
- if (env != null) {
+ if (inOrb == null && env != null) {
inOrb = (org.omg.CORBA.ORB) env.get("java.naming.corba.orb");
}
+ if (inOrb == null)
+ inOrb = getDefaultOrb(); // will create a default ORB if none exists
+
// Extract PROVIDER_URL from environment
String provUrl = null;
if (env != null) {
@@ -226,13 +244,6 @@
// Initialize the root naming context by using the IOR supplied
// in the PROVIDER_URL
ncIor = getStringifiedIor(provUrl);
-
- if (inOrb == null) {
-
- // no ORB instance specified; create one using env and defaults
- inOrb = CorbaUtils.getOrb(null, -1, env);
- orbTracker = new OrbReuseTracker(inOrb);
- }
setOrbAndRootContext(inOrb, ncIor);
} else if (provUrl != null) {
// Initialize the root naming context by using the URL supplied
@@ -258,14 +269,8 @@
}
} else {
// No PROVIDER_URL supplied; initialize using defaults
- if (inOrb == null) {
-
- // No ORB instance specified; create one using env and defaults
- inOrb = CorbaUtils.getOrb(null, -1, env);
- orbTracker = new OrbReuseTracker(inOrb);
- if (debug) {
- System.err.println("Getting default ORB: " + inOrb + env);
- }
+ if (debug) {
+ System.err.println("Getting default ORB: " + inOrb + env);
}
setOrbAndRootContext(inOrb, (String)null);
}
@@ -286,6 +291,10 @@
*/
private String initUsingIiopUrl(ORB defOrb, String url, Hashtable<?,?> env)
throws NamingException {
+
+ if (defOrb == null)
+ defOrb = getDefaultOrb();
+
try {
IiopUrl parsedUrl = new IiopUrl(url);
@@ -294,19 +303,17 @@
for (IiopUrl.Address addr : parsedUrl.getAddresses()) {
try {
- if (defOrb != null) {
- try {
- String tmpUrl = "corbaloc:iiop:" + addr.host
- + ":" + addr.port + "/NameService";
- if (debug) {
- System.err.println("Using url: " + tmpUrl);
- }
- org.omg.CORBA.Object rootCtx =
- defOrb.string_to_object(tmpUrl);
- setOrbAndRootContext(defOrb, rootCtx);
- return parsedUrl.getStringName();
- } catch (Exception e) {} // keep going
- }
+ try {
+ String tmpUrl = "corbaloc:iiop:" + addr.host
+ + ":" + addr.port + "/NameService";
+ if (debug) {
+ System.err.println("Using url: " + tmpUrl);
+ }
+ org.omg.CORBA.Object rootCtx =
+ defOrb.string_to_object(tmpUrl);
+ setOrbAndRootContext(defOrb, rootCtx);
+ return parsedUrl.getStringName();
+ } catch (Exception e) {} // keep going
// Get ORB
if (debug) {
@@ -314,12 +321,8 @@
+ " and port " + addr.port);
}
- // Get ORB
- ORB orb = CorbaUtils.getOrb(addr.host, addr.port, env);
- orbTracker = new OrbReuseTracker(orb);
-
// Assign to fields
- setOrbAndRootContext(orb, (String)null);
+ setOrbAndRootContext(defOrb, (String)null);
return parsedUrl.getStringName();
} catch (NamingException ne) {
@@ -341,18 +344,16 @@
*/
private String initUsingCorbanameUrl(ORB orb, String url, Hashtable<?,?> env)
throws NamingException {
+
+ if (orb == null)
+ orb = getDefaultOrb();
+
try {
CorbanameUrl parsedUrl = new CorbanameUrl(url);
String corbaloc = parsedUrl.getLocation();
String cosName = parsedUrl.getStringName();
- if (orb == null) {
-
- // No ORB instance specified; create one using env and defaults
- orb = CorbaUtils.getOrb(null, -1, env);
- orbTracker = new OrbReuseTracker(orb);
- }
setOrbAndRootContext(orb, corbaloc);
return parsedUrl.getStringName();
@@ -1117,9 +1118,6 @@
}
synchronized public void incEnumCount() {
- if (orbTracker == null) {
- return;
- }
enumCount++;
if (debug) {
System.out.println("incEnumCount, new count:" + enumCount);
@@ -1128,9 +1126,6 @@
synchronized public void decEnumCount()
throws NamingException {
- if (orbTracker == null) {
- return;
- }
enumCount--;
if (debug) {
System.out.println("decEnumCount, new count:" + enumCount +
@@ -1142,14 +1137,15 @@
}
synchronized public void close() throws NamingException {
- if (orbTracker == null) {
- return;
- }
+
if (enumCount > 0) {
isCloseCalled = true;
return;
}
- orbTracker.decRefCount();
+
+ // Never destroy an orb in CNCtx.
+ // The orb we have is either the shared/default orb, or one passed in to a constructor
+ // from elsewhere, so that orb is somebody else's reponsibility.
}
protected void finalize() {
--- a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -680,9 +680,11 @@
ldr = ldr.next;
}
}
- parent.processConnectionClosure();
}
}
+ if (nparent) {
+ parent.processConnectionClosure();
+ }
}
--- a/jdk/src/share/classes/com/sun/jndi/ldap/LdapClient.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/com/sun/jndi/ldap/LdapClient.java Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -488,14 +488,16 @@
*/
void processConnectionClosure() {
// Notify listeners
- if (unsolicited.size() > 0) {
- String msg;
- if (conn != null) {
- msg = conn.host + ":" + conn.port + " connection closed";
- } else {
- msg = "Connection closed";
+ synchronized (unsolicited) {
+ if (unsolicited.size() > 0) {
+ String msg;
+ if (conn != null) {
+ msg = conn.host + ":" + conn.port + " connection closed";
+ } else {
+ msg = "Connection closed";
+ }
+ notifyUnsolicited(new CommunicationException(msg));
}
- notifyUnsolicited(new CommunicationException(msg));
}
// Remove from pool
--- a/jdk/src/share/classes/java/lang/Process.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/java/lang/Process.java Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -26,6 +26,7 @@
package java.lang;
import java.io.*;
+import java.util.concurrent.TimeUnit;
/**
* The {@link ProcessBuilder#start()} and
@@ -91,7 +92,7 @@
* @return the output stream connected to the normal input of the
* subprocess
*/
- abstract public OutputStream getOutputStream();
+ public abstract OutputStream getOutputStream();
/**
* Returns the input stream connected to the normal output of the
@@ -117,7 +118,7 @@
* @return the input stream connected to the normal output of the
* subprocess
*/
- abstract public InputStream getInputStream();
+ public abstract InputStream getInputStream();
/**
* Returns the input stream connected to the error output of the
@@ -138,7 +139,7 @@
* @return the input stream connected to the error output of
* the subprocess
*/
- abstract public InputStream getErrorStream();
+ public abstract InputStream getErrorStream();
/**
* Causes the current thread to wait, if necessary, until the
@@ -156,7 +157,51 @@
* thread while it is waiting, then the wait is ended and
* an {@link InterruptedException} is thrown.
*/
- abstract public int waitFor() throws InterruptedException;
+ public abstract int waitFor() throws InterruptedException;
+
+ /**
+ * Causes the current thread to wait, if necessary, until the
+ * subprocess represented by this {@code Process} object has
+ * terminated, or the specified waiting time elapses.
+ *
+ * <p>If the subprocess has already terminated then this method returns
+ * immediately with the value {@code true}. If the process has not
+ * terminated and the timeout value is less than, or equal to, zero, then
+ * this method returns immediately with the value {@code false}.
+ *
+ * <p>The default implementation of this methods polls the {@code exitValue}
+ * to check if the process has terminated. Concrete implementations of this
+ * class are strongly encouraged to override this method with a more
+ * efficient implementation.
+ *
+ * @param timeout the maximum time to wait
+ * @param unit the time unit of the {@code timeout} argument
+ * @return {@code true} if the subprocess has exited and {@code false} if
+ * the waiting time elapsed before the subprocess has exited.
+ * @throws InterruptedException if the current thread is interrupted
+ * while waiting.
+ * @throws NullPointerException if unit is null
+ * @since 1.8
+ */
+ public boolean waitFor(long timeout, TimeUnit unit)
+ throws InterruptedException
+ {
+ long startTime = System.nanoTime();
+ long rem = unit.toNanos(timeout);
+
+ do {
+ try {
+ exitValue();
+ return true;
+ } catch(IllegalThreadStateException ex) {
+ if (rem > 0)
+ Thread.sleep(
+ Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100));
+ }
+ rem = unit.toNanos(timeout) - (System.nanoTime() - startTime);
+ } while (rem > 0);
+ return false;
+ }
/**
* Returns the exit value for the subprocess.
@@ -167,11 +212,54 @@
* @throws IllegalThreadStateException if the subprocess represented
* by this {@code Process} object has not yet terminated
*/
- abstract public int exitValue();
+ public abstract int exitValue();
+
+ /**
+ * Kills the subprocess. Whether the subprocess represented by this
+ * {@code Process} object is forcibly terminated or not is
+ * implementation dependent.
+ */
+ public abstract void destroy();
/**
* Kills the subprocess. The subprocess represented by this
* {@code Process} object is forcibly terminated.
+ *
+ * <p>The default implementation of this method invokes {@link #destroy}
+ * and so may not forcibly terminate the process. Concrete implementations
+ * of this class are strongly encouraged to override this method with a
+ * compliant implementation. Invoking this method on {@code Process}
+ * objects returned by {@link ProcessBuilder#start} and
+ * {@link Runtime#exec} will forcibly terminate the process.
+ *
+ * <p>Note: The subprocess may not terminate immediately.
+ * i.e. {@code isAlive()} may return true for a brief period
+ * after {@code destroyForcibly()} is called. This method
+ * may be chained to {@code waitFor()} if needed.
+ *
+ * @return the {@code Process} object representing the
+ * subprocess to be forcibly destroyed.
+ * @since 1.8
*/
- abstract public void destroy();
+ public Process destroyForcibly() {
+ destroy();
+ return this;
+ }
+
+ /**
+ * Tests whether the subprocess represented by this {@code Process} is
+ * alive.
+ *
+ * @return {@code true} if the subprocess represented by this
+ * {@code Process} object has not yet terminated.
+ * @since 1.8
+ */
+ public boolean isAlive() {
+ try {
+ exitValue();
+ return false;
+ } catch(IllegalThreadStateException e) {
+ return true;
+ }
+ }
}
--- a/jdk/src/share/classes/java/lang/String.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/java/lang/String.java Tue Jul 03 20:58:02 2012 -0700
@@ -1921,17 +1921,17 @@
* <blockquote><pre>
* str.substring(begin, end)</pre></blockquote>
*
- * This method is defined so that the <tt>String</tt> class can implement
+ * This method is defined so that the {@code String} class can implement
* the {@link CharSequence} interface. </p>
*
- * @param beginIndex the begin index, inclusive.
- * @param endIndex the end index, exclusive.
- * @return the specified subsequence.
+ * @param beginIndex the begin index, inclusive.
+ * @param endIndex the end index, exclusive.
+ * @return the specified subsequence.
*
* @throws IndexOutOfBoundsException
- * if <tt>beginIndex</tt> or <tt>endIndex</tt> are negative,
- * if <tt>endIndex</tt> is greater than <tt>length()</tt>,
- * or if <tt>beginIndex</tt> is greater than <tt>startIndex</tt>
+ * if {@code beginIndex} or {@code endIndex} is negative,
+ * if {@code endIndex} is greater than {@code length()},
+ * or if {@code beginIndex} is greater than {@code endIndex}
*
* @since 1.4
* @spec JSR-51
--- a/jdk/src/share/classes/java/lang/StringBuffer.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/java/lang/StringBuffer.java Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -39,29 +39,38 @@
* that is consistent with the order of the method calls made by each of
* the individual threads involved.
* <p>
- * The principal operations on a <code>StringBuffer</code> are the
- * <code>append</code> and <code>insert</code> methods, which are
+ * The principal operations on a {@code StringBuffer} are the
+ * {@code append} and {@code insert} methods, which are
* overloaded so as to accept data of any type. Each effectively
* converts a given datum to a string and then appends or inserts the
* characters of that string to the string buffer. The
- * <code>append</code> method always adds these characters at the end
- * of the buffer; the <code>insert</code> method adds the characters at
+ * {@code append} method always adds these characters at the end
+ * of the buffer; the {@code insert} method adds the characters at
* a specified point.
* <p>
- * For example, if <code>z</code> refers to a string buffer object
- * whose current contents are "<code>start</code>", then
- * the method call <code>z.append("le")</code> would cause the string
- * buffer to contain "<code>startle</code>", whereas
- * <code>z.insert(4, "le")</code> would alter the string buffer to
- * contain "<code>starlet</code>".
+ * For example, if {@code z} refers to a string buffer object
+ * whose current contents are {@code "start"}, then
+ * the method call {@code z.append("le")} would cause the string
+ * buffer to contain {@code "startle"}, whereas
+ * {@code z.insert(4, "le")} would alter the string buffer to
+ * contain {@code "starlet"}.
* <p>
- * In general, if sb refers to an instance of a <code>StringBuffer</code>,
- * then <code>sb.append(x)</code> has the same effect as
- * <code>sb.insert(sb.length(), x)</code>.
+ * In general, if sb refers to an instance of a {@code StringBuffer},
+ * then {@code sb.append(x)} has the same effect as
+ * {@code sb.insert(sb.length(), x)}.
* <p>
* Whenever an operation occurs involving a source sequence (such as
- * appending or inserting from a source sequence) this class synchronizes
+ * appending or inserting from a source sequence), this class synchronizes
* only on the string buffer performing the operation, not on the source.
+ * Note that while {@code StringBuffer} is designed to be safe to use
+ * concurrently from multiple threads, if the constructor or the
+ * {@code append} or {@code insert} operation is passed a source sequence
+ * that is shared across threads, the calling code must ensure
+ * that the operation has a consistent and unchanging view of the source
+ * sequence for the duration of the operation.
+ * This could be satisfied by the caller holding a lock during the
+ * operation's call, by using an immutable source sequence, or by not
+ * sharing the source sequence across threads.
* <p>
* Every string buffer has a capacity. As long as the length of the
* character sequence contained in the string buffer does not exceed
@@ -101,8 +110,8 @@
* the specified initial capacity.
*
* @param capacity the initial capacity.
- * @exception NegativeArraySizeException if the <code>capacity</code>
- * argument is less than <code>0</code>.
+ * @exception NegativeArraySizeException if the {@code capacity}
+ * argument is less than {@code 0}.
*/
public StringBuffer(int capacity) {
super(capacity);
@@ -111,10 +120,10 @@
/**
* Constructs a string buffer initialized to the contents of the
* specified string. The initial capacity of the string buffer is
- * <code>16</code> plus the length of the string argument.
+ * {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
- * @exception NullPointerException if <code>str</code> is <code>null</code>
+ * @exception NullPointerException if {@code str} is {@code null}
*/
public StringBuffer(String str) {
super(str.length() + 16);
@@ -123,16 +132,16 @@
/**
* Constructs a string buffer that contains the same characters
- * as the specified <code>CharSequence</code>. The initial capacity of
- * the string buffer is <code>16</code> plus the length of the
- * <code>CharSequence</code> argument.
+ * as the specified {@code CharSequence}. The initial capacity of
+ * the string buffer is {@code 16} plus the length of the
+ * {@code CharSequence} argument.
* <p>
- * If the length of the specified <code>CharSequence</code> is
+ * If the length of the specified {@code CharSequence} is
* less than or equal to zero, then an empty buffer of capacity
- * <code>16</code> is returned.
+ * {@code 16} is returned.
*
* @param seq the sequence to copy.
- * @exception NullPointerException if <code>seq</code> is <code>null</code>
+ * @exception NullPointerException if {@code seq} is {@code null}
* @since 1.5
*/
public StringBuffer(CharSequence seq) {
@@ -253,10 +262,10 @@
* the new character sequence is equal to the character at index <i>k</i>
* in the old character sequence, if <i>k</i> is less than <i>n</i>;
* otherwise, it is equal to the character at index <i>k-n</i> in the
- * argument <code>sb</code>.
+ * argument {@code sb}.
* <p>
- * This method synchronizes on <code>this</code> (the destination)
- * object but does not synchronize on the source (<code>sb</code>).
+ * This method synchronizes on {@code this}, the destination
+ * object, but does not synchronize on the source ({@code sb}).
*
* @param sb the <tt>StringBuffer</tt> to append.
* @return a reference to this object.
@@ -269,23 +278,23 @@
/**
- * Appends the specified <code>CharSequence</code> to this
+ * Appends the specified {@code CharSequence} to this
* sequence.
* <p>
- * The characters of the <code>CharSequence</code> argument are appended,
+ * The characters of the {@code CharSequence} argument are appended,
* in order, increasing the length of this sequence by the length of the
* argument.
*
* <p>The result of this method is exactly the same as if it were an
* invocation of this.append(s, 0, s.length());
*
- * <p>This method synchronizes on this (the destination)
- * object but does not synchronize on the source (<code>s</code>).
+ * <p>This method synchronizes on {@code this}, the destination
+ * object, but does not synchronize on the source ({@code s}).
*
- * <p>If <code>s</code> is <code>null</code>, then the four characters
- * <code>"null"</code> are appended.
+ * <p>If {@code s} is {@code null}, then the four characters
+ * {@code "null"} are appended.
*
- * @param s the <code>CharSequence</code> to append.
+ * @param s the {@code CharSequence} to append.
* @return a reference to this object.
* @since 1.5
*/
--- a/jdk/src/share/classes/java/util/InvalidPropertiesFormatException.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/java/util/InvalidPropertiesFormatException.java Tue Jul 03 20:58:02 2012 -0700
@@ -44,6 +44,9 @@
*/
public class InvalidPropertiesFormatException extends IOException {
+
+ private static final long serialVersionUID = 7763056076009360219L;
+
/**
* Constructs an InvalidPropertiesFormatException with the specified
* cause.
--- a/jdk/src/share/classes/java/util/concurrent/PriorityBlockingQueue.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/PriorityBlockingQueue.java Tue Jul 03 20:58:02 2012 -0700
@@ -35,7 +35,8 @@
package java.util.concurrent;
-import java.util.concurrent.locks.*;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.*;
/**
@@ -111,7 +112,7 @@
* java.util.PriorityQueue operations within a lock, as was done
* in a previous version of this class. To maintain
* interoperability, a plain PriorityQueue is still used during
- * serialization, which maintains compatibility at the espense of
+ * serialization, which maintains compatibility at the expense of
* transiently doubling overhead.
*/
@@ -308,14 +309,13 @@
/**
* Mechanics for poll(). Call only while holding lock.
*/
- private E extract() {
- E result;
+ private E dequeue() {
int n = size - 1;
if (n < 0)
- result = null;
+ return null;
else {
Object[] array = queue;
- result = (E) array[0];
+ E result = (E) array[0];
E x = (E) array[n];
array[n] = null;
Comparator<? super E> cmp = comparator;
@@ -324,8 +324,8 @@
else
siftDownUsingComparator(0, x, array, n, cmp);
size = n;
+ return result;
}
- return result;
}
/**
@@ -382,39 +382,43 @@
*/
private static <T> void siftDownComparable(int k, T x, Object[] array,
int n) {
- Comparable<? super T> key = (Comparable<? super T>)x;
- int half = n >>> 1; // loop while a non-leaf
- while (k < half) {
- int child = (k << 1) + 1; // assume left child is least
- Object c = array[child];
- int right = child + 1;
- if (right < n &&
- ((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
- c = array[child = right];
- if (key.compareTo((T) c) <= 0)
- break;
- array[k] = c;
- k = child;
+ if (n > 0) {
+ Comparable<? super T> key = (Comparable<? super T>)x;
+ int half = n >>> 1; // loop while a non-leaf
+ while (k < half) {
+ int child = (k << 1) + 1; // assume left child is least
+ Object c = array[child];
+ int right = child + 1;
+ if (right < n &&
+ ((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
+ c = array[child = right];
+ if (key.compareTo((T) c) <= 0)
+ break;
+ array[k] = c;
+ k = child;
+ }
+ array[k] = key;
}
- array[k] = key;
}
private static <T> void siftDownUsingComparator(int k, T x, Object[] array,
int n,
Comparator<? super T> cmp) {
- int half = n >>> 1;
- while (k < half) {
- int child = (k << 1) + 1;
- Object c = array[child];
- int right = child + 1;
- if (right < n && cmp.compare((T) c, (T) array[right]) > 0)
- c = array[child = right];
- if (cmp.compare(x, (T) c) <= 0)
- break;
- array[k] = c;
- k = child;
+ if (n > 0) {
+ int half = n >>> 1;
+ while (k < half) {
+ int child = (k << 1) + 1;
+ Object c = array[child];
+ int right = child + 1;
+ if (right < n && cmp.compare((T) c, (T) array[right]) > 0)
+ c = array[child = right];
+ if (cmp.compare(x, (T) c) <= 0)
+ break;
+ array[k] = c;
+ k = child;
+ }
+ array[k] = x;
}
- array[k] = x;
}
/**
@@ -520,13 +524,11 @@
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
- E result;
try {
- result = extract();
+ return dequeue();
} finally {
lock.unlock();
}
- return result;
}
public E take() throws InterruptedException {
@@ -534,7 +536,7 @@
lock.lockInterruptibly();
E result;
try {
- while ( (result = extract()) == null)
+ while ( (result = dequeue()) == null)
notEmpty.await();
} finally {
lock.unlock();
@@ -548,7 +550,7 @@
lock.lockInterruptibly();
E result;
try {
- while ( (result = extract()) == null && nanos > 0)
+ while ( (result = dequeue()) == null && nanos > 0)
nanos = notEmpty.awaitNanos(nanos);
} finally {
lock.unlock();
@@ -559,13 +561,11 @@
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
- E result;
try {
- result = size > 0 ? (E) queue[0] : null;
+ return (size == 0) ? null : (E) queue[0];
} finally {
lock.unlock();
}
- return result;
}
/**
@@ -649,32 +649,28 @@
* @return {@code true} if this queue changed as a result of the call
*/
public boolean remove(Object o) {
- boolean removed = false;
final ReentrantLock lock = this.lock;
lock.lock();
try {
int i = indexOf(o);
- if (i != -1) {
- removeAt(i);
- removed = true;
- }
+ if (i == -1)
+ return false;
+ removeAt(i);
+ return true;
} finally {
lock.unlock();
}
- return removed;
}
-
/**
* Identity-based version for use in Itr.remove
*/
- private void removeEQ(Object o) {
+ void removeEQ(Object o) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] array = queue;
- int n = size;
- for (int i = 0; i < n; i++) {
+ for (int i = 0, n = size; i < n; i++) {
if (o == array[i]) {
removeAt(i);
break;
@@ -694,15 +690,13 @@
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
- int index;
final ReentrantLock lock = this.lock;
lock.lock();
try {
- index = indexOf(o);
+ return indexOf(o) != -1;
} finally {
lock.unlock();
}
- return index != -1;
}
/**
@@ -728,7 +722,6 @@
}
}
-
public String toString() {
final ReentrantLock lock = this.lock;
lock.lock();
@@ -739,7 +732,7 @@
StringBuilder sb = new StringBuilder();
sb.append('[');
for (int i = 0; i < n; ++i) {
- E e = (E)queue[i];
+ Object e = queue[i];
sb.append(e == this ? "(this Collection)" : e);
if (i != n - 1)
sb.append(',').append(' ');
@@ -757,23 +750,7 @@
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c) {
- if (c == null)
- throw new NullPointerException();
- if (c == this)
- throw new IllegalArgumentException();
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- int n = 0;
- E e;
- while ( (e = extract()) != null) {
- c.add(e);
- ++n;
- }
- return n;
- } finally {
- lock.unlock();
- }
+ return drainTo(c, Integer.MAX_VALUE);
}
/**
@@ -792,11 +769,10 @@
final ReentrantLock lock = this.lock;
lock.lock();
try {
- int n = 0;
- E e;
- while (n < maxElements && (e = extract()) != null) {
- c.add(e);
- ++n;
+ int n = Math.min(size, maxElements);
+ for (int i = 0; i < n; i++) {
+ c.add((E) queue[0]); // In this order, in case add() throws.
+ dequeue();
}
return n;
} finally {
@@ -844,8 +820,7 @@
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
- * <pre>
- * String[] y = x.toArray(new String[0]);</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -898,7 +873,7 @@
*/
final class Itr implements Iterator<E> {
final Object[] array; // Array of all elements
- int cursor; // index of next element to return;
+ int cursor; // index of next element to return
int lastRet; // index of last element, or -1 if no such
Itr(Object[] array) {
@@ -926,17 +901,18 @@
}
/**
- * Saves the state to a stream (that is, serializes it). For
- * compatibility with previous version of this class,
- * elements are first copied to a java.util.PriorityQueue,
- * which is then serialized.
+ * Saves this queue to a stream (that is, serializes it).
+ *
+ * For compatibility with previous version of this class, elements
+ * are first copied to a java.util.PriorityQueue, which is then
+ * serialized.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
lock.lock();
try {
- int n = size; // avoid zero capacity argument
- q = new PriorityQueue<E>(n == 0 ? 1 : n, comparator);
+ // avoid zero capacity argument
+ q = new PriorityQueue<E>(Math.max(size, 1), comparator);
q.addAll(this);
s.defaultWriteObject();
} finally {
@@ -946,10 +922,7 @@
}
/**
- * Reconstitutes the {@code PriorityBlockingQueue} instance from a stream
- * (that is, deserializes it).
- *
- * @param s the stream
+ * Reconstitutes this queue from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
--- a/jdk/src/share/classes/java/util/regex/Pattern.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/java/util/regex/Pattern.java Tue Jul 03 20:58:02 2012 -0700
@@ -2026,6 +2026,7 @@
}
}
+ @SuppressWarnings("fallthrough")
/**
* Parsing of sequences between alternations.
*/
@@ -2140,6 +2141,7 @@
return head;
}
+ @SuppressWarnings("fallthrough")
/**
* Parse and add a new Single or Slice.
*/
@@ -2978,6 +2980,7 @@
return head;
}
+ @SuppressWarnings("fallthrough")
/**
* Parses inlined match flags and set them appropriately.
*/
@@ -3019,6 +3022,7 @@
}
}
+ @SuppressWarnings("fallthrough")
/**
* Parses the second part of inlined match flags and turns off
* flags appropriately.
--- a/jdk/src/share/classes/java/util/zip/GZIPInputStream.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/java/util/zip/GZIPInputStream.java Tue Jul 03 20:58:02 2012 -0700
@@ -252,7 +252,7 @@
*/
private int readUShort(InputStream in) throws IOException {
int b = readUByte(in);
- return ((int)readUByte(in) << 8) | b;
+ return (readUByte(in) << 8) | b;
}
/*
--- a/jdk/src/share/classes/sun/tools/jar/Main.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/sun/tools/jar/Main.java Tue Jul 03 20:58:02 2012 -0700
@@ -137,7 +137,7 @@
File dir = file.getParentFile();
if (dir == null)
dir = new File(".");
- return Files.createTempFile(dir.toPath(), "jartmp", null).toFile();
+ return File.createTempFile("jartmp", null, dir);
}
private boolean ok;
--- a/jdk/src/share/classes/sun/tools/native2ascii/Main.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/classes/sun/tools/native2ascii/Main.java Tue Jul 03 20:58:02 2012 -0700
@@ -241,7 +241,9 @@
if (tempDir == null)
tempDir = new File(System.getProperty("user.dir"));
- tempFile = Files.createTempFile(tempDir.toPath(), "_N2A", ".TMP").toFile();
+ tempFile = File.createTempFile("_N2A",
+ ".TMP",
+ tempDir);
tempFile.deleteOnExit();
try {
@@ -291,7 +293,9 @@
File tempDir = f.getParentFile();
if (tempDir == null)
tempDir = new File(System.getProperty("user.dir"));
- tempFile = Files.createTempFile(tempDir.toPath(), "_N2A", ".TMP").toFile();
+ tempFile = File.createTempFile("_N2A",
+ ".TMP",
+ tempDir);
tempFile.deleteOnExit();
try {
--- a/jdk/src/share/lib/security/java.security Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/lib/security/java.security Tue Jul 03 20:58:02 2012 -0700
@@ -1,6 +1,28 @@
#
# This is the "master security properties file".
#
+# An alternate java.security properties file may be specified
+# from the command line via the system property
+#
+# -Djava.security.properties=<URL>
+#
+# This properties file appends to the master security properties file.
+# If both properties files specify values for the same key, the value
+# from the command-line properties file is selected, as it is the last
+# one loaded.
+#
+# Also, if you specify
+#
+# -Djava.security.properties==<URL> (2 equals),
+#
+# then that properties file completely overrides the master security
+# properties file.
+#
+# To disable the ability to specify an additional properties file from
+# the command line, set the key security.overridePropertiesFile
+# to false in the master security properties file. It is set to true
+# by default.
+
# In this file, various security properties are set for use by
# java.security classes. This is where users can statically register
# Cryptography Package Providers ("providers" for short). The term
--- a/jdk/src/share/lib/security/java.security-macosx Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/lib/security/java.security-macosx Tue Jul 03 20:58:02 2012 -0700
@@ -1,6 +1,28 @@
#
# This is the "master security properties file".
#
+# An alternate java.security properties file may be specified
+# from the command line via the system property
+#
+# -Djava.security.properties=<URL>
+#
+# This properties file appends to the master security properties file.
+# If both properties files specify values for the same key, the value
+# from the command-line properties file is selected, as it is the last
+# one loaded.
+#
+# Also, if you specify
+#
+# -Djava.security.properties==<URL> (2 equals),
+#
+# then that properties file completely overrides the master security
+# properties file.
+#
+# To disable the ability to specify an additional properties file from
+# the command line, set the key security.overridePropertiesFile
+# to false in the master security properties file. It is set to true
+# by default.
+
# In this file, various security properties are set for use by
# java.security classes. This is where users can statically register
# Cryptography Package Providers ("providers" for short). The term
--- a/jdk/src/share/lib/security/java.security-solaris Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/lib/security/java.security-solaris Tue Jul 03 20:58:02 2012 -0700
@@ -1,6 +1,28 @@
#
# This is the "master security properties file".
#
+# An alternate java.security properties file may be specified
+# from the command line via the system property
+#
+# -Djava.security.properties=<URL>
+#
+# This properties file appends to the master security properties file.
+# If both properties files specify values for the same key, the value
+# from the command-line properties file is selected, as it is the last
+# one loaded.
+#
+# Also, if you specify
+#
+# -Djava.security.properties==<URL> (2 equals),
+#
+# then that properties file completely overrides the master security
+# properties file.
+#
+# To disable the ability to specify an additional properties file from
+# the command line, set the key security.overridePropertiesFile
+# to false in the master security properties file. It is set to true
+# by default.
+
# In this file, various security properties are set for use by
# java.security classes. This is where users can statically register
# Cryptography Package Providers ("providers" for short). The term
--- a/jdk/src/share/lib/security/java.security-windows Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/share/lib/security/java.security-windows Tue Jul 03 20:58:02 2012 -0700
@@ -1,6 +1,28 @@
#
# This is the "master security properties file".
#
+# An alternate java.security properties file may be specified
+# from the command line via the system property
+#
+# -Djava.security.properties=<URL>
+#
+# This properties file appends to the master security properties file.
+# If both properties files specify values for the same key, the value
+# from the command-line properties file is selected, as it is the last
+# one loaded.
+#
+# Also, if you specify
+#
+# -Djava.security.properties==<URL> (2 equals),
+#
+# then that properties file completely overrides the master security
+# properties file.
+#
+# To disable the ability to specify an additional properties file from
+# the command line, set the key security.overridePropertiesFile
+# to false in the master security properties file. It is set to true
+# by default.
+
# In this file, various security properties are set for use by
# java.security classes. This is where users can statically register
# Cryptography Package Providers ("providers" for short). The term
--- a/jdk/src/solaris/classes/java/lang/UNIXProcess.java.bsd Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/solaris/classes/java/lang/UNIXProcess.java.bsd Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -38,6 +38,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import java.security.AccessController;
import static java.security.AccessController.doPrivileged;
import java.security.PrivilegedAction;
@@ -211,6 +212,24 @@
}
return exitcode;
}
+
+ @Override
+ public synchronized boolean waitFor(long timeout, TimeUnit unit)
+ throws InterruptedException
+ {
+ if (hasExited) return true;
+ if (timeout <= 0) return false;
+
+ long timeoutAsNanos = unit.toNanos(timeout);
+ long startTime = System.nanoTime();
+ long rem = timeoutAsNanos;
+
+ while (!hasExited && (rem > 0)) {
+ wait(Math.max(TimeUnit.NANOSECONDS.toMillis(rem), 1));
+ rem = timeoutAsNanos - (System.nanoTime() - startTime);
+ }
+ return hasExited;
+ }
public synchronized int exitValue() {
if (!hasExited) {
@@ -219,8 +238,8 @@
return exitcode;
}
- private static native void destroyProcess(int pid);
- public void destroy() {
+ private static native void destroyProcess(int pid, boolean force);
+ private void destroy(boolean force) {
// There is a risk that pid will be recycled, causing us to
// kill the wrong process! So we only terminate processes
// that appear to still be running. Even with this check,
@@ -229,13 +248,28 @@
// soon, so this is quite safe.
synchronized (this) {
if (!hasExited)
- destroyProcess(pid);
+ destroyProcess(pid, force);
}
try { stdin.close(); } catch (IOException ignored) {}
try { stdout.close(); } catch (IOException ignored) {}
try { stderr.close(); } catch (IOException ignored) {}
}
+ public void destroy() {
+ destroy(false);
+ }
+
+ @Override
+ public Process destroyForcibly() {
+ destroy(true);
+ return this;
+ }
+
+ @Override
+ public synchronized boolean isAlive() {
+ return !hasExited;
+ }
+
/* This routine initializes JNI field offsets for the class */
private static native void initIDs();
--- a/jdk/src/solaris/classes/java/lang/UNIXProcess.java.linux Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/solaris/classes/java/lang/UNIXProcess.java.linux Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -38,6 +38,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import java.security.AccessController;
import static java.security.AccessController.doPrivileged;
import java.security.PrivilegedAction;
@@ -212,6 +213,24 @@
return exitcode;
}
+ @Override
+ public synchronized boolean waitFor(long timeout, TimeUnit unit)
+ throws InterruptedException
+ {
+ if (hasExited) return true;
+ if (timeout <= 0) return false;
+
+ long timeoutAsNanos = unit.toNanos(timeout);
+ long startTime = System.nanoTime();
+ long rem = timeoutAsNanos;
+
+ while (!hasExited && (rem > 0)) {
+ wait(Math.max(TimeUnit.NANOSECONDS.toMillis(rem), 1));
+ rem = timeoutAsNanos - (System.nanoTime() - startTime);
+ }
+ return hasExited;
+ }
+
public synchronized int exitValue() {
if (!hasExited) {
throw new IllegalThreadStateException("process hasn't exited");
@@ -219,8 +238,8 @@
return exitcode;
}
- private static native void destroyProcess(int pid);
- public void destroy() {
+ private static native void destroyProcess(int pid, boolean force);
+ private void destroy(boolean force) {
// There is a risk that pid will be recycled, causing us to
// kill the wrong process! So we only terminate processes
// that appear to still be running. Even with this check,
@@ -229,13 +248,28 @@
// soon, so this is quite safe.
synchronized (this) {
if (!hasExited)
- destroyProcess(pid);
+ destroyProcess(pid, force);
}
try { stdin.close(); } catch (IOException ignored) {}
try { stdout.close(); } catch (IOException ignored) {}
try { stderr.close(); } catch (IOException ignored) {}
}
+ public void destroy() {
+ destroy(false);
+ }
+
+ @Override
+ public Process destroyForcibly() {
+ destroy(true);
+ return this;
+ }
+
+ @Override
+ public synchronized boolean isAlive() {
+ return !hasExited;
+ }
+
/* This routine initializes JNI field offsets for the class */
private static native void initIDs();
--- a/jdk/src/solaris/classes/java/lang/UNIXProcess.java.solaris Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/solaris/classes/java/lang/UNIXProcess.java.solaris Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -26,6 +26,7 @@
package java.lang;
import java.io.*;
+import java.util.concurrent.TimeUnit;
/* java.lang.Process subclass in the UNIX environment.
*
@@ -158,6 +159,24 @@
return exitcode;
}
+ @Override
+ public synchronized boolean waitFor(long timeout, TimeUnit unit)
+ throws InterruptedException
+ {
+ if (hasExited) return true;
+ if (timeout <= 0) return false;
+
+ long timeoutAsNanos = unit.toNanos(timeout);
+ long startTime = System.nanoTime();
+ long rem = timeoutAsNanos;
+
+ while (!hasExited && (rem > 0)) {
+ wait(Math.max(TimeUnit.NANOSECONDS.toMillis(rem), 1));
+ rem = timeoutAsNanos - (System.nanoTime() - startTime);
+ }
+ return hasExited;
+ }
+
public synchronized int exitValue() {
if (!hasExited) {
throw new IllegalThreadStateException("process hasn't exited");
@@ -165,8 +184,8 @@
return exitcode;
}
- private static native void destroyProcess(int pid);
- public synchronized void destroy() {
+ private static native void destroyProcess(int pid, boolean force);
+ private synchronized void destroy(boolean force) {
// There is a risk that pid will be recycled, causing us to
// kill the wrong process! So we only terminate processes
// that appear to still be running. Even with this check,
@@ -174,7 +193,7 @@
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
if (!hasExited)
- destroyProcess(pid);
+ destroyProcess(pid, force);
try {
stdin_stream.close();
if (stdout_inner_stream != null)
@@ -187,6 +206,21 @@
}
}
+ public void destroy() {
+ destroy(false);
+ }
+
+ @Override
+ public Process destroyForcibly() {
+ destroy(true);
+ return this;
+ }
+
+ @Override
+ public synchronized boolean isAlive() {
+ return !hasExited;
+ }
+
// A FileInputStream that supports the deferment of the actual close
// operation until the last pending I/O operation on the stream has
// finished. This is required on Solaris because we must close the stdin
--- a/jdk/src/solaris/native/java/lang/UNIXProcess_md.c Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/solaris/native/java/lang/UNIXProcess_md.c Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -955,7 +955,11 @@
}
JNIEXPORT void JNICALL
-Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env, jobject junk, jint pid)
+Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env,
+ jobject junk,
+ jint pid,
+ jboolean force)
{
- kill(pid, SIGTERM);
+ int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
+ kill(pid, sig);
}
--- a/jdk/src/windows/classes/java/lang/ProcessImpl.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/windows/classes/java/lang/ProcessImpl.java Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -37,6 +37,7 @@
import java.lang.ProcessBuilder.Redirect;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.concurrent.TimeUnit;
/* This class is for the exclusive use of ProcessBuilder.start() to
* create new processes.
@@ -254,11 +255,44 @@
throw new InterruptedException();
return exitValue();
}
+
private static native void waitForInterruptibly(long handle);
+ @Override
+ public boolean waitFor(long timeout, TimeUnit unit)
+ throws InterruptedException
+ {
+ if (getExitCodeProcess(handle) != STILL_ACTIVE) return true;
+ if (timeout <= 0) return false;
+
+ long msTimeout = unit.toMillis(timeout);
+
+ waitForTimeoutInterruptibly(handle, msTimeout);
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ return (getExitCodeProcess(handle) != STILL_ACTIVE);
+ }
+
+ private static native void waitForTimeoutInterruptibly(
+ long handle, long timeout);
+
public void destroy() { terminateProcess(handle); }
+
+ @Override
+ public Process destroyForcibly() {
+ destroy();
+ return this;
+ }
+
private static native void terminateProcess(long handle);
+ @Override
+ public boolean isAlive() {
+ return isProcessAlive(handle);
+ }
+
+ private static native boolean isProcessAlive(long handle);
+
/**
* Create a process using the win32 function CreateProcess.
*
--- a/jdk/src/windows/native/java/lang/ProcessImpl_md.c Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/src/windows/native/java/lang/ProcessImpl_md.c Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -299,18 +299,45 @@
if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
FALSE, /* Wait for ANY event */
- INFINITE) /* Wait forever */
+ INFINITE) /* Wait forever */
== WAIT_FAILED)
win32Error(env, "WaitForMultipleObjects");
}
JNIEXPORT void JNICALL
+Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
+ jclass ignored,
+ jlong handle,
+ jlong timeout)
+{
+ HANDLE events[2];
+ DWORD dwTimeout = (DWORD)timeout;
+ DWORD result;
+ events[0] = (HANDLE) handle;
+ events[1] = JVM_GetThreadInterruptEvent();
+ result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
+ FALSE, /* Wait for ANY event */
+ dwTimeout); /* Wait for dwTimeout */
+
+ if (result == WAIT_FAILED)
+ win32Error(env, "WaitForMultipleObjects");
+}
+
+JNIEXPORT void JNICALL
Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
{
TerminateProcess((HANDLE) handle, 1);
}
JNIEXPORT jboolean JNICALL
+Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
+{
+ DWORD dwExitStatus;
+ GetExitCodeProcess(handle, &dwExitStatus);
+ return dwExitStatus == STILL_ACTIVE;
+}
+
+JNIEXPORT jboolean JNICALL
Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
{
return CloseHandle((HANDLE) handle);
--- a/jdk/test/java/lang/ProcessBuilder/Basic.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/test/java/lang/ProcessBuilder/Basic.java Tue Jul 03 20:58:02 2012 -0700
@@ -26,7 +26,7 @@
* @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689
* 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
* 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958
- * 4947220 7018606 7034570
+ * 4947220 7018606 7034570 4244896
* @summary Basic tests for Process and Environment Variable code
* @run main/othervm/timeout=300 Basic
* @author Martin Buchholz
@@ -38,6 +38,7 @@
import java.io.*;
import java.util.*;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.security.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
@@ -636,6 +637,44 @@
static boolean is() { return is; }
}
+ static class DelegatingProcess extends Process {
+ final Process p;
+
+ DelegatingProcess(Process p) {
+ this.p = p;
+ }
+
+ @Override
+ public void destroy() {
+ p.destroy();
+ }
+
+ @Override
+ public int exitValue() {
+ return p.exitValue();
+ }
+
+ @Override
+ public int waitFor() throws InterruptedException {
+ return p.waitFor();
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ return p.getOutputStream();
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ return p.getInputStream();
+ }
+
+ @Override
+ public InputStream getErrorStream() {
+ return p.getErrorStream();
+ }
+ }
+
private static boolean matches(String str, String regex) {
return Pattern.compile(regex).matcher(str).find();
}
@@ -2090,6 +2129,112 @@
policy.setPermissions(new RuntimePermission("setSecurityManager"));
System.setSecurityManager(null);
+ //----------------------------------------------------------------
+ // Check that Process.isAlive() &
+ // Process.waitFor(0, TimeUnit.MILLISECONDS) work as expected.
+ //----------------------------------------------------------------
+ try {
+ List<String> childArgs = new ArrayList<String>(javaChildArgs);
+ childArgs.add("sleep");
+ final Process p = new ProcessBuilder(childArgs).start();
+ long start = System.nanoTime();
+ if (!p.isAlive() || p.waitFor(0, TimeUnit.MILLISECONDS)) {
+ fail("Test failed: Process exited prematurely");
+ }
+ long end = System.nanoTime();
+ // give waitFor(timeout) a wide berth (100ms)
+ if ((end - start) > 100000000)
+ fail("Test failed: waitFor took too long");
+
+ p.destroy();
+ p.waitFor();
+
+ if (p.isAlive() ||
+ !p.waitFor(0, TimeUnit.MILLISECONDS))
+ {
+ fail("Test failed: Process still alive - please terminate " +
+ p.toString() + " manually");
+ }
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
+ // works as expected.
+ //----------------------------------------------------------------
+ try {
+ List<String> childArgs = new ArrayList<String>(javaChildArgs);
+ childArgs.add("sleep");
+ final Process p = new ProcessBuilder(childArgs).start();
+ long start = System.nanoTime();
+
+ p.waitFor(1000, TimeUnit.MILLISECONDS);
+
+ long end = System.nanoTime();
+ if ((end - start) < 500000000)
+ fail("Test failed: waitFor didn't take long enough");
+
+ p.destroy();
+
+ start = System.nanoTime();
+ p.waitFor(1000, TimeUnit.MILLISECONDS);
+ end = System.nanoTime();
+ if ((end - start) > 100000000)
+ fail("Test failed: waitFor took too long on a dead process.");
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
+ // interrupt works as expected.
+ //----------------------------------------------------------------
+ try {
+ List<String> childArgs = new ArrayList<String>(javaChildArgs);
+ childArgs.add("sleep");
+ final Process p = new ProcessBuilder(childArgs).start();
+ final long start = System.nanoTime();
+
+ final Thread thread = new Thread() {
+ public void run() {
+ try {
+ try {
+ p.waitFor(10000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return;
+ }
+ fail("waitFor() wasn't interrupted");
+ } catch (Throwable t) { unexpected(t); }}};
+
+ thread.start();
+ Thread.sleep(1000);
+ thread.interrupt();
+ p.destroy();
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check the default implementation for
+ // Process.waitFor(long, TimeUnit)
+ //----------------------------------------------------------------
+ try {
+ List<String> childArgs = new ArrayList<String>(javaChildArgs);
+ childArgs.add("sleep");
+ final Process proc = new ProcessBuilder(childArgs).start();
+ DelegatingProcess p = new DelegatingProcess(proc);
+ long start = System.nanoTime();
+
+ p.waitFor(1000, TimeUnit.MILLISECONDS);
+
+ long end = System.nanoTime();
+ if ((end - start) < 500000000)
+ fail("Test failed: waitFor didn't take long enough");
+
+ p.destroy();
+
+ start = System.nanoTime();
+ p.waitFor(1000, TimeUnit.MILLISECONDS);
+ end = System.nanoTime();
+ // allow for the less accurate default implementation
+ if ((end - start) > 200000000)
+ fail("Test failed: waitFor took too long on a dead process.");
+ } catch (Throwable t) { unexpected(t); }
}
static void closeStreams(Process p) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ProcessBuilder/DestroyTest.java Tue Jul 03 20:58:02 2012 -0700
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4244896
+ * @summary Test for the various platform specific implementations of
+ * destroyForcibly.
+ */
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+
+abstract class ProcessTest implements Runnable {
+ ProcessBuilder bldr;
+ Process p;
+
+ public Process killProc(boolean force) throws Exception {
+ if (force) {
+ p.destroyForcibly();
+ } else {
+ p.destroy();
+ }
+ return p;
+ }
+
+ public boolean isAlive() {
+ return p.isAlive();
+ }
+
+ public void run() {
+ try {
+ String line;
+ BufferedReader is =
+ new BufferedReader(new InputStreamReader(p.getInputStream()));
+ while ((line = is.readLine()) != null)
+ System.err.println("ProcessTrap: " + line);
+ } catch(IOException e) {
+ if (!e.getMessage().matches("[Ss]tream [Cc]losed")) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public abstract void runTest() throws Exception;
+}
+
+class UnixTest extends ProcessTest {
+ public UnixTest(File script) throws IOException {
+ script.deleteOnExit();
+ createScript(script);
+ bldr = new ProcessBuilder(script.getCanonicalPath());
+ bldr.redirectErrorStream(true);
+ bldr.directory(new File("."));
+ p = bldr.start();
+ }
+
+ void createScript(File processTrapScript) throws IOException {
+ processTrapScript.deleteOnExit();
+ FileWriter fstream = new FileWriter(processTrapScript);
+ try (BufferedWriter out = new BufferedWriter(fstream)) {
+ out.write("#!/bin/bash\n" +
+ "echo \\\"ProcessTrap.sh started: trapping SIGTERM/SIGINT\\\"\n" +
+ "trap bashtrap SIGTERM SIGINT\n" +
+ "bashtrap()\n" +
+ "{\n" +
+ " echo \\\"SIGTERM/SIGINT detected!\\\"\n" +
+ "}\n" +
+ "\n" +
+ "while :\n" +
+ "do\n" +
+ " sleep 1;\n" +
+ "done\n");
+ }
+ processTrapScript.setExecutable(true, true);
+ }
+
+ @Override
+ public void runTest() throws Exception {
+ killProc(false);
+ Thread.sleep(1000);
+ if (!p.isAlive())
+ throw new RuntimeException("Process terminated prematurely.");
+ killProc(true).waitFor();
+ if (p.isAlive())
+ throw new RuntimeException("Problem terminating the process.");
+ }
+}
+
+class MacTest extends UnixTest {
+ public MacTest(File script) throws IOException {
+ super(script);
+ }
+
+ @Override
+ public void runTest() throws Exception {
+ // On Mac, it appears that when we close the processes streams
+ // after a destroy() call, the process terminates with a
+ // SIGPIPE even if it was trapping the SIGTERM, so as with
+ // windows, we skip the trap test and go straight to destroyForcibly().
+ killProc(true).waitFor();
+ if (p.isAlive())
+ throw new RuntimeException("Problem terminating the process.");
+ }
+}
+
+class WindowsTest extends ProcessTest {
+ public WindowsTest() throws IOException {
+ bldr = new ProcessBuilder("ftp");
+ bldr.redirectErrorStream(true);
+ bldr.directory(new File("."));
+ p = bldr.start();
+ }
+
+ @Override
+ public void runTest() throws Exception {
+ killProc(true).waitFor();
+ }
+}
+
+public class DestroyTest {
+
+ public static ProcessTest getTest() throws Exception {
+ String osName = System.getProperty("os.name");
+ if (osName.startsWith("Windows")) {
+ return new WindowsTest();
+ } else if (osName.startsWith("Linux") == true) {
+ return new UnixTest(
+ File.createTempFile("ProcessTrap-", ".sh",null));
+ } else if (osName.startsWith("Mac OS")) {
+ return new MacTest(
+ File.createTempFile("ProcessTrap-", ".sh",null));
+ } else if (osName.equals("SunOS")) {
+ return new UnixTest(
+ File.createTempFile("ProcessTrap-", ".sh",null));
+ }
+ return null;
+ }
+
+ public static void main(String args[]) throws Exception {
+ ProcessTest test = getTest();
+ if (test == null) {
+ throw new RuntimeException("Unrecognised OS");
+ } else {
+ new Thread(test).start();
+ Thread.sleep(1000);
+ test.runTest();
+ }
+ }
+}
+
--- a/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6215625
+ * @bug 6215625 7161229
* @summary Check correct behavior when last element is removed.
* @author Martin Buchholz
*/
@@ -38,9 +38,7 @@
testQueue(new ArrayBlockingQueue<Integer>(10, true));
testQueue(new ArrayBlockingQueue<Integer>(10, false));
testQueue(new LinkedTransferQueue<Integer>());
-
- System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
- if (failed > 0) throw new Exception("Some tests failed");
+ testQueue(new PriorityBlockingQueue<Integer>());
}
void testQueue(BlockingQueue<Integer> q) throws Throwable {
@@ -59,6 +57,7 @@
try {check(q.take() == three);}
catch (Throwable t) {unexpected(t);}
check(q.isEmpty() && q.size() == 0);
+ check(noRetention(q));
// iterator().remove()
q.clear();
@@ -77,6 +76,26 @@
check(q.isEmpty() && q.size() == 0);
}
+ boolean noRetention(BlockingQueue<?> q) {
+ if (q instanceof PriorityBlockingQueue) {
+ PriorityBlockingQueue<?> pbq = (PriorityBlockingQueue) q;
+ try {
+ java.lang.reflect.Field queue =
+ PriorityBlockingQueue.class.getDeclaredField("queue");
+ queue.setAccessible(true);
+ Object[] a = (Object[]) queue.get(pbq);
+ return a[0] == null;
+ }
+ catch (NoSuchFieldException e) {
+ unexpected(e);
+ }
+ catch (IllegalAccessException e) {
+ // ignore - security manager must be installed
+ }
+ }
+ return true;
+ }
+
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java Tue Jul 03 20:56:24 2012 -0700
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java Tue Jul 03 20:58:02 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -287,18 +287,27 @@
if (serverClose) {
serverEngine.closeOutbound();
}
+ }
+
+ if (closed && isEngineClosed(serverEngine)) {
serverIn.flip();
/*
* A sanity check to ensure we got what was sent.
*/
if (serverIn.remaining() != clientMsg.length) {
- throw new Exception("Client: Data length error");
+ throw new Exception("Client: Data length error -" +
+ " IF THIS FAILS, PLEASE REPORT THIS TO THE" +
+ " SECURITY TEAM. WE HAVE BEEN UNABLE TO" +
+ " RELIABLY DUPLICATE.");
}
for (int i = 0; i < clientMsg.length; i++) {
if (clientMsg[i] != serverIn.get()) {
- throw new Exception("Client: Data content error");
+ throw new Exception("Client: Data content error -" +
+ " IF THIS FAILS, PLEASE REPORT THIS TO THE" +
+ " SECURITY TEAM. WE HAVE BEEN UNABLE TO" +
+ " RELIABLY DUPLICATE.");
}
}
serverIn.compact();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/native2ascii/Permission.java Tue Jul 03 20:58:02 2012 -0700
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 7177216
+ * @summary resulting file of native2ascii should have normal permission
+ */
+
+import java.io.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import sun.tools.native2ascii.Main;
+
+public class Permission {
+
+ private static void cleanup(String... fnames) throws Throwable {
+ for (String fname : fnames) {
+ Files.deleteIfExists(Paths.get(fname));
+ }
+ }
+
+ public static void realMain(String[] args) throws Throwable {
+ if (!System.getProperty("os.name").startsWith("Windows")) {
+ String src = "native2ascii_permtest_src";
+ String dst = "native2ascii_permtest_dst";
+
+ cleanup(src, dst);
+ try {
+ try (FileOutputStream fos = new FileOutputStream(src)) {
+ fos.write('a'); fos.write('b'); fos.write('c');
+ }
+ String[] n2aArgs = new String[] {"-encoding", "utf8", src, dst};
+ if (!new Main().convert(n2aArgs)) {
+ fail("n2a failed.");
+ }
+ equal(Files.getPosixFilePermissions(Paths.get(src)),
+ Files.getPosixFilePermissions(Paths.get(dst)));
+ String[] a2nArgs = new String[] {"-reverse", "-encoding", "utf8", dst, src};
+ if (!new Main().convert(a2nArgs)) {
+ fail("a2n failed.");
+ }
+ equal(Files.getPosixFilePermissions(Paths.get(src)),
+ Files.getPosixFilePermissions(Paths.get(dst)));
+ } finally {
+ cleanup(src, dst);
+ }
+ }
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static void pass() {passed++;}
+ static void fail() {failed++; Thread.dumpStack();}
+ static void fail(String msg) {System.out.println(msg); fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static void check(boolean cond) {if (cond) pass(); else fail();}
+ static void equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) pass();
+ else fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/UpdateJar.java Tue Jul 03 20:58:02 2012 -0700
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 7175845
+ * @summary jar -uf should not change file permission
+ */
+
+import java.io.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.util.Set;
+import sun.tools.jar.Main;
+
+public class UpdateJar {
+
+ private static void cleanup(String... fnames) throws Throwable {
+ for (String fname : fnames) {
+ Files.deleteIfExists(Paths.get(fname));
+ }
+ }
+
+ public static void realMain(String[] args) throws Throwable {
+ if (!System.getProperty("os.name").startsWith("Windows")) {
+ String jar = "testUpdateJar.jar";
+ String e0 = "testUpdateJar_entry0.txt";
+ String e1 = "testUpdateJar_entry1.txt";
+ cleanup(jar, e0, e1);
+ try {
+ try (FileOutputStream fos0 = new FileOutputStream(e0);
+ FileOutputStream fos1 = new FileOutputStream(e1)) {
+ fos0.write(0);
+ fos1.write(0);
+ }
+ String[] jarArgs = new String[] {"cfM0", jar, e0};
+ if (!new Main(System.out, System.err, "jar").run(jarArgs)) {
+ fail("Could not create jar file.");
+ }
+ Set<PosixFilePermission> pm = Files.getPosixFilePermissions(Paths.get(jar));
+ jarArgs = new String[] {"uf", jar, e1};
+ if (!new Main(System.out, System.err, "jar").run(jarArgs)) {
+ fail("Could not create jar file.");
+ }
+ equal(pm, Files.getPosixFilePermissions(Paths.get(jar)));
+ } finally {
+ cleanup(jar, e0, e1);
+ }
+ }
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static void pass() {passed++;}
+ static void fail() {failed++; Thread.dumpStack();}
+ static void fail(String msg) {System.out.println(msg); fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static void check(boolean cond) {if (cond) pass(); else fail();}
+ static void equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) pass();
+ else fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}