/*******************************************************************************
* Copyright (c) 2015 IBH SYSTEMS GmbH.
* 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:
* IBH SYSTEMS GmbH - initial API and implementation
*******************************************************************************/
package org.eclipse.packagedrone.repo.channel.web.channel;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.packagedrone.job.JobHandle;
import org.eclipse.packagedrone.job.JobManager;
import org.eclipse.packagedrone.repo.channel.ChannelInformation;
import org.eclipse.packagedrone.repo.channel.ChannelService;
import org.eclipse.packagedrone.repo.channel.ReadableChannel;
import org.eclipse.packagedrone.repo.importer.Importer;
import org.eclipse.packagedrone.repo.importer.ImporterDescription;
import org.eclipse.packagedrone.repo.importer.job.ImporterResult;
import org.eclipse.packagedrone.repo.importer.web.ImportDescriptor;
import org.eclipse.packagedrone.repo.importer.web.ImportRequest;
import org.eclipse.packagedrone.repo.web.utils.Channels;
import org.eclipse.packagedrone.sec.web.controller.HttpContraintControllerInterceptor;
import org.eclipse.packagedrone.sec.web.controller.Secured;
import org.eclipse.packagedrone.sec.web.controller.SecuredControllerInterceptor;
import org.eclipse.packagedrone.web.Controller;
import org.eclipse.packagedrone.web.LinkTarget;
import org.eclipse.packagedrone.web.ModelAndView;
import org.eclipse.packagedrone.web.RequestMapping;
import org.eclipse.packagedrone.web.RequestMethod;
import org.eclipse.packagedrone.web.ViewResolver;
import org.eclipse.packagedrone.web.common.InterfaceExtender;
import org.eclipse.packagedrone.web.common.Modifier;
import org.eclipse.packagedrone.web.common.menu.MenuEntry;
import org.eclipse.packagedrone.web.controller.ControllerInterceptor;
import org.eclipse.packagedrone.web.controller.binding.PathVariable;
import org.eclipse.packagedrone.web.controller.binding.RequestParameter;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import com.google.gson.GsonBuilder;
@Secured
@Controller
@ViewResolver ( "/WEB-INF/views/imp/%s.jsp" )
@ControllerInterceptor ( SecuredControllerInterceptor.class )
@HttpConstraint ( rolesAllowed = "MANAGER" )
@ControllerInterceptor ( HttpContraintControllerInterceptor.class )
public class ImportController implements InterfaceExtender
{
private ChannelService service;
private ImportManager impManager;
private JobManager jobManager;
public static class ImporterDescriptionLabelComparator implements Comparator<ImporterDescription>
{
@Override
public int compare ( final ImporterDescription o1, final ImporterDescription o2 )
{
return o1.getLabel ().compareTo ( o2.getLabel () );
}
}
private static ImporterDescriptionLabelComparator NAME_COMPARATOR = new ImporterDescriptionLabelComparator ();
private static class Entry
{
private final BundleContext context;
private final Importer service;
private final ServiceReference<Importer> reference;
private final ImporterDescription description;
public Entry ( final BundleContext context, final ServiceReference<Importer> reference )
{
this.context = context;
this.reference = reference;
this.service = context.getService ( reference );
this.description = this.service.getDescription ();
}
public void dispose ()
{
this.context.ungetService ( this.reference );
}
public ImporterDescription getDescription ()
{
return this.description;
}
}
private ServiceTracker<Importer, Entry> tracker;
private final ServiceTrackerCustomizer<Importer, Entry> customizer = new ServiceTrackerCustomizer<Importer, Entry> () {
@Override
public void removedService ( final ServiceReference<Importer> reference, final Entry service )
{
service.dispose ();
}
@Override
public void modifiedService ( final ServiceReference<Importer> reference, final Entry service )
{
}
@Override
public Entry addingService ( final ServiceReference<Importer> reference )
{
return new Entry ( FrameworkUtil.getBundle ( ImportController.class ).getBundleContext (), reference );
}
};
public void setJobManager ( final JobManager jobManager )
{
this.jobManager = jobManager;
}
public void setService ( final ChannelService service )
{
this.service = service;
}
public void start ()
{
final BundleContext context = FrameworkUtil.getBundle ( ImportController.class ).getBundleContext ();
this.tracker = new ServiceTracker<> ( context, Importer.class, this.customizer );
this.tracker.open ();
this.impManager = new ImportManager ( context, this.jobManager );
}
public void stop ()
{
this.tracker.close ();
this.impManager.dispose ();
}
@RequestMapping ( value = "/channel/{channelId}/import" )
public ModelAndView index ( @PathVariable ( "channelId" ) final String channelId)
{
return Channels.withChannel ( this.service, channelId, ReadableChannel.class, channel -> {
final Map<String, Object> model = new HashMap<> ();
model.put ( "channel", channel.getInformation () );
model.put ( "descriptions", getDescriptions () );
final ImportDescriptor desc = new ImportDescriptor ();
desc.setChannelId ( channel.getId ().getId () );
desc.setType ( "channel" );
model.put ( "token", desc.toBase64 () );
return new ModelAndView ( "index", model );
} );
}
@RequestMapping ( value = "/import/perform", method = { RequestMethod.POST, RequestMethod.GET } )
public ModelAndView perform ( @RequestParameter ( "token" ) final String token, @RequestParameter ( "request" ) final ImportRequest request)
{
final Map<String, Object> model = new HashMap<> ();
final ImportDescriptor desc = ImportDescriptor.fromBase64 ( token );
final JobHandle job = this.impManager.perform ( desc, request );
model.put ( "job", job );
return new ModelAndView ( "perform", model );
}
@RequestMapping ( "/import/job/{id}/result" )
public ModelAndView viewResult ( @PathVariable ( "id" ) final String jobId)
{
final JobHandle job = this.jobManager.getJob ( jobId );
final Map<String, Object> model = new HashMap<> ();
model.put ( "job", job );
final ImporterResult result = new GsonBuilder ().create ().fromJson ( job.getResult (), ImporterResult.class );
model.put ( "result", result );
if ( result != null )
{
return Channels.withChannel ( this.service, result.getChannelId (), ReadableChannel.class, channel -> {
model.put ( "channel", channel.getInformation () );
return new ModelAndView ( "result", model );
} );
}
return new ModelAndView ( "result", model );
}
public ImporterDescription[] getDescriptions ()
{
final ImporterDescription[] result = this.tracker.getTracked ().values ().stream ().map ( Entry::getDescription ).toArray ( ImporterDescription[]::new );
Arrays.sort ( result, NAME_COMPARATOR );
return result;
}
@Override
public List<MenuEntry> getActions ( final HttpServletRequest request, final Object object )
{
if ( ! ( object instanceof ChannelInformation ) )
{
return null;
}
if ( !request.isUserInRole ( "MANAGER" ) )
{
return null;
}
final List<MenuEntry> result = new LinkedList<> ();
final ChannelInformation channel = (ChannelInformation)object;
final Map<String, String> model = new HashMap<> ( 1 );
model.put ( "channelId", channel.getId () );
result.add ( new MenuEntry ( "Import", 600, LinkTarget.createFromController ( ImportController.class, "index" ).expand ( model ), Modifier.DEFAULT, "import" ) );
return result;
}
}