| /******************************************************************************* |
| * Copyright (c) 2003, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ant.internal.ui.launchConfigurations; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| import java.net.SocketException; |
| import java.net.SocketTimeoutException; |
| 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.apache.tools.ant.Project; |
| import org.apache.tools.ant.util.FileUtils; |
| import org.eclipse.ant.internal.core.AbstractEclipseBuildLogger; |
| import org.eclipse.ant.internal.ui.AntUIPlugin; |
| import org.eclipse.ant.internal.ui.AntUtil; |
| import org.eclipse.ant.internal.ui.ExternalHyperlink; |
| import org.eclipse.ant.internal.ui.IAntUIConstants; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.runtime.ISafeRunnable; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.ILaunch; |
| import org.eclipse.debug.core.ILaunchesListener; |
| import org.eclipse.debug.core.model.IProcess; |
| import org.eclipse.debug.ui.console.FileLink; |
| import org.eclipse.jface.text.Region; |
| import org.eclipse.ui.console.IHyperlink; |
| |
| /** |
| * Parts adapted from org.eclipse.jdt.internal.junit.ui.RemoteTestRunnerClient |
| * The client side of the RemoteAntBuildLogger. Handles the |
| * marshalling of the different messages. |
| */ |
| public class RemoteAntBuildListener implements ILaunchesListener { |
| public abstract class ListenerSafeRunnable implements ISafeRunnable { |
| public void handleException(Throwable exception) { |
| AntUIPlugin.log(exception); |
| } |
| } |
| |
| /** |
| * The server socket |
| */ |
| private ServerSocket fServerSocket; |
| private static final int fgServerSocketTimeout= 10000; |
| private Socket fSocket; |
| private int fPort= -1; |
| private BufferedReader fBufferedReader; |
| protected boolean fDebug= false; |
| private IProcess fProcess; |
| private String fProcessId; |
| private File fBuildFileParent= null; |
| private List fMessageQueue; |
| protected ILaunch fLaunch; |
| private Map fFileNameToIFile= new HashMap(); |
| private String fLastFileName= null; |
| private String fLastTaskName= null; |
| private boolean fBuildFailed= false; |
| |
| /** |
| * Reads the message stream from the RemoteAntBuildLogger |
| */ |
| private class ServerConnection extends Thread { |
| private int fServerPort; |
| |
| public ServerConnection(int port) { |
| super("Ant Build Server Connection"); //$NON-NLS-1$ |
| setDaemon(true); |
| fServerPort= port; |
| } |
| |
| public void run() { |
| Exception exception= null; |
| try { |
| if (fDebug) { |
| System.out.println("Creating server socket " + fServerPort); //$NON-NLS-1$ |
| } |
| fServerSocket= new ServerSocket(fServerPort); |
| fServerSocket.setSoTimeout(fgServerSocketTimeout); |
| fSocket= fServerSocket.accept(); |
| if (fDebug) { |
| System.out.println("Connection"); //$NON-NLS-1$ |
| } |
| fBufferedReader= new BufferedReader(new InputStreamReader(fSocket.getInputStream())); |
| String message; |
| while(fBufferedReader != null && (message= fBufferedReader.readLine()) != null) { |
| receiveMessage(message); |
| } |
| } catch (SocketException e) { |
| } catch (SocketTimeoutException e) { |
| exception= e; |
| } catch (IOException e) { |
| // fall through |
| exception= e; |
| } |
| if (exception != null) { |
| AntUIPlugin.log(exception); |
| } |
| shutDown(); |
| } |
| } |
| |
| public RemoteAntBuildListener(ILaunch launch) { |
| super(); |
| fLaunch= launch; |
| DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); |
| } |
| |
| /** |
| * Start listening to an Ant build. Start a server connection that |
| * the RemoteAntBuildLogger can connect to. |
| * |
| * @param port The port number to create the server connection on |
| */ |
| public synchronized void startListening(int eventPort){ |
| fPort = eventPort; |
| ServerConnection connection = new ServerConnection(eventPort); |
| connection.start(); |
| } |
| |
| protected synchronized void shutDown() { |
| if (fDebug) { |
| System.out.println("shutdown " + fPort); //$NON-NLS-1$ |
| } |
| fLaunch= null; |
| fFileNameToIFile= null; |
| DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this); |
| try { |
| if (fBufferedReader != null) { |
| fBufferedReader.close(); |
| fBufferedReader= null; |
| } |
| } catch(IOException e) { |
| } |
| try{ |
| if(fSocket != null) { |
| fSocket.close(); |
| fSocket= null; |
| } |
| } catch(IOException e) { |
| } |
| try{ |
| if(fServerSocket != null) { |
| fServerSocket.close(); |
| fServerSocket= null; |
| } |
| } catch(IOException e) { |
| } |
| } |
| |
| protected void receiveMessage(String message) { |
| if (fDebug) { |
| System.out.println(message); |
| } |
| if (message.startsWith(MessageIds.TASK)) { |
| receiveTaskMessage(message); |
| } else if (message.startsWith(MessageIds.TARGET)) { |
| receiveTargetMessage(message); |
| } else if (message.startsWith(MessageIds.PROCESS_ID)) { |
| message= message.substring(MessageIds.PROCESS_ID.length()); |
| fProcessId= message; |
| } else { |
| int index= message.indexOf(','); |
| if (index > 0) { |
| int priority= Integer.parseInt(message.substring(0, index)); |
| message= message.substring(index + 1); |
| |
| writeMessage(message + System.getProperty("line.separator"), priority); //$NON-NLS-1$ |
| if (message.startsWith("BUILD FAILED")) { //$NON-NLS-1$ |
| fBuildFailed= true; |
| } else if (fBuildFailed) { |
| AntUtil.linkBuildFailedMessage(message, getProcess()); |
| fBuildFailed= false; |
| } |
| } |
| } |
| } |
| |
| private void receiveTargetMessage(String message) { |
| message= message.substring(MessageIds.TARGET.length()); |
| StringTokenizer tokenizer= new StringTokenizer(message, ","); //$NON-NLS-1$ |
| message= tokenizer.nextToken(); |
| if (tokenizer.hasMoreTokens()) { |
| String location= tokenizer.nextToken(); |
| int lineNumber= Integer.parseInt(tokenizer.nextToken()); |
| generateLink(message, location, lineNumber, 0, message.length() - 1); |
| } |
| writeMessage(message + System.getProperty("line.separator"), Project.MSG_INFO); //$NON-NLS-1$ |
| } |
| |
| private void receiveTaskMessage(String message) { |
| message= message.substring(MessageIds.TASK.length()); |
| |
| int index= message.indexOf(','); |
| int priority= Integer.parseInt(message.substring(0, index)); |
| int index2= message.indexOf(',', index + 1); |
| String taskName= message.substring(index + 1, index2); |
| if (taskName.length() == 0) { |
| taskName= fLastTaskName; |
| } |
| int index3= message.indexOf(',', index2 + 1); |
| int lineLength= Integer.parseInt(message.substring(index2 + 1, index3)); |
| int index4= index3 + 1 + lineLength; |
| |
| String line= message.substring(index3 + 1, index4); |
| StringBuffer labelBuff= new StringBuffer(); |
| labelBuff.append('['); |
| labelBuff.append(taskName); |
| labelBuff.append("] "); //$NON-NLS-1$ |
| labelBuff.append(line); |
| line= labelBuff.toString(); |
| |
| fLastTaskName= taskName; |
| int finalIndex= message.indexOf(',', index4 + 1); |
| String fileName= message.substring(index4 + 1, finalIndex); |
| if (fileName.length() == 0) { |
| fileName= fLastFileName; |
| } |
| fLastFileName= fileName; |
| int lineNumber= Integer.parseInt(message.substring(finalIndex + 1)); |
| |
| int size = IAntUIConstants.LEFT_COLUMN_SIZE - (taskName.length() + 3); |
| int offset = Math.max(size - 2, 1); |
| int length = IAntUIConstants.LEFT_COLUMN_SIZE - size - 3; |
| if (fileName != null) { |
| generateLink(line, fileName, lineNumber, offset, length); |
| } |
| |
| StringBuffer fullMessage= new StringBuffer(); |
| adornMessage(taskName, line, fullMessage); |
| writeMessage(fullMessage.append(System.getProperty("line.separator")).toString(), priority); //$NON-NLS-1$ |
| } |
| |
| private void generateLink(String line, String fileName, int lineNumber, int offset, int length) { |
| IHyperlink taskLink= null; |
| if (lineNumber == -1) { |
| //fileName will actually be the String representation of Location |
| taskLink = AntUtil.getLocationLink(fileName, fBuildFileParent); |
| } else { |
| IFile file= (IFile) fFileNameToIFile.get(fileName); |
| if (file == null) { |
| file= AntUtil.getFileForLocation(fileName, fBuildFileParent); |
| if (file != null) { |
| fFileNameToIFile.put(fileName, file); |
| taskLink= new FileLink(file, null, -1, -1, lineNumber); |
| } else { |
| File javaIOFile= FileUtils.newFileUtils().resolveFile(fBuildFileParent, fileName); |
| if (javaIOFile.exists()) { |
| taskLink= new ExternalHyperlink(javaIOFile, lineNumber); |
| } |
| } |
| } else { |
| taskLink= new FileLink(file, null, -1, -1, lineNumber); |
| } |
| } |
| if (taskLink != null) { |
| TaskLinkManager.addTaskHyperlink(getProcess(), taskLink, new Region(offset, length), line); |
| } |
| } |
| |
| /** |
| * Returns the associated process, finding it if necessary. |
| */ |
| protected IProcess getProcess() { |
| if (fProcess == null) { |
| if (fProcessId != null) { |
| IProcess[] all = DebugPlugin.getDefault().getLaunchManager().getProcesses(); |
| for (int i = 0; i < all.length; i++) { |
| IProcess process = all[i]; |
| if (fProcessId.equals(process.getAttribute(AbstractEclipseBuildLogger.ANT_PROCESS_ID))) { |
| fProcess = process; |
| break; |
| } |
| } |
| } |
| } |
| return fProcess; |
| } |
| |
| private AntStreamMonitor getMonitor(int priority) { |
| IProcess process= getProcess(); |
| if (process == null) { |
| return null; |
| } |
| AntStreamsProxy proxy = (AntStreamsProxy)process.getStreamsProxy(); |
| if (proxy == null) { |
| return null; |
| } |
| AntStreamMonitor monitor = null; |
| switch (priority) { |
| case Project.MSG_INFO: |
| monitor = (AntStreamMonitor)proxy.getOutputStreamMonitor(); |
| break; |
| case Project.MSG_ERR: |
| monitor = (AntStreamMonitor)proxy.getErrorStreamMonitor(); |
| break; |
| case Project.MSG_DEBUG: |
| monitor = (AntStreamMonitor)proxy.getDebugStreamMonitor(); |
| break; |
| case Project.MSG_WARN: |
| monitor = (AntStreamMonitor)proxy.getWarningStreamMonitor(); |
| break; |
| case Project.MSG_VERBOSE: |
| monitor = (AntStreamMonitor)proxy.getVerboseStreamMonitor(); |
| break; |
| } |
| return monitor; |
| } |
| |
| /** |
| * Builds a right justified task prefix for the given build event, placing it |
| * in the given string buffer. |
| * |
| * @param event build event |
| * @param fullMessage buffer to place task prefix in |
| */ |
| private void adornMessage(String taskName, String line, StringBuffer fullMessage) { |
| if (taskName == null) { |
| taskName = "null"; //$NON-NLS-1$ |
| } |
| |
| int size = IAntUIConstants.LEFT_COLUMN_SIZE - (taskName.length() + 6); |
| for (int i = 0; i < size; i++) { |
| fullMessage.append(' '); |
| } |
| |
| fullMessage.append(line); |
| } |
| |
| protected void writeMessage(String message, int priority) { |
| AntStreamMonitor monitor= getMonitor(priority); |
| if (monitor == null) { |
| if (fMessageQueue == null) { |
| fMessageQueue= new ArrayList(); |
| } |
| fMessageQueue.add(message); |
| return; |
| } |
| if (fMessageQueue != null) { |
| for (Iterator iter = fMessageQueue.iterator(); iter.hasNext();) { |
| String oldMessage = (String) iter.next(); |
| monitor.append(oldMessage); |
| } |
| fMessageQueue= null; |
| } |
| monitor.append(message); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchesListener#launchesAdded(org.eclipse.debug.core.ILaunch[]) |
| */ |
| public void launchesAdded(ILaunch[] launches) { |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchesListener#launchesChanged(org.eclipse.debug.core.ILaunch[]) |
| */ |
| public void launchesChanged(ILaunch[] launches) { |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchesListener#launchesRemoved(org.eclipse.debug.core.ILaunch[]) |
| */ |
| public void launchesRemoved(ILaunch[] launches) { |
| for (int i = 0; i < launches.length; i++) { |
| ILaunch launch = launches[i]; |
| if (launch.equals(fLaunch)) { |
| shutDown(); |
| return; |
| } |
| } |
| } |
| } |