xref: /illumos-gate/usr/src/lib/libdtrace_jni/java/src/org/opensolaris/os/dtrace/ProcessState.java (revision 4ae67516a1d5dc4a5dbc761762bad5b596647388)
1fb3fb4f3Stomee /*
2fb3fb4f3Stomee  * CDDL HEADER START
3fb3fb4f3Stomee  *
4fb3fb4f3Stomee  * The contents of this file are subject to the terms of the
5fb3fb4f3Stomee  * Common Development and Distribution License (the "License").
6fb3fb4f3Stomee  * You may not use this file except in compliance with the License.
7fb3fb4f3Stomee  *
8fb3fb4f3Stomee  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fb3fb4f3Stomee  * or http://www.opensolaris.org/os/licensing.
10fb3fb4f3Stomee  * See the License for the specific language governing permissions
11fb3fb4f3Stomee  * and limitations under the License.
12fb3fb4f3Stomee  *
13fb3fb4f3Stomee  * When distributing Covered Code, include this CDDL HEADER in each
14fb3fb4f3Stomee  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fb3fb4f3Stomee  * If applicable, add the following below this CDDL HEADER, with the
16fb3fb4f3Stomee  * fields enclosed by brackets "[]" replaced with your own identifying
17fb3fb4f3Stomee  * information: Portions Copyright [yyyy] [name of copyright owner]
18fb3fb4f3Stomee  *
19fb3fb4f3Stomee  * CDDL HEADER END
20fb3fb4f3Stomee  */
21fb3fb4f3Stomee 
22fb3fb4f3Stomee /*
2391cfa10aStomee  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24fb3fb4f3Stomee  * Use is subject to license terms.
25fb3fb4f3Stomee  *
26fb3fb4f3Stomee  * ident	"%Z%%M%	%I%	%E% SMI"
27fb3fb4f3Stomee  */
28fb3fb4f3Stomee package org.opensolaris.os.dtrace;
29fb3fb4f3Stomee 
30fb3fb4f3Stomee import java.io.*;
31fb3fb4f3Stomee import java.beans.*;
32fb3fb4f3Stomee 
33fb3fb4f3Stomee /**
34fb3fb4f3Stomee  * State of a target process designated by {@link
35fb3fb4f3Stomee  * Consumer#createProcess(String command)} or {@link
36fb3fb4f3Stomee  * Consumer#grabProcess(int pid)}.
37fb3fb4f3Stomee  * <p>
38fb3fb4f3Stomee  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
39fb3fb4f3Stomee  *
40fb3fb4f3Stomee  * @see ConsumerListener#processStateChanged(ProcessEvent e)
41fb3fb4f3Stomee  *
42fb3fb4f3Stomee  * @author Tom Erickson
43fb3fb4f3Stomee  */
44fb3fb4f3Stomee public final class ProcessState implements Serializable {
45fb3fb4f3Stomee     static final long serialVersionUID = -3395911213431317292L;
46fb3fb4f3Stomee 
47fb3fb4f3Stomee     static {
48fb3fb4f3Stomee 	try {
49fb3fb4f3Stomee 	    BeanInfo info = Introspector.getBeanInfo(ProcessState.class);
50fb3fb4f3Stomee 	    PersistenceDelegate persistenceDelegate =
51fb3fb4f3Stomee 		    new DefaultPersistenceDelegate(
52fb3fb4f3Stomee 		    new String[] {"processID", "state",
53fb3fb4f3Stomee 		    "terminationSignal", "terminationSignalName",
54fb3fb4f3Stomee 		    "exitStatus", "message"})
55fb3fb4f3Stomee 	    {
56fb3fb4f3Stomee 		/*
57fb3fb4f3Stomee 		 * Need to prevent DefaultPersistenceDelegate from using
58fb3fb4f3Stomee 		 * overridden equals() method, resulting in a
59fb3fb4f3Stomee 		 * StackOverFlowError.  Revert to PersistenceDelegate
60fb3fb4f3Stomee 		 * implementation.  See
61fb3fb4f3Stomee 		 * http://forum.java.sun.com/thread.jspa?threadID=
62fb3fb4f3Stomee 		 * 477019&tstart=135
63fb3fb4f3Stomee 		 */
64fb3fb4f3Stomee 		protected boolean
65fb3fb4f3Stomee 		mutatesTo(Object oldInstance, Object newInstance)
66fb3fb4f3Stomee 		{
67fb3fb4f3Stomee 		    return (newInstance != null && oldInstance != null &&
68fb3fb4f3Stomee 			    oldInstance.getClass() == newInstance.getClass());
69fb3fb4f3Stomee 		}
70fb3fb4f3Stomee 
71fb3fb4f3Stomee 		protected Expression
72fb3fb4f3Stomee 		instantiate(Object oldInstance, Encoder out)
73fb3fb4f3Stomee 		{
74fb3fb4f3Stomee 		    ProcessState pstate = (ProcessState)oldInstance;
75fb3fb4f3Stomee 		    return new Expression(oldInstance, oldInstance.getClass(),
76fb3fb4f3Stomee 			    "new", new Object[] { pstate.getProcessID(),
77fb3fb4f3Stomee 			    pstate.getState().name(),
78fb3fb4f3Stomee 			    pstate.getTerminationSignal(),
79fb3fb4f3Stomee 			    pstate.getTerminationSignalName(),
80fb3fb4f3Stomee 			    pstate.getExitStatus(),
81fb3fb4f3Stomee 			    pstate.getMessage() });
82fb3fb4f3Stomee 		}
83fb3fb4f3Stomee 	    };
84fb3fb4f3Stomee 	    BeanDescriptor d = info.getBeanDescriptor();
85fb3fb4f3Stomee 	    d.setValue("persistenceDelegate", persistenceDelegate);
86fb3fb4f3Stomee 	} catch (IntrospectionException e) {
87fb3fb4f3Stomee 	    System.out.println(e);
88fb3fb4f3Stomee 	}
89fb3fb4f3Stomee     }
90fb3fb4f3Stomee 
91fb3fb4f3Stomee     /**
92fb3fb4f3Stomee      * State of a target process.
93fb3fb4f3Stomee      */
94fb3fb4f3Stomee     public enum State {
95fb3fb4f3Stomee 	/** Process is running. */
96fb3fb4f3Stomee 	RUN,
97fb3fb4f3Stomee 	/** Process is stopped. */
98fb3fb4f3Stomee 	STOP,
99fb3fb4f3Stomee 	/** Process is lost to control. */
100fb3fb4f3Stomee 	LOST,
101fb3fb4f3Stomee 	/** Process is terminated (zombie). */
102fb3fb4f3Stomee 	UNDEAD,
103fb3fb4f3Stomee 	/** Process is terminated (core file). */
104fb3fb4f3Stomee 	DEAD
105fb3fb4f3Stomee     }
106fb3fb4f3Stomee 
107fb3fb4f3Stomee     /** @serial */
108fb3fb4f3Stomee     private int processID;
109fb3fb4f3Stomee     /** @serial */
110fb3fb4f3Stomee     private State state;
111fb3fb4f3Stomee     /** @serial */
112fb3fb4f3Stomee     private int terminationSignal;
113fb3fb4f3Stomee     /** @serial */
114fb3fb4f3Stomee     private String terminationSignalName;
115fb3fb4f3Stomee     /** @serial */
116fb3fb4f3Stomee     private Integer exitStatus;
117fb3fb4f3Stomee     /** @serial */
118fb3fb4f3Stomee     private String message;
119fb3fb4f3Stomee 
120fb3fb4f3Stomee     /**
121fb3fb4f3Stomee      * Creates a {@code ProcessState} instance with the given state.
122fb3fb4f3Stomee      *
123fb3fb4f3Stomee      * @param pid non-negative target process ID
124fb3fb4f3Stomee      * @param processState target process state
125fb3fb4f3Stomee      * @param processTerminationSignal signal that terminated the target
126fb3fb4f3Stomee      * process, {@code -1} if the process was not terminated by a signal
127fb3fb4f3Stomee      * or if the terminating signal is unknown
128fb3fb4f3Stomee      * @param processTerminationSignalName name of the signal that
129fb3fb4f3Stomee      * terminated the target process, {@code null} if the process was
130fb3fb4f3Stomee      * not terminated by a signal or if the terminating signal is
131fb3fb4f3Stomee      * unknown
132fb3fb4f3Stomee      * @param processExitStatus target process exit status, {@code null}
133fb3fb4f3Stomee      * if the process has not exited or the exit status is unknown
134fb3fb4f3Stomee      * @param msg message included by DTrace, if any
135fb3fb4f3Stomee      * @throws NullPointerException if the given process state is {@code
136fb3fb4f3Stomee      * null}
137fb3fb4f3Stomee      * @throws IllegalArgumentException if the given process ID is negative
138fb3fb4f3Stomee      */
139fb3fb4f3Stomee     public
ProcessState(int pid, State processState, int processTerminationSignal, String processTerminationSignalName, Integer processExitStatus, String msg)140fb3fb4f3Stomee     ProcessState(int pid, State processState,
141fb3fb4f3Stomee 	    int processTerminationSignal,
142fb3fb4f3Stomee 	    String processTerminationSignalName,
143fb3fb4f3Stomee 	    Integer processExitStatus, String msg)
144fb3fb4f3Stomee     {
145fb3fb4f3Stomee 	processID = pid;
146fb3fb4f3Stomee 	state = processState;
147fb3fb4f3Stomee 	terminationSignal = processTerminationSignal;
148fb3fb4f3Stomee 	terminationSignalName = processTerminationSignalName;
149fb3fb4f3Stomee 	exitStatus = processExitStatus;
150fb3fb4f3Stomee 	message = msg;
151fb3fb4f3Stomee 	validate();
152fb3fb4f3Stomee     }
153fb3fb4f3Stomee 
154fb3fb4f3Stomee     /**
155fb3fb4f3Stomee      * Supports XML persistence.
156fb3fb4f3Stomee      *
157fb3fb4f3Stomee      * @see #ProcessState(int pid, State processState, int
158fb3fb4f3Stomee      * processTerminationSignal, String processTerminationSignalName,
159fb3fb4f3Stomee      * Integer processExitStatus, String msg)
160fb3fb4f3Stomee      * @throws IllegalArgumentException if there is no {@link
161fb3fb4f3Stomee      * ProcessState.State} value with the given state name.
162fb3fb4f3Stomee      */
163fb3fb4f3Stomee     public
ProcessState(int pid, String processStateName, int processTerminationSignal, String processTerminationSignalName, Integer processExitStatus, String msg)164fb3fb4f3Stomee     ProcessState(int pid, String processStateName,
165fb3fb4f3Stomee 	    int processTerminationSignal,
166fb3fb4f3Stomee 	    String processTerminationSignalName,
167fb3fb4f3Stomee 	    Integer processExitStatus, String msg)
168fb3fb4f3Stomee     {
169fb3fb4f3Stomee 	processID = pid;
170fb3fb4f3Stomee 	state = Enum.valueOf(State.class, processStateName);
171fb3fb4f3Stomee 	terminationSignal = processTerminationSignal;
172fb3fb4f3Stomee 	terminationSignalName = processTerminationSignalName;
173fb3fb4f3Stomee 	exitStatus = processExitStatus;
174fb3fb4f3Stomee 	message = msg;
175fb3fb4f3Stomee 	validate();
176fb3fb4f3Stomee     }
177fb3fb4f3Stomee 
17891cfa10aStomee     private final void
validate()179fb3fb4f3Stomee     validate()
180fb3fb4f3Stomee     {
181fb3fb4f3Stomee 	if (processID < 0) {
182fb3fb4f3Stomee 	    throw new IllegalArgumentException("pid is negative");
183fb3fb4f3Stomee 	}
184fb3fb4f3Stomee 	if (state == null) {
185fb3fb4f3Stomee 	    throw new NullPointerException("process state is null");
186fb3fb4f3Stomee 	}
187fb3fb4f3Stomee     }
188fb3fb4f3Stomee 
189fb3fb4f3Stomee     /**
190fb3fb4f3Stomee      * Gets the process ID.
191fb3fb4f3Stomee      *
192fb3fb4f3Stomee      * @return non-negative target process ID
193fb3fb4f3Stomee      */
194fb3fb4f3Stomee     public int
getProcessID()195fb3fb4f3Stomee     getProcessID()
196fb3fb4f3Stomee     {
197fb3fb4f3Stomee 	return processID;
198fb3fb4f3Stomee     }
199fb3fb4f3Stomee 
200fb3fb4f3Stomee     /**
201fb3fb4f3Stomee      * Gets the process state.
202fb3fb4f3Stomee      *
203fb3fb4f3Stomee      * @return non-null target process state
204fb3fb4f3Stomee      */
205fb3fb4f3Stomee     public State
getState()206fb3fb4f3Stomee     getState()
207fb3fb4f3Stomee     {
208fb3fb4f3Stomee 	return state;
209fb3fb4f3Stomee     }
210fb3fb4f3Stomee 
211fb3fb4f3Stomee     /**
212fb3fb4f3Stomee      * Gets the signal that terminated the process.
213fb3fb4f3Stomee      *
214fb3fb4f3Stomee      * @return termination signal, {@code -1} if the process was not
215fb3fb4f3Stomee      * terminated by a signal or if the terminating signal is unknown
216fb3fb4f3Stomee      */
217fb3fb4f3Stomee     public int
getTerminationSignal()218fb3fb4f3Stomee     getTerminationSignal()
219fb3fb4f3Stomee     {
220fb3fb4f3Stomee 	return terminationSignal;
221fb3fb4f3Stomee     }
222fb3fb4f3Stomee 
223fb3fb4f3Stomee     /**
224fb3fb4f3Stomee      * Gets the name of the signal that terminated the process.
225fb3fb4f3Stomee      *
226fb3fb4f3Stomee      * @return termination signal name, {@code null} if the process was
227fb3fb4f3Stomee      * not terminated by a signal or if the terminating signal is
228fb3fb4f3Stomee      * unknown
229fb3fb4f3Stomee      */
230fb3fb4f3Stomee     public String
getTerminationSignalName()231fb3fb4f3Stomee     getTerminationSignalName()
232fb3fb4f3Stomee     {
233fb3fb4f3Stomee 	return terminationSignalName;
234fb3fb4f3Stomee     }
235fb3fb4f3Stomee 
236fb3fb4f3Stomee     /**
237fb3fb4f3Stomee      * Gets the process exit status.
238fb3fb4f3Stomee      *
239fb3fb4f3Stomee      * @return exit status, or {@code null} if the process has not
240fb3fb4f3Stomee      * exited or the exit status is unknown
241fb3fb4f3Stomee      */
242fb3fb4f3Stomee     public Integer
getExitStatus()243fb3fb4f3Stomee     getExitStatus()
244fb3fb4f3Stomee     {
245fb3fb4f3Stomee 	return exitStatus;
246fb3fb4f3Stomee     }
247fb3fb4f3Stomee 
248fb3fb4f3Stomee     /**
249fb3fb4f3Stomee      * Called by native code.
250fb3fb4f3Stomee      */
251fb3fb4f3Stomee     private void
setExitStatus(int status)252fb3fb4f3Stomee     setExitStatus(int status)
253fb3fb4f3Stomee     {
254fb3fb4f3Stomee 	exitStatus = new Integer(status);
255fb3fb4f3Stomee     }
256fb3fb4f3Stomee 
257fb3fb4f3Stomee     /**
258fb3fb4f3Stomee      * Gets the message from DTrace describing this process state.
259fb3fb4f3Stomee      *
260fb3fb4f3Stomee      * @return DTrace message, or {@code null} if DTrace did not include
261fb3fb4f3Stomee      * a message with this process state
262fb3fb4f3Stomee      */
263fb3fb4f3Stomee     public String
getMessage()264fb3fb4f3Stomee     getMessage()
265fb3fb4f3Stomee     {
266fb3fb4f3Stomee 	return message;
267fb3fb4f3Stomee     }
268fb3fb4f3Stomee 
269fb3fb4f3Stomee     /**
270fb3fb4f3Stomee      * Compares the specified object with this {@code ProcessState}
271fb3fb4f3Stomee      * instance for equality.  Defines equality as having the same
272fb3fb4f3Stomee      * attributes.
273fb3fb4f3Stomee      *
274fb3fb4f3Stomee      * @return {@code true} if and only if the specified object is also
275fb3fb4f3Stomee      * a {@code ProcessState} and both instances have the same
276fb3fb4f3Stomee      * attributes
277fb3fb4f3Stomee      */
278fb3fb4f3Stomee     @Override
279fb3fb4f3Stomee     public boolean
equals(Object o)280fb3fb4f3Stomee     equals(Object o)
281fb3fb4f3Stomee     {
282fb3fb4f3Stomee 	if (o instanceof ProcessState) {
283fb3fb4f3Stomee 	    ProcessState s = (ProcessState)o;
284fb3fb4f3Stomee 	    return ((processID == s.processID) &&
285fb3fb4f3Stomee 		    (state == s.state) &&
286fb3fb4f3Stomee 		    (terminationSignal == s.terminationSignal) &&
287fb3fb4f3Stomee 		    ((terminationSignalName == null) ?
288fb3fb4f3Stomee 		    (s.terminationSignalName == null) :
289fb3fb4f3Stomee 		    terminationSignalName.equals(s.terminationSignalName)) &&
290fb3fb4f3Stomee 		    ((exitStatus == null) ?
291fb3fb4f3Stomee 		    (s.exitStatus == null) :
292fb3fb4f3Stomee 		    exitStatus.equals(s.exitStatus)) &&
293fb3fb4f3Stomee 		    ((message == null) ? (s.message == null) :
294fb3fb4f3Stomee 		    message.equals(s.message)));
295fb3fb4f3Stomee 	}
296fb3fb4f3Stomee 	return false;
297fb3fb4f3Stomee     }
298fb3fb4f3Stomee 
299fb3fb4f3Stomee     /**
300fb3fb4f3Stomee      * Overridden to ensure that equal instances have equal hash codes.
301fb3fb4f3Stomee      */
302fb3fb4f3Stomee     @Override
303fb3fb4f3Stomee     public int
hashCode()304fb3fb4f3Stomee     hashCode()
305fb3fb4f3Stomee     {
306fb3fb4f3Stomee 	int hash = 17;
307fb3fb4f3Stomee 	hash = (37 * hash) + processID;
308fb3fb4f3Stomee 	hash = (37 * hash) + state.hashCode();
309fb3fb4f3Stomee 	hash = (37 * hash) + terminationSignal;
310fb3fb4f3Stomee 	hash = (37 * hash) + (exitStatus == null ? 0 :
311fb3fb4f3Stomee 		exitStatus.hashCode());
312fb3fb4f3Stomee 	hash = (37 * hash) + (message == null ? 0 : message.hashCode());
313fb3fb4f3Stomee 	return hash;
314fb3fb4f3Stomee     }
315fb3fb4f3Stomee 
316fb3fb4f3Stomee     private void
readObject(ObjectInputStream s)317fb3fb4f3Stomee     readObject(ObjectInputStream s)
318fb3fb4f3Stomee             throws IOException, ClassNotFoundException
319fb3fb4f3Stomee     {
320fb3fb4f3Stomee 	s.defaultReadObject();
321fb3fb4f3Stomee 	// check class invariants
322fb3fb4f3Stomee 	try {
323fb3fb4f3Stomee 	    validate();
324fb3fb4f3Stomee 	} catch (Exception e) {
325*4ae67516Stomee 	    InvalidObjectException x = new InvalidObjectException(
326*4ae67516Stomee 		    e.getMessage());
327*4ae67516Stomee 	    x.initCause(e);
328*4ae67516Stomee 	    throw x;
329fb3fb4f3Stomee 	}
330fb3fb4f3Stomee     }
331fb3fb4f3Stomee 
332fb3fb4f3Stomee     /**
333fb3fb4f3Stomee      * Gets a string representation of this process state useful for
334fb3fb4f3Stomee      * logging and not intended for display.  The exact details of the
335fb3fb4f3Stomee      * representation are unspecified and subject to change, but the
336fb3fb4f3Stomee      * following format may be regarded as typical:
337fb3fb4f3Stomee      * <pre><code>
338fb3fb4f3Stomee      * class-name[property1 = value1, property2 = value2]
339fb3fb4f3Stomee      * </code></pre>
340fb3fb4f3Stomee      */
341fb3fb4f3Stomee     public String
toString()342fb3fb4f3Stomee     toString()
343fb3fb4f3Stomee     {
344*4ae67516Stomee 	StringBuilder buf = new StringBuilder();
345fb3fb4f3Stomee 	buf.append(ProcessState.class.getName());
346fb3fb4f3Stomee 	buf.append("[pid = ");
347fb3fb4f3Stomee 	buf.append(processID);
348fb3fb4f3Stomee 	buf.append(", state = ");
349fb3fb4f3Stomee 	buf.append(state);
350fb3fb4f3Stomee 	buf.append(", terminationSignal = ");
351fb3fb4f3Stomee 	buf.append(terminationSignal);
352fb3fb4f3Stomee 	buf.append(", terminationSignalName = ");
353fb3fb4f3Stomee 	buf.append(terminationSignalName);
354fb3fb4f3Stomee 	buf.append(", exitStatus = ");
355fb3fb4f3Stomee 	buf.append(exitStatus);
356fb3fb4f3Stomee 	buf.append(", message = ");
357fb3fb4f3Stomee 	buf.append(message);
358fb3fb4f3Stomee 	buf.append(']');
359fb3fb4f3Stomee 	return buf.toString();
360fb3fb4f3Stomee     }
361fb3fb4f3Stomee }
362