package uk.ac.ebi.fg.myequivalents.webservices.client;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import uk.ac.ebi.fg.myequivalents.managers.interfaces.EntityMappingManager;
import uk.ac.ebi.fg.myequivalents.managers.interfaces.EntityMappingSearchResult;
import uk.ac.ebi.fg.myequivalents.managers.interfaces.EntityMappingSearchResult.Bundle;
import uk.ac.ebi.fg.myequivalents.model.Entity;
import uk.ac.ebi.fg.myequivalents.model.EntityMapping;
import uk.ac.ebi.fg.myequivalents.model.Repository;
import uk.ac.ebi.fg.myequivalents.model.Service;
import uk.ac.ebi.fg.myequivalents.model.ServiceCollection;
import uk.ac.ebi.fg.myequivalents.utils.jaxb.JAXBUtils;
import uk.ac.ebi.utils.io.IOUtils;
import com.sun.jersey.api.representation.Form;
/**
* The web service client implementation of {@link EntityMappingManager}.
*
* <dl><dt>date</dt><dd>Oct 1, 2012</dd></dl>
* @author Marco Brandizi
*
*/
public class EntityMappingWSClient extends MyEquivalentsWSClient implements EntityMappingManager
{
public EntityMappingWSClient ()
{
super ();
}
public EntityMappingWSClient ( String baseUrl )
{
super ( baseUrl );
}
@Override
protected String getServicePath () {
return "/mapping";
}
@Override
public void storeMappings ( String ... entityIds )
{
Form req = prepareReq ();
for ( String eid: entityIds ) req.add ( "entity", eid );
invokeVoidWsReq ( "/store", req );
}
@Override
public void storeMappingBundle ( String ... entityIds )
{
Form req = prepareReq ();
for ( String eid: entityIds ) req.add ( "entity", eid );
invokeVoidWsReq ( "/bundle/store", req );
}
@Override
public void storeMappingBundles ( EntityMappingSearchResult mappings )
{
storeMappingBundlesFromXML (
new StringReader ( JAXBUtils.marshal ( mappings, EntityMappingSearchResult.class ) )
);
}
@Override
public void storeMappingBundlesFromXML ( Reader reader )
{
try
{
String mappingsXml = IOUtils.readInputFully ( reader );
Form req = prepareReq ();
req.add ( "mappings-xml", mappingsXml );
invokeVoidWsReq ( "/bundles/store", req );
}
catch ( IOException ex )
{
throw new RuntimeException (
"Error while invoking the myEq web service for 'bundles/store': " + ex.getMessage (), ex
);
}
}
@Override
public int deleteMappings ( String ... entityIds )
{
Form req = prepareReq ();
for ( String eid: entityIds ) req.add ( "entity", eid );
return invokeIntWsReq ( "/delete", req );
}
@Override
public int deleteEntities ( String ... entityIds )
{
Form req = prepareReq ();
for ( String eid: entityIds ) req.add ( "entity", eid );
return invokeIntWsReq ( "/entity/delete", req );
}
@Override
public EntityMappingSearchResult getMappings ( Boolean wantRawResult, String ... entityIds )
{
Form req = prepareReq ();
req.add ( "raw", wantRawResult.toString () );
for ( String eid: entityIds ) req.add ( "entity", eid );
return invokeMappingGetWsReq ( "/get", req );
}
@Override
public EntityMappingSearchResult getMappingsForTarget ( Boolean wantRawResult, String targetServiceName, String entityId )
{
Form req = prepareReq ();
req.add ( "raw", wantRawResult.toString () );
req.add ( "service", targetServiceName );
req.add ( "entity", entityId );
return invokeMappingGetWsReq ( "/target/get", req );
}
@Override
public String getMappingsAs ( String outputFormat, Boolean wantRawResult, String ... entityIds )
{
Form req = prepareReq ();
req.add ( "raw", wantRawResult.toString () );
for ( String eid: entityIds ) req.add ( "entity", eid );
return getRawResult ( "/get", req, outputFormat );
}
@Override
public String getMappingsForTargetAs ( String outputFormat, Boolean wantRawResult, String targetServiceName, String entityId )
{
Form req = prepareReq ();
req.add ( "raw", wantRawResult.toString () );
req.add ( "service", targetServiceName );
req.add ( "entity", entityId );
return getRawResult ( "/target/get", req, outputFormat );
}
private EntityMappingSearchResult invokeMappingGetWsReq ( String reqPath, Form req )
{
return rebuildEntityMappingLinks ( invokeWsReq ( reqPath, req, EntityMappingSearchResult.class ) );
}
/**
* This rebuilds links like the one between {@link Entity} and {@link Service}, by looking at objects in the
* flat XML that is returned by the web service.
*
* This will also reconstruct {@link Bundle bundles} in emsr, using fictitious identifiers, which replace the ones
* actually stored on the server storage back end. This shouldn't be a problem, since the clients should consider
* these IDs opaque and volatile.
*
*/
private EntityMappingSearchResult rebuildEntityMappingLinks ( EntityMappingSearchResult emsr )
{
if ( emsr == null ) return null;
// Do you have more than one mapping?
Set<Service> orgServs = emsr.getServices ();
if ( orgServs == null ) return emsr;
// OK, first let's index that
Map<String, Service> servs = new HashMap<String, Service> ();
for ( Service s: orgServs ) servs.put ( s.getName (), s );
Map<String, Repository> repos = new HashMap<String, Repository> ();
for ( Repository repo: emsr.getRepositories () ) repos.put ( repo.getName (), repo );
Map<String, ServiceCollection> scs = new HashMap<String, ServiceCollection> ();
for ( ServiceCollection sc: emsr.getServiceCollections () ) scs.put ( sc.getName (), sc );
// Do you *really* have something?
if ( servs.isEmpty () && repos.isEmpty () && scs.isEmpty () ) return emsr;
// If yes, let's rebuild entity mappings with proper links
List<EntityMapping> newEms = new LinkedList<EntityMapping> ();
int bid = 0; // It's OK to have fictitious bundlle IDs, you're not supposed to mess up with these anyway
for ( Bundle b: emsr.getBundles () )
{
String bidStr = Integer.toString ( bid++ );
for ( Entity e : b.getEntities () )
{
// Try with either the service or its name reference
Service s = e.getService ();
if ( s == null ) s = servs.get ( e.getServiceName () );
// Create the new entity mapping and clone from the old one.
EntityMapping newEm = new EntityMapping ( s, e.getAccession (), bidStr );
newEm.setPublicFlag ( e.getPublicFlag () );
newEm.setReleaseDate ( e.getReleaseDate () );
newEms.add ( newEm );
}
}
// Rebuild the service->repository relationship
for ( Service s: orgServs )
{
String rname = s.getRepositoryName ();
if ( rname != null ) s.setRepository ( repos.get ( rname ) );
String scname = s.getServiceCollectionName ();
if ( scname != null ) s.setServiceCollection ( scs.get ( scname ) );
}
// Whoaa! Last bit and return
EntityMappingSearchResult result = new EntityMappingSearchResult ( false );
result.addAllEntityMappings ( newEms );
return result;
}
}