⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 abstractshell.java

📁 Python Development Environment (Python IDE plugin for Eclipse). Features editor, code completion, re
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*
 * Created on 13/08/2005
 */
package org.python.pydev.editor.codecompletion.shell;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.python.copiedfromeclipsesrc.JDTNotAvailableException;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.IToken;
import org.python.pydev.core.Tuple;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.codecompletion.PyCodeCompletion;
import org.python.pydev.editor.codecompletion.PyCodeCompletionPreferencesPage;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.plugin.SocketUtil;
import org.python.pydev.runners.ThreadStreamReader;

/**
 * This is the shell that 'talks' to the python / jython process (it is intended to be subclassed so that
 * we know how to deal with each). 
 * 
 * Its methods are synched to prevent concurrent access.
 * 
 * @author fabioz
 *
 */
public abstract class AbstractShell {

    public static final int BUFFER_SIZE = 1024 ;
    public static final int OTHERS_SHELL = 2;
    public static final int COMPLETION_SHELL = 1;
    protected static final int DEFAULT_SLEEP_BETWEEN_ATTEMPTS = 1000; //1sec, so we can make the number of attempts be shown as elapsed in secs
    protected static final int DEBUG_SHELL = -1;
    
    /**
     * Determines if we are already in a method that starts the shell
     */
    private boolean inStart = false;

    /**
     * Determines if we are (theoretically) already connected (meaning that trying to start the shell
     * again will not do anything)
     * 
     * Ending the shell sets this to false and starting it sets it to true (if successful) 
     */
    private boolean isConnected = false;

    private boolean isInRead = false;
    private boolean isInWrite = false;
    private boolean isInRestart = false;
    
    /**
     * Lock to know if there is someone already using this shell for some operation
     */
    private boolean isInOperation = false;

    private static void dbg(String string, int priority) {
        if(priority <= DEBUG_SHELL){
            System.out.println(string);
        }
        if(PyCodeCompletion.DEBUG_CODE_COMPLETION){
            Log.toLogFile(string, AbstractShell.class);
        }
    }

    /**
     * the encoding used to encode messages
     */
    private static final String ENCODING_UTF_8 = "UTF-8";
    
    /**
     * Reference to 'global python shells'
     * 
     * this works as follows:
     * we have a 'related to' id as the first step, according to the IPythonNature constants
     * 
     * @see org.python.pydev.core.IPythonNature#PYTHON_RELATED
     * @see org.python.pydev.core.IPythonNature#JYTHON_RELATED
     * 
     * and then we have the id with the shell type that points to the actual shell
     * 
     * @see #COMPLETION_SHELL
     * @see #OTHERS_SHELL
     */
    protected static Map<Integer,Map<Integer,AbstractShell>> shells = new HashMap<Integer,Map<Integer,AbstractShell>>();
    
    /**
     * if we are already finished for good, we may not start new shells (this is a static, because this 
     * should be set only at shutdown).
     */
    private static boolean finishedForGood = false;
    
    /**
     * simple stop of a shell (it may be later restarted)
     */
    public synchronized static void stopServerShell(int relatedId, int id) {
        Map<Integer, AbstractShell> typeToShell = getTypeToShellFromId(relatedId);
        AbstractShell pythonShell = (AbstractShell) typeToShell.get(new Integer(id));
        
        if(pythonShell != null){
            try {
                pythonShell.endIt();
            } catch (Exception e) {
                // ignore... we are ending it anyway...
            }
        }
    }

    
    /**
     * stops all registered shells 
     *
     */
    public synchronized static void shutdownAllShells(){
    	synchronized(shells){
	        for (Iterator<Map<Integer, AbstractShell>> iter = shells.values().iterator(); iter.hasNext();) {
	            finishedForGood = true;  //we may no longer restart shells
	            
	            Map<Integer,AbstractShell> rel = (Map<Integer, AbstractShell>) iter.next();
	            if(rel != null){
	                for (Iterator iter2 = rel.values().iterator(); iter2.hasNext();) {
	                    AbstractShell element = (AbstractShell) iter2.next();
	                    if(element != null){
	                        try {
	                            element.shutdown(); //shutdown
	                        } catch (Exception e) {
	                            PydevPlugin.log(e); //let's log it... this should not happen
	                        }
	                    }
	                }
	            }
	        }
	        shells.clear();
    	}
    }

    /**
     * @param relatedId the id that is related to the structure we want to get
     * @return a map with the type of the shell mapping to the shell itself
     */
    private synchronized static Map<Integer, AbstractShell> getTypeToShellFromId(int relatedId) {
    	synchronized(shells){
	        Map<Integer, AbstractShell> typeToShell = shells.get(relatedId);
	        
	        if (typeToShell == null) {
	            typeToShell = new HashMap<Integer, AbstractShell>();
	            shells.put(relatedId, typeToShell);
	        }
	        return typeToShell;
    	}
    }

    /**
     * register a shell and give it an id
     * @param id the shell id
     * @param shell the shell to register
     * 
     * @see org.python.pydev.core.IPythonNature#PYTHON_RELATED
     * @see org.python.pydev.core.IPythonNature#JYTHON_RELATED
     * 
     * @see #COMPLETION_SHELL
     * @see #OTHERS_SHELL
     */
    public synchronized static void putServerShell(IPythonNature nature, int id, AbstractShell shell) {
        try {
            Map<Integer, AbstractShell> typeToShell = getTypeToShellFromId(nature.getRelatedId());
            typeToShell.put(new Integer(id), shell);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public synchronized static AbstractShell getServerShell(IPythonNature nature, int id) throws IOException, JDTNotAvailableException, CoreException {
        return getServerShell(nature.getRelatedId(), id);
    }
    
    /**
     * @return the shell with the given id related to some nature
     * 
     * @see org.python.pydev.core.IPythonNature#PYTHON_RELATED
     * @see org.python.pydev.core.IPythonNature#JYTHON_RELATED
     * 
     * @see #COMPLETION_SHELL
     * @see #OTHERS_SHELL
     * 
     * @throws CoreException
     * @throws IOException
     */
    public synchronized static AbstractShell getServerShell(int relatedId, int id) throws IOException, JDTNotAvailableException, CoreException {
    	AbstractShell pythonShell = null;
    	synchronized(shells){
    	    if(PyCodeCompletion.DEBUG_CODE_COMPLETION){
    	        Log.toLogFile("Synchronizing on shells...", AbstractShell.class);
    	    }
            if(PyCodeCompletion.DEBUG_CODE_COMPLETION){
                Log.toLogFile( "Getting shell relatedId:"+relatedId+" id:"+id, AbstractShell.class);
            }
	        Map<Integer, AbstractShell> typeToShell = getTypeToShellFromId(relatedId);
	        pythonShell = (AbstractShell) typeToShell.get(new Integer(id));
	        
	        if(pythonShell == null){
                if(PyCodeCompletion.DEBUG_CODE_COMPLETION){
                    Log.toLogFile("pythonShell == null", AbstractShell.class);
                }
	            if(relatedId == IPythonNature.PYTHON_RELATED){
	                pythonShell = new PythonShell();
	            }else if(relatedId == IPythonNature.JYTHON_RELATED){
	                pythonShell = new JythonShell();
	            }else{
	                throw new RuntimeException("unknown related id");
	            }
                if(PyCodeCompletion.DEBUG_CODE_COMPLETION){
                    Log.toLogFile("pythonShell.startIt()", AbstractShell.class);
                    Log.addLogLevel();
                }
            	pythonShell.startIt(); //first start it
            	if(PyCodeCompletion.DEBUG_CODE_COMPLETION){
            	    Log.remLogLevel();
            	    Log.toLogFile("Finished pythonShell.startIt()", AbstractShell.class);
            	}
	            
	            //then make it accessible
	            typeToShell.put(new Integer(id), pythonShell);
	        }
            
    	}
    	return pythonShell;
    }

    /**
     * Python server process.
     */
    protected Process process;
    /**
     * We should write in this socket.
     */
    protected Socket socketToWrite;
    /**
     * We should read this socket.
     */
    protected Socket socketToRead;
    /**
     * Python file that works as the server.
     */
    protected File serverFile;
    /**
     * Server socket (accept connections).
     */
    protected ServerSocket serverSocket;
    private ThreadStreamReader stdReader;
    private ThreadStreamReader errReader;

    
    /**
     * Initialize given the file that points to the python server (execute it
     * with python).
     *  
     * @param f file pointing to the python server
     * 
     * @throws IOException
     * @throws CoreException
     */
    protected AbstractShell(File f) throws IOException, CoreException {
        if(finishedForGood){
            throw new RuntimeException("Shells are already finished for good, so, it is an invalid state to try to create a new shell.");
        }
        
        serverFile = f;
        if(!serverFile.exists()){
            throw new RuntimeException("Can't find python server file");
        }
    }

    /**
     * Just wait a little...
     */
    protected synchronized void sleepALittle(int t) {
        try {
            synchronized(this){
                wait(t); //millis
            }
        } catch (InterruptedException e) {
        }
    }

    /**
     * This method creates the python server process and starts the sockets, so that we
     * can talk with the server.
     * @throws IOException
     * @throws CoreException
     */
    public synchronized void startIt() throws IOException, JDTNotAvailableException, CoreException {
    	synchronized(this){
    		this.startIt(AbstractShell.DEFAULT_SLEEP_BETWEEN_ATTEMPTS);
    	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -