package com.limegroup.gnutella.xml;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.limewire.i18n.I18nMarker;
import org.limewire.inject.EagerSingleton;
import org.limewire.lifecycle.Service;
import org.limewire.lifecycle.ServiceRegistry;
import org.limewire.listener.EventListener;
import org.limewire.listener.ListenerSupport;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.limegroup.gnutella.library.FileDesc;
import com.limegroup.gnutella.library.FileDescChangeEvent;
import com.limegroup.gnutella.library.FileViewChangeEvent;
import com.limegroup.gnutella.library.Library;
import com.limegroup.gnutella.library.LibraryStatusEvent;
/**
* Used to map schema URIs to Reply Collections.
*
* @author Sumeet Thadani
*/
@EagerSingleton
public class SchemaReplyCollectionMapper implements XmlController {
private final Map<String, LimeXMLReplyCollection> mapper;
protected final LimeXMLReplyCollectionFactory limeXMLReplyCollectionFactory;
protected final Provider<LimeXMLSchemaRepository> limeXMLSchemaRepository;
@Inject SchemaReplyCollectionMapper(LimeXMLReplyCollectionFactory limeXMLReplyCollectionFactory,
Provider<LimeXMLSchemaRepository> limeXMLSchemaRepository) {
this.limeXMLReplyCollectionFactory = limeXMLReplyCollectionFactory;
this.limeXMLSchemaRepository = limeXMLSchemaRepository;
mapper = new ConcurrentHashMap<String, LimeXMLReplyCollection>();
}
/**
* Adds the SchemaURI to a HashMap with the replyCollection.
* <p>
* Warning/Note:If the schemaURI already corresponds to a ReplyCollection
* this method will replace the old reply collection with the new one.
* The old collection will be lost!
*/
public void add(String schemaURI, LimeXMLReplyCollection replyCollection) {
mapper.put(schemaURI, replyCollection);
}
/**
* Looks up and returns the <tt>LimeXMLReplyCollection</tt> value for the
* supplied schemaURI key.
*
* @ return the <tt>LimeXMLReplyCollection</tt> for the given schema URI,
* or <tt>null</tt> if we the requested mapping does not exist
*/
public LimeXMLReplyCollection getReplyCollection(String schemaURI) {
return mapper.get(schemaURI);
}
/**
* Returns a collection of all available LimeXMLReplyCollections.
*/
public Collection<LimeXMLReplyCollection> getCollections() {
return mapper.values();
}
@Inject void register(ServiceRegistry registry, final Library managedList,
final ListenerSupport<FileDescChangeEvent> fileDescSupport) {
registry.register(new Service() {
@Override
public String getServiceName() {
return I18nMarker.marktr("Metadata Loader");
}
@Override
public void initialize() {
loadSchemas();
managedList.addListener(new EventListener<FileViewChangeEvent>() {
@Override
public void handleEvent(FileViewChangeEvent event) {
switch(event.getType()) {
case FILE_REMOVED:
removeFileDesc(event.getFileDesc());
break;
case FILE_CHANGED:
removeFileDesc(event.getOldValue());
break;
case FILES_CLEARED:
loadSchemas();
break;
}
}
});
managedList.addManagedListStatusListener(new EventListener<LibraryStatusEvent>() {
@Override
public void handleEvent(LibraryStatusEvent event) {
switch (event.getType()) {
case LOAD_FINISHING:
finishLoading();
break;
case SAVE:
save(event);
break;
}
}
});
}
@Override
public void start() {
// TODO Auto-generated method stub
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
});
}
private void removeFileDesc(FileDesc fd) {
// Get the schema URI of each document and remove from the collection
// We must remember the schemas and then remove the doc, or we will
// get a concurrent mod exception because removing the doc also
// removes it from the FileDesc.
List<LimeXMLDocument> xmlDocs = fd.getLimeXMLDocuments();
List<String> schemas = new LinkedList<String>();
for (LimeXMLDocument doc : xmlDocs)
schemas.add(doc.getSchemaURI());
for (String uri : schemas) {
LimeXMLReplyCollection col = getReplyCollection(uri);
if (col != null)
col.removeDoc(fd);
}
}
/**
* Notifies all the LimeXMLReplyCollections that the initial loading
* has completed.
*/
private void finishLoading() {
Collection<LimeXMLReplyCollection> replies = getCollections();
for (LimeXMLReplyCollection col : replies)
col.loadFinished();
}
/**
* Serializes the current LimeXMLReplyCollection to disk.
*/
private void save(LibraryStatusEvent event) {
if (event.getLibrary().isLoadFinished()) {
Collection<LimeXMLReplyCollection> replies = getCollections();
for (LimeXMLReplyCollection col : replies)
col.writeMapToDisk();
}
}
@Override
public boolean canConstructXml(FileDesc fd) {
Collection<LimeXMLReplyCollection> replies = getCollections();
for (LimeXMLReplyCollection col : replies) {
if(col.canCreateDocument(fd.getFile())) {
return true;
}
}
return false;
}
@Override
public boolean loadCachedXml(FileDesc fd, Collection<? extends LimeXMLDocument> prebuilt) {
Collection<LimeXMLReplyCollection> replies = getCollections();
boolean loaded = false;
for (LimeXMLReplyCollection col : replies) {
LimeXMLDocument doc = col.initialize(fd, prebuilt);
if(doc != null) {
loaded = true;
}
}
return loaded;
}
/**
* Loads the map with the LimeXMLDocument for a given FileDesc. If no LimeXMLDocument
* exists for the FileDesc, one is created for it.
*/
@Override
public boolean loadXml(FileDesc fd) {
Collection<LimeXMLReplyCollection> replies = getCollections();
boolean loaded = false;
for (LimeXMLReplyCollection col : replies) {
LimeXMLDocument doc = col.createIfNecessary(fd);
if(doc != null) {
loaded = true;
}
}
return loaded;
}
/**
* Loads all the SchemaURI to a HashMap with the replyCollection.
*/
private void loadSchemas() {
String[] schemas = limeXMLSchemaRepository.get().getAvailableSchemaURIs();
for(String schema : schemas) {
add(schema, limeXMLReplyCollectionFactory.createLimeXMLReplyCollection(schema));
}
}
}