/******************************************************************************
* Copyright (c) 2007 g-Eclipse consortium
* 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
*
* Initial development of the original code was made for
* project g-Eclipse founded by European Union
* project number: FP6-IST-034327 http://www.geclipse.eu/
*
* Contributor(s):
* Mariusz Wojtysiak - initial API and implementation
*
*****************************************************************************/
package eu.geclipse.ui.views.jobdetails;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.swt.widgets.Composite;
import eu.geclipse.core.model.GridModel;
import eu.geclipse.core.model.IGridJob;
import eu.geclipse.core.model.IGridJobID;
import eu.geclipse.core.model.IGridJobStatus;
import eu.geclipse.ui.Extensions;
/**
* Manager of {@link IJobDetailsSection}s
*/
public class JobDetailSectionsManager {
static private int nextId = 1;
static private Integer generalSectionId;
static private Integer applicationSectionId;
static private HashSet<IGridJobID> updatedJobs = new HashSet<IGridJobID>();
private Composite parent; // parent for sections
private Map<Integer, IJobDetailsSection> sectionsMap = new HashMap<Integer, IJobDetailsSection>();
private List<IJobDetail> currentDetails;
private IViewConfiguration viewConfiguration;
/**
* Enum specifying order in which sections appears in view
*/
public enum SectionOrder {
/**
*
*/
GENERAL,
/**
*
*/
APPLICATION;
int getOrder() {
return this.ordinal();
}
}
/**
* @param parent on which {@link IJobDetailsSection}s should be created
* @param viewConfiguration the configuration of view, to which manager is connected
*/
public JobDetailSectionsManager( final Composite parent, final IViewConfiguration viewConfiguration ) {
super();
this.parent = parent;
this.viewConfiguration = viewConfiguration;
}
private static int getNextId() {
return nextId++;
}
void refresh( final IGridJob inputJob )
{
List<IJobDetailsFactory> factories = null;
if( inputJob != null ) {
Class<?> statusClass = inputJob.getJobStatus() != null
? inputJob.getJobStatus()
.getClass()
: null;
factories = Extensions.getJobDetailsFactories( inputJob.getClass(),
statusClass );
}
List<IJobDetail> details = getDetails( inputJob, factories );
List<IJobDetailsSection> sections = getSections( details );
disposeNotUsedDetails( details );
dispatchDetailsToSections( details );
disposeNotUsedSections();
for( IJobDetailsSection section : sections ) {
section.refresh( inputJob, this.parent );
}
this.currentDetails = details;
scheduleJobStatusUpdate( factories, inputJob );
}
private void scheduleJobStatusUpdate( final List<IJobDetailsFactory> factories,
final IGridJob inputJob )
{
if( factories != null
&& inputJob != null ) {
IGridJobID id = inputJob.getID();
if( !JobDetailSectionsManager.updatedJobs.contains( id ) ) {
for( IJobDetailsFactory jobDetailsFactory : factories ) {
if( jobDetailsFactory.shouldUpdateJobStatus( inputJob ) ) {
Job backgroundJob = new Job( String.format( Messages.JobDetailSectionsManager_taskNameUpdateJobStatus, inputJob.getJobName() ) ) {
@Override
protected IStatus run( final IProgressMonitor monitor ) {
IStatus status = Status.OK_STATUS;
IGridJobStatus oldStatus = inputJob.getJobStatus();
inputJob.updateJobStatus( monitor, true );
GridModel.getJobManager().jobStatusChanged( inputJob, oldStatus );
return status;
}
};
JobDetailSectionsManager.updatedJobs.add( id );
backgroundJob.schedule();
break;
}
}
}
}
}
private List<IJobDetail> getDetails( final IGridJob gridJob, final List<IJobDetailsFactory> factories ) {
List<IJobDetail> details = new ArrayList<IJobDetail>( 100 );
if( gridJob != null ) {
for( IJobDetailsFactory jobDetailsFactory : factories ) {
details.addAll( jobDetailsFactory.getDetails( gridJob, this ) );
}
}
return details;
}
private List<IJobDetailsSection> getSections( final List<IJobDetail> details )
{
List<IJobDetailsSection> sections = new ArrayList<IJobDetailsSection>();
for( IJobDetail detail : details ) {
if( !sections.contains( detail.getSection() ) ) {
sections.add( detail.getSection() );
}
}
Collections.sort( sections, new Comparator<IJobDetailsSection>() {
public int compare( final IJobDetailsSection section1,
final IJobDetailsSection section2 )
{
return section1.getOrder() - section2.getOrder();
}
} );
return sections;
}
/**
* Return already created section. If section with given id wasn't created yet
* (returned null), then please call
* {@link JobDetailSectionsManager#createSection(String, int)}
*
* @param sectionId identifier returned from
* {@link JobDetailSectionsManager#createSection(String, int)}
* @return section, or null if section wasn't created yet.
*/
public IJobDetailsSection getSection( final Integer sectionId ) {
return this.sectionsMap.get( sectionId );
}
/**
* @param name name for section
* @param order
* @param lazy <code>true</code> if section should be collapsed after creation, and refresh for details will be called after expansion by user
* @return created section ID
*/
public Integer createSection( final String name, final int order, final boolean lazy ) {
Integer id = Integer.valueOf( getNextId() );
JobDetailsSection section = new JobDetailsSection( name, order, this.viewConfiguration, lazy );
this.sectionsMap.put( id, section );
return id;
}
/**
* @param name name for section
* @param order
* @return created section ID
*/
public Integer createSection( final String name, final int order ) {
return createSection( name, order, false );
}
/**
* @return general section
*/
public IJobDetailsSection getSectionGeneral() {
IJobDetailsSection section = getSection( JobDetailSectionsManager.generalSectionId );
if( section == null ) {
JobDetailSectionsManager.generalSectionId = createSection( Messages.JobDetailSectionsManager_general,
SectionOrder.GENERAL.getOrder() );
section = getSection( JobDetailSectionsManager.generalSectionId );
}
return section;
}
/**
* @return section
*/
public IJobDetailsSection getSectionApplication() {
IJobDetailsSection section = getSection( JobDetailSectionsManager.applicationSectionId );
if( section == null ) {
JobDetailSectionsManager.applicationSectionId = createSection( Messages.JobDetailSectionsManager_application,
SectionOrder.APPLICATION.getOrder() );
section = getSection( JobDetailSectionsManager.applicationSectionId );
}
return section;
}
private void dispatchDetailsToSections( final List<IJobDetail> details ) {
if( details != null ) {
for( IJobDetail detail : details ) {
detail.getSection().addDetail( detail );
}
}
}
private void disposeNotUsedDetails( final List<IJobDetail> newDetails ) {
if( this.currentDetails != null ) {
for( IJobDetail jobDetail : this.currentDetails ) {
if( findDetailById( newDetails,
jobDetail.getId(),
jobDetail.getSection() ) == null )
{
jobDetail.dispose();
jobDetail.getSection().removeDetail( jobDetail );
}
}
}
}
private void disposeNotUsedSections() {
Iterator<Integer> iterator = this.sectionsMap.keySet().iterator();
while( iterator.hasNext() ) {
Integer sectionId = iterator.next();
IJobDetailsSection section = getSection( sectionId );
if( section != null
&& section.getDetails().size() == 0 ) {
section.dispose();
}
}
}
private IJobDetail findDetailById( final List<IJobDetail> details,
final String detailId,
final IJobDetailsSection section )
{
IJobDetail foundDetail = null;
for( Iterator<IJobDetail> iterator = details.iterator(); iterator.hasNext()
&& foundDetail == null; )
{
IJobDetail jobDetail = iterator.next();
if( jobDetail.getSection() == section
&& jobDetail.getId().equals( detailId ) )
{
foundDetail = jobDetail;
}
}
return foundDetail;
}
}