Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: linux/Linux.java


1   /*
2   *  @(#)Linux.java
3   *  Copyright (C) 2001-2003 Tay Hock Keong <tay_ivan@hotmail.com>
4   *  This file is part of JD4X.
5   *  JD4X is free software; you can redistribute it and/or modify it
6   *  under the terms of the GNU General Public License as published by
7   *  the Free Software Foundation; either version 2, or (at your option)
8   *  any later version.
9   *  JD4X is distributed in the hope that it will be useful, but
10  *  WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  *  GNU General Public License for more details.
13  *  You should have received a copy of the GNU General Public License
14  *  along with JD4X; see the file COPYING. If not, write to the Free
15  *  Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
16  */
17  
18  package linux;
19  
20  import arch.module.major.JXMajorModule;
21  import arch.module.data.*;
22  import arch.module.icore.*;
23  import arch.message.error.JXError;
24  import arch.message.request.JXRequest;
25  import arch.task.*;
26  import arch.task.supported.*;
27  import java.util.*;
28  
29  /**
30  *  The JD4X operating system module is known as Linux. Linux is a platform dependent 
31  *  module that deals with all the platform specific needs of the JD4X desktop. It has
32  *  native support for kernel facilties like administration and file system services.
33  *  <BR>Note: Some of J2SDK's functions are undependable for the type of services that
34  *  JD4X requires and therefore there is a need to re-implement some of them to have
35  *  the JD4X system working correctly. An example would be the Runtime.exec() function.
36  *  Careful testing has revealed JNI invokation problems that exist when processes
37  *  created by this facility tries to re-invoke Java code. This same facility also
38  *  causes XSync() to crash the Java threads and results in unpredictable behavior for
39  *  native windowing applications.
40  *  @version 0.1, 05/07/2003
41  *  @see arch.module.major.JXMajorModule
42  *  @see arch.message.error.JXError
43  *  @see arch.message.request.JXRequest
44  *  @see arch.task.LinuxTask
45  *  @see arch.task.supported.LinuxSupportedTask
46  *  @see libjxlin.c
47  *  @since JD4X 1.0
48  *  @author Tay Hock Keong
49  */
50  
51  public final class Linux extends JXMajorModule{
52  
53    /** Table of current running processes */
54    private static volatile Hashtable runPTable;
55  
56    /** Table of current running Jvms */
57    private static volatile Hashtable jvmTable;
58  
59    /** Fixed java commands */
60    private static final String[] jvmCmd = {"java", "-jar",  "-classpath",
61      "appletviewer"};
62  
63    /** Fixed java command extendsions */
64    private static final String[] jvmExt = {".jar", ".class"};
65  
66    /** Linux ID */
67    public static final int LINUX_ID=5;
68  
69    // loading native OS library in static code block.
70    static{
71      System.loadLibrary("jxlin");
72    }
73  
74    /**
75    *  Fork and execute a new linux process.
76    *  @param arg
77    *    the command and its arguments.
78    *  @return
79    *    the specific linux process pid.
80    *  @see libjxlin.c
81    */
82    private native int forkExec0(String arg[]);
83    
84    /**
85    *  kill a linux process.
86    *  @param pid
87    *    the ID of the process to be terminated.
88    *  @see libjxlin.c
89    */
90    private native void kill0(int pid);
91  
92    /**
93    *  Default constructor that creates a new Windowing module with the
94    *  default settings.
95    *  @param home
96    *    the absolute path to the user's home directory.
97    */
98    public Linux(){
99            super(); //refactor to this() when other constructors are up!
100           setModuleID(LINUX_ID);
101           setVersion(0.1F);
102   }
103 
104   /**
105   *  It requests Linux to perform a certain task on another's behalf. The
106   *  task requested must be supported before requesting the task.
107   *  <BR>Note: Peer methods run under commit are executed in a seperate
108   *  thread in JUNK and will not block the other modules. Some peer
109   *  functions here are infinite loops and cannot be directly called.
110   *  @param task
111   *    the task that the requester wants the provider to do.
112   *  @return
113   *    the error that occured, if any, wrap in a JXError object. null
114   *    is returned if no error occured.
115   *  <dt><b>Precondition:</b><dd>
116   *    Linux ensures that the security manager has granted the
117   *    permission to perform the act, else the task must be denied. 
118   *  <dt><b>Postcondition:</b><dd>
119   *    Linux completes the task assigned to it. Any error that
120   *    occured while performing the task will be managed under the
121   *    thread that executed the task.
122   *  @see arch.task.LinuxTask
123   *  @see arch.task.supported.LinuxSupportedTask
124   */
125   public JXError commit(JXTask task){
126     JXError reply = null;
127     if(task instanceof LinuxTask){
128       LinuxTask lt = (LinuxTask)task;
129       //check custom permissions?
130       int reqID = lt.getTaskID();
131       if(LinuxSupportedTask.isTaskSupported(reqID)){
132         switch(reqID){
133           case LinuxSupportedTask.FORK_EXEC:
134             requestProcess(lt.getCommand());
135           break;
136 
137           case LinuxSupportedTask.EXEC_JAR:
138             requestJvmJar(lt.getJvmOption(), lt.getCommand());
139           break;
140 
141           case LinuxSupportedTask.EXEC_CLASS:
142             requestJvmClass(lt.getJvmOption(), lt.getFQC());
143           break;
144 
145           case LinuxSupportedTask.KILL_JVM:
146           case LinuxSupportedTask.KILL_PROCESS:
147             terminate(reqID, lt.getPIDs());
148           break;
149 
150           default: //can only result if reqID is mutable.
151           reply = new JXError("Task ID mutation detected, ID=="+reqID);
152           break;
153         }
154       }
155       else{
156         reply = new JXError("Invalid task type, JXTask!=LinuxTask.");
157       }
158     }
159     return reply;
160   }
161 
162   /**
163   *  All major modules must provide the facility to configure 
164   *  its properties such that user customization is possible.
165   *  @param prop
166   *    the property that defines the new configuration. prop
167   *    will be interpreted differently depending on the specific
168   *    implementation of the configure method.
169   *  @return
170   *    the error that occured, if any, wrap in a JXError object. null
171   *    is returned if no error occured.  
172   *  <dt><b>Precondition:</b><dd>
173   *    The individual modules must maintain its own default
174   *    configuration values that can be restorted on error.
175   *  <dt><b>Postcondition:</b><dd>
176   *    The module is updated to the new configuration only if
177   *    no error ocurred, else it will fall back to the default
178   *    configuration values. Any error that resulted from the
179   *    new configuration will be managed under the thread that
180   *    executed the configuration procedure.
181   */
182   private JXError configure(Object prop){
183     System.out.println("Linux: configure();");
184     return null;
185   }
186 
187   /**
188   *  Get the list of current running native process IDs.
189   *  @return
190   *    the names of the running processes.
191   */
192   public static Object[] getProcesses(){
193     if(runPTable != null){
194       synchronized(runPTable){
195         return runPTable.keySet().toArray();
196       }
197     }
198     return null;
199   }
200   
201   /**
202   *  Get the list of current running Jvm IDs.
203   *  @return
204   *    the names of the running Jvms.
205   */
206   public static Object[] getJvms(){
207     if(jvmTable != null){
208       synchronized(jvmTable){
209         return jvmTable.keySet().toArray();
210       }
211     }
212     return null;
213   }
214   
215   /**
216   *  It allows the module developer to provide his/her information. The basic
217   *  information should be short and should include the following format each
218   *  on its own line:
219   *  <BR>Module: Name, version
220   *  <BR>Developer: Name, <Email>. Name, <Email>. [...]
221   *  @return
222   *    the credit information that the developer desires to be displayed.
223   *  <dt><b>Postcondition:</b><dd>
224   *    The information to be displayed will be added to the global information
225   *    panel. The display panel is implementation dependent.
226   */
227   public String getCredits(){
228     String m = toString();
229     m = m.replaceAll("<", "&lt;");
230     m = m.replaceAll(">", "&gt;");
231     StringBuffer temp = new StringBuffer("<BR>Module: ").append(m).
232       append("<BR>Developer: Tay Hock Keong, &lt;tay_ivan@hotmail.com&gt;.");
233     return  temp.toString();
234   }
235 
236   /**
237   *  Initialize all resources and to prepare the module to do useful task. 
238   *  @return
239   *    the error that occured, if any, wrap in a JXError object. null
240   *    is returned if no error occured.
241   *  <dt><b>Postcondition:</b><dd>
242   *    The module is properly initialized such that it can support all
243   *    the functionality it is supposed to provide for its clients.
244   *  @see arch.message.error.JXError
245   */
246    public JXError init(){
247     //assume max of 30 processes with 0.75 load factor.
248     runPTable = new Hashtable(40);
249     //assume max of 30 processes with 0.75 load factor.
250     jvmTable = new Hashtable(40);
251     return null;
252   }
253 
254   /**
255   *  All major modules must provide the facility to indicate whether
256   *  it is busy processing some command or it is in an idle state.
257   *  The client calling this method must be ready to defer any task
258   *  that it wants the module to do if the return value is true. If 
259   *  a module do not have shared resources that requires queueing or
260   *  synchronization then this method should always return true.
261   *  @return
262   *    true=the module is current processing something, else
263   *    the module is in its idle state.
264   *  <dt><b>Postcondition:</b><dd>
265   *    If the return value is false, then the module is ready
266   *    to do any task delegated to it, else if the client
267   *    forces the busy module to do its requested task, the
268   *    action taken by the module is undefined depending
269   *    on the different module's implementation.
270   *    
271   */
272   public boolean isBusy(){
273       return false;
274   }
275   
276   /**
277   *  It allows the native code to feed messages back to the standard
278   *  output logged by JUNK. Use for debugging and feedback tracking.
279   *  This method will print a newline at end of the message. Even
280   *  though this method is not a required standard interface but it
281   *  is very useful and should be considered by all implementations.
282   *  @param msg
283   *    the client message to be printed to the GUI.
284   */
285   private static void println(String msg){
286       System.out.println(msg);
287   }
288 
289   /**
290   *  Start a new linux process.
291   *  @param param
292   *    the command and parameters to be passed to a
293   *    JXProcess.
294   *  <dt><b>Postcondition:</b><dd>
295   *    An independent native process is started.
296   */
297   private void requestProcess(String[] params){
298     if((params!=null) && (params[0]!=null)){
299       int pid = forkExec0(params);
300       JXProcess p = new JXProcess(pid, params[0]);
301       synchronized(runPTable){
302         runPTable.put(p.getID(), p);
303       }
304     }
305     else{
306       System.out.println("Linux: Process parameter error, param==null.");
307     }
308   }
309 
310   /**
311   *  Start a new Jvm process using jar invokation.
312   *  @param jvmOpts
313   *    the desired Jvm options.
314   *  @param cmds
315   *    the jar file path and arguments.
316   *  <dt><b>Postcondition:</b><dd>
317   *    An independent Jvm process is started.
318   */
319   private void requestJvmJar(String[] jvmOpts, String[] cmds){
320     String[] argv = null;
321     int k = 1;
322 
323     if((cmds!=null) && (cmds[0]!=null)){
324       if(cmds[0].endsWith(jvmExt[0])){ /* jar file. */
325         if((jvmOpts!=null) && (jvmOpts[0]!=null)){
326           argv = new String[cmds.length+jvmOpts.length+2];
327           for(int i=0; i<jvmOpts.length; i++){
328             argv[k++] = jvmOpts[i];
329           }
330         }
331         else{
332           argv = new String[cmds.length+2];
333         }
334         argv[0] = jvmCmd[0];
335         argv[k++] = jvmCmd[1];
336         for(int i=0; i<cmds.length; i++){
337           argv[k++] = cmds[i];
338         }
339         int pid = forkExec0(argv);
340         JXProcess p = new JXProcess(pid, cmds[0]);
341         synchronized(jvmTable){
342           jvmTable.put(p.getID(), p);
343         }
344       }
345       else{
346         System.out.println("Linux: Jvm jar file parameter error.");
347       }
348     }
349     else{
350       System.out.println("Linux: Jvm jar command error.");
351     }
352   }
353   
354   /**
355   *  Start a new Jvm process using class invokation.
356   *  @param jvmOpts
357   *    the desired Jvm options.
358   *  @param cmds
359   *    the fqc path and arguments.
360   *  <dt><b>Postcondition:</b><dd>
361   *    An independent Jvm process is started.
362   */
363   private void requestJvmClass(String[] jvmOpts, String[] cmds){
364     String[] argv = null;
365     int k = 1;
366 
367     if((cmds!=null) && (cmds[0]!=null)){
368       if((jvmOpts!=null) && (jvmOpts[0]!=null)){
369         argv = new String[cmds.length+jvmOpts.length+1];
370         for(int i=0; i<jvmOpts.length; i++){
371           argv[k++] = jvmOpts[i];
372         }
373       }
374       else{
375         argv = new String[cmds.length+1];
376       }
377       argv[0] = jvmCmd[0];
378       for(int i=0; i<cmds.length; i++){
379         argv[k++] = cmds[i];
380       }
381       int pid = forkExec0(argv);
382       JXProcess p = new JXProcess(pid, cmds[0]);
383       synchronized(jvmTable){
384         jvmTable.put(p.getID(), p);
385       }
386     }
387     else{
388       System.out.println("Linux: Jvm class command error.");
389     }
390   }
391   
392   /**
393   *  All major modules must provide the facility to restore 
394   *  the previous state of the module such that it can retain
395   *  previous module configurations and preferences.
396   *  @return
397   *    the restore status error that occured, if any, wrap in
398   *    a JXError object. null is returned if no error occured. 
399   *  <dt><b>Precondition:</b><dd>
400   *    The previous state of the module must have already been
401   *    saved into persistent storage.
402   *  <dt><b>Postcondition:</b><dd>
403   *    The module is restored to its previous state according
404   *    to the saved data. If any error occured during the 
405   *    restoration or if no saved data is available, a default
406   *    state must be provided by the module as a backup.
407   */
408    public JXError restoreState(){
409     System.out.println("Linux: restoreState();");
410     return null;
411   }
412 
413   /**
414   *  All major modules must provide the facility to save the 
415   *  state of the module such that it can be restorted when
416   *  the previous state of the module is desired.
417   *  @return
418   *    the save status error that occured, if any, wrap in a
419   *    JXError object. null is returned if no error occured. 
420   *  <dt><b>Postcondition:</b><dd>
421   *    All configuration, user preference and module component
422   *    states are place into persistent storage such that
423   *    different execution instances can use the common data.
424   */
425   public JXError saveState(){
426     System.out.println("Linux: saveState();");
427     return null;
428   }
429 
430   /**
431   *  Terminate the module, clean up and exit native code.
432   *  @return
433   *    the error that occured, if any, wrap in a JXError object. null
434   *    is returned if no error occured.
435   *  @see arch.message.error.JXError
436   */
437    public JXError shutdown(){
438     //Jvm shutdown
439     terminate(LinuxSupportedTask.KILL_JVM, jvmTable.keySet().toArray());
440     //process shutdown
441     terminate(LinuxSupportedTask.KILL_PROCESS, runPTable.keySet().toArray());
442     runPTable.clear();
443     jvmTable.clear();
444     return null;
445   }
446 
447   /**
448   *  Allow the terminating of any task that Linux has been requested to perform.
449   *  Tasks that are waiting to be executed or is already being executed will
450   *  be halted and removed from Linux's task list. A terminiated task cannot
451   *  be restarted or referenced again.
452   *  @param id
453   *    the type of task/tasks to be terminated.
454   *  @param param
455   *    the task ID/IDs that is/are being requested for termination.
456   */
457   private void terminate(int id, Object[] param){
458     JXError e = null;
459     JXProcess p = null;
460 
461     for(int i=0; i<param.length; i++){
462       if(id == LinuxSupportedTask.KILL_PROCESS){
463         synchronized(runPTable){
464           p = (JXProcess)runPTable.remove(param[i]);
465         }
466       }
467       else if(id == LinuxSupportedTask.KILL_JVM){
468         synchronized(jvmTable){
469           p = (JXProcess)jvmTable.remove(param[i]);
470         }
471       }
472       if(p != null){
473         kill0(p.getID().intValue());
474       }
475       else{
476         System.out.println("Linux: Unknown termination process "+p.toString());
477       }
478     }
479   }
480 
481   /**
482   *  A String representation of the core module. The exact details of the
483   *  representation are unspecified and subject to change, but the following
484   *  maybe regarded as typical: JD4X <m5-v0.1>, [mj] LINUX.
485   *  It can be interpreted as module id = 5, version = 0.1 and a major module
486   *  known as Linux.
487   *  @return
488   *    the string representation of Linux with its module status.
489   *  @see arch.module.major.JXMajorModule
490   */
491   public String toString(){
492     StringBuffer temp = new StringBuffer(super.toString()).append(" LINUX");
493     return  temp.toString();
494   }
495 
496   /**
497   *  Testing function.
498   */
499   public static void main(String[] argv){
500     String[] cargv = {"evim", "/home/o27/error"};
501     Linux l = new Linux();
502     l.init();
503     JXTask task = LinuxSupportedTask.getTaskDescription(LinuxSupportedTask.FORK_EXEC);
504     ((LinuxTask)task).setCommand(cargv);
505     l.commit(task);
506   }
507 }