/** * This file is protected by Copyright. * Please refer to the COPYRIGHT file distributed with this source distribution. * * This file is part of REDHAWK IDE. * * 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 */ package gov.redhawk.logging.ui.jobs; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.transaction.RunnableWithResult; import org.omg.CORBA.BAD_PARAM; import CF.LogConfiguration; import CF.LogConfigurationHelper; import gov.redhawk.logging.ui.LogLevels; import gov.redhawk.logging.ui.LoggingUiPlugin; import gov.redhawk.logging.ui.config.Log4JConfigGenerator; import gov.redhawk.model.sca.CorbaObjWrapper; import gov.redhawk.model.sca.RefreshDepth; import gov.redhawk.model.sca.ScaDomainManager; import gov.redhawk.model.sca.ScaEventChannel; import gov.redhawk.model.sca.commands.ScaModelCommandWithResult; import gov.redhawk.sca.util.OrbSession; import gov.redhawk.sca.util.SubMonitor; import mil.jpeojtrs.sca.util.CorbaUtils; import mil.jpeojtrs.sca.util.ScaEcoreUtils; public class CreateEventChannelLogger extends Job { /** * Time in ms to wait for event channel to be found after a logging configuration is adjusted to use one. */ private static final long WAIT_FOR_EVENT_CHANNEL = 5000; /** * How long to sleep in our wait loop */ private static final long WAIT_LOOP_SLEEP = 250; private CorbaObjWrapper< ? > modelObject; private LogConfiguration corbaObject; private String logger; private LogLevels logLevel; private ScaDomainManager domMgr; private String eventChannelName = null; private String oldLogConfig = null; private ScaEventChannel eventChannel = null; private OrbSession session; public CreateEventChannelLogger(CorbaObjWrapper< ? > modelObject, String logger, LogLevels logLevel) { super(Messages.CreateEventChannelLogger_0); this.modelObject = modelObject; this.logger = logger; this.logLevel = logLevel; this.domMgr = ScaEcoreUtils.getEContainerOfType((EObject) modelObject, ScaDomainManager.class); if (this.domMgr == null) { throw new IllegalArgumentException(Messages.CreateEventChannelLogger_1); } } /** * Create a job to undo the logging configuration changes made by this job. This should only be called if this job * has already completed successfully. * @return */ public Job createCleanupJob() { return new DestroyEventChannelLoggerJob(session, corbaObject, eventChannelName); } /** * Gets the event channel created to receive logging events * @return the event channel, or null if not created */ public ScaEventChannel getEventChannel() { return eventChannel; } @Override protected IStatus run(IProgressMonitor monitor) { final int WORK_NARROW = 1; final int WORK_ADJUST_LOG_CONFIG = 2; final int WORK_FETCH_EVENT_CHANNELS = 4; SubMonitor progress = SubMonitor.convert(monitor, WORK_NARROW + WORK_ADJUST_LOG_CONFIG + WORK_FETCH_EVENT_CHANNELS); // Generate event channel name, new logging configuration eventChannelName = createEventChannelName(); // Create a new session session = OrbSession.createSession("gov.redhawk.logging.ui"); //$NON-NLS-1$ // Get a narrowed CORBA object using our own ORB (so we're independent of the model) // We use an unchecked narrow, but we specifically handle a BAD_PARAM exception below String ior = modelObject.getIor(); org.omg.CORBA.Object obj = session.getOrb().string_to_object(ior); corbaObject = LogConfigurationHelper.unchecked_narrow(obj); progress.worked(WORK_NARROW); // Update the logging config try { oldLogConfig = CorbaUtils.invoke(new Callable<String>() { @Override public String call() throws Exception { String logConfig = corbaObject.getLogConfig(); List<String> oldAppenders = Log4JConfigGenerator.getExistingAppenders(logConfig, logger); String appendToConfig = Log4JConfigGenerator.createLog4jConfig(domMgr.getName(), eventChannelName, logger, logLevel, oldAppenders); corbaObject.setLogConfig(logConfig + appendToConfig); return logConfig; } }, progress.newChild(WORK_ADJUST_LOG_CONFIG)); } catch (CoreException e) { if (e.getCause() instanceof BAD_PARAM) { Status status = new Status(IStatus.ERROR, LoggingUiPlugin.PLUGIN_ID, Messages.CreateEventChannelLogger_3, e); return rollback(progress, status); } Status status = new Status(IStatus.ERROR, LoggingUiPlugin.PLUGIN_ID, Messages.CreateEventChannelLogger_4, e); return rollback(progress, status); } catch (InterruptedException e) { return rollback(progress, null); } // Allow the event channel a little time to show up and be found long startTime = System.currentTimeMillis(); SubMonitor waitProgress = progress.newChild(WORK_FETCH_EVENT_CHANNELS).setWorkRemaining((int) (WAIT_FOR_EVENT_CHANNEL / WAIT_LOOP_SLEEP)); while (eventChannel == null && System.currentTimeMillis() < startTime + WAIT_FOR_EVENT_CHANNEL) { // Refresh event channel list domMgr.fetchEventChannels(waitProgress.newChild(1), RefreshDepth.NONE); if (progress.isCanceled()) { return rollback(progress, null); } // Locate event channel by name try { eventChannel = ScaModelCommandWithResult.runExclusive(domMgr, new RunnableWithResult.Impl<ScaEventChannel>() { @Override public void run() { for (ScaEventChannel eventChannelCandidate : domMgr.getEventChannels()) { if (eventChannelName.equals(eventChannelCandidate.getName())) { setResult(eventChannelCandidate); return; } } } }); } catch (InterruptedException e1) { if (progress.isCanceled()) { return rollback(progress, null); } else { IStatus status = new Status(IStatus.ERROR, LoggingUiPlugin.PLUGIN_ID, Messages.CreateEventChannelLogger_5); return rollback(progress, status); } } // Sleep for a moment try { Thread.sleep(WAIT_LOOP_SLEEP); } catch (InterruptedException e) { if (progress.isCanceled()) { return rollback(progress, null); } else { IStatus status = new Status(IStatus.ERROR, LoggingUiPlugin.PLUGIN_ID, Messages.CreateEventChannelLogger_5); return rollback(progress, status); } } } if (eventChannel == null) { String msg = Messages.bind(Messages.CreateEventChannelLogger_6, eventChannelName); IStatus status = new Status(IStatus.ERROR, LoggingUiPlugin.PLUGIN_ID, msg); return rollback(progress, status); } progress.done(); return Status.OK_STATUS; } private String createEventChannelName() { try { String hostname = InetAddress.getLocalHost().getHostName().replace('.', '_'); return "IDE_" + hostname + "_" + System.currentTimeMillis(); //$NON-NLS-1$ //$NON-NLS-2$ } catch (UnknownHostException e) { return "IDE_" + System.currentTimeMillis(); //$NON-NLS-1$ } } /** * Performs rollback of the log configuration changes, and finalizes work on the monitor. * @param monitor The progress monitor from {@link #run(IProgressMonitor)} * @param errorStatus The error causing a rollback, or null if rollback is due to * {@link IProgressMonitor#isCanceled()} * @return An appropriate return status for {@link #run(IProgressMonitor)} */ private IStatus rollback(IProgressMonitor monitor, IStatus errorStatus) { // If we were cancelled, clear it so we can try rollback, but possibly be cancelled again boolean cancelled = monitor.isCanceled(); if (cancelled) { monitor.setCanceled(false); } monitor.setTaskName(Messages.CreateEventChannelLogger_10); List<IStatus> statuses = new ArrayList<IStatus>(); if (errorStatus != null) { statuses.add(errorStatus); } // Attempt rollback of log config try { if (oldLogConfig != null) { CorbaUtils.invoke(new Callable<Object>() { @Override public String call() throws Exception { corbaObject.setLogConfig(oldLogConfig); return null; } }, monitor); } } catch (CoreException e) { statuses.add(new Status(IStatus.ERROR, LoggingUiPlugin.PLUGIN_ID, Messages.CreateEventChannelLogger_11, e)); } catch (InterruptedException e) { statuses.add(new Status(IStatus.ERROR, LoggingUiPlugin.PLUGIN_ID, Messages.CreateEventChannelLogger_12)); } // Release the CORBA object if (corbaObject != null) { CorbaUtils.release(corbaObject); } // Dispose the session if (session != null) { session.dispose(); } // Restore cancellation status if we cleared it if (cancelled) { monitor.setCanceled(true); } monitor.done(); switch (statuses.size()) { case 0: return Status.CANCEL_STATUS; case 1: return statuses.get(0); default: MultiStatus multiStatus = new MultiStatus(LoggingUiPlugin.PLUGIN_ID, 0, Messages.CreateEventChannelLogger_13, null); for (IStatus status : statuses) { multiStatus.add(status); } return multiStatus; } } }