package org.gcube.informationsystem.registry.impl; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.InputStreamReader; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.Method; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.List; import org.apache.axis.components.uuid.UUIDGen; import org.apache.axis.components.uuid.UUIDGenFactory; import org.gcube.common.core.contexts.GHNContext; import org.gcube.common.core.faults.GCUBEFault; import org.gcube.common.core.resources.GCUBEGenericResource; import org.gcube.common.core.resources.GCUBEHostingNode; import org.gcube.common.core.resources.GCUBEResource; import org.gcube.common.core.resources.impl.kxml.GCUBEResourceImpl; import org.gcube.common.core.scope.GCUBEScope; import org.gcube.common.core.state.GCUBEWSResourceKey; import org.gcube.common.core.utils.events.GCUBEEvent; import org.gcube.common.core.utils.logging.GCUBELog; import org.gcube.informationsystem.registry.impl.contexts.FactoryContext; import org.gcube.informationsystem.registry.impl.contexts.ProfileContext; import org.gcube.informationsystem.registry.impl.contexts.ServiceContext; import org.gcube.informationsystem.registry.impl.state.ProfileResource; import org.gcube.informationsystem.registry.impl.state.RegistryFactoryResource; import org.gcube.informationsystem.registry.impl.util.ProfileManager; import org.gcube.informationsystem.registry.impl.util.RegistryUtil; import org.gcube.informationsystem.registry.stubs.CreateResourceMessage; import org.gcube.informationsystem.registry.stubs.ProfileAlreadyRegisteredFault; import org.gcube.informationsystem.registry.stubs.RegistryProperty; import org.gcube.informationsystem.registry.stubs.RemoveResourceMessage; import org.gcube.informationsystem.registry.stubs.RemoveResourceResponse; import org.gcube.informationsystem.registry.stubs.RemoveScopeInProfileMessage; import org.gcube.informationsystem.registry.stubs.SchemaValidationFault; import org.gcube.informationsystem.registry.stubs.StartRegistration; import org.gcube.informationsystem.registry.stubs.StartRegistrationResponse; import org.gcube.informationsystem.registry.stubs.UpdateResourceMessage; import org.gcube.informationsystem.registry.stubs.UpdateResourceResponse; import org.gcube.informationsystem.registry.stubs.UpdateScopeInProfileMessage; import org.gcube.informationsystem.registry.stubs.UpdateStateMessage; import org.globus.wsrf.security.SecurityManager; import static org.gcube.informationsystem.registry.impl.core.RegistryConfiguration.ResourceType; /** * Implementation of the Registry Factory portType * * @author Andrea Manzi, Manuele Simi (ISTI-CNR) * */ public class RegistryFactory{ /** * The UUIDGen */ private static final UUIDGen uuidgen = UUIDGenFactory.getUUIDGen(); /** * Object logger. * */ protected final GCUBELog logger = new GCUBELog(RegistryFactory.class); /** * * */ enum OperationType {create,update,destroy}; /** * Map of registration to Notification */ public static List notificationMap = Collections.synchronizedList(new ArrayList()); /** the key used to label the Factory Resource */ public static final String NOTIFICATOR_RESOURCE_KEY = "RegistryResource"; /** * Use to Load from Disk persistence profiles and registers it into the IS-IC ( in case the IS-IC is empty) * * * @param start same as void * @return void * @throws RemoteException Exception */ public StartRegistrationResponse startRegistration(StartRegistration start ) throws GCUBEFault{ //start registration to broker and new profiles registration logger.debug("Starting profile registration from disk"); try { //loadProfiles(); } catch (Exception e) { logger.error("Error Loading profiles"); throw new GCUBEFault(e.getMessage()); } return new StartRegistrationResponse(); } /** * * Creates a new GCUBEResource's profile manager * * @param inputMessage * @return the profile as string * @throws SchemaValidationFault * @throws RemoteException * @throws ProfileAlreadyRegisteredFault */ public String createResource(CreateResourceMessage mess) throws SchemaValidationFault,RemoteException,ProfileAlreadyRegisteredFault { GCUBEResource resource; try { resource = GHNContext.getImplementation(GCUBEResource.class); }catch(Exception e) {throw new RemoteException("Error in GHNContext");} logger.info("CreateResource operation invoked"); logSecurityInfo("createResource"); String profile = mess.getProfile(); if (profile == null || profile.compareTo("") == 0) { String msg = "Profile file empty"; logger.debug(msg); throw new RemoteException(msg); } System.out.println("profile:" +profile); try { ResourceType.valueOf(mess.getType()).getResourceClass().getClass().cast(resource); resource.load(new BufferedReader(new InputStreamReader(new ByteArrayInputStream(profile.getBytes("UTF-8")), "UTF-8"))); if (mess.getType().compareTo(GCUBEGenericResource.TYPE)==0){ System.out.println(((GCUBEGenericResource) resource).getBody()); } //the parse Profile class allows to extract from profiles information about type/SCOPE/UniqueID //in order to distinguish among different Resource Type //Adding scopes to Profile String [] scopes = mess.getScopes(); if (scopes != null) { for (String scope : scopes) { logger.debug("Adding Scopes to Profile "+ scope); resource.addScope(GCUBEScope.getScope(scope)); } } //check ID if (resource.getID()== null || resource.getID().compareTo("")==0) {resource.setID(uuidgen.nextUUID()); } } catch (Exception ex) { logger.error("Error trying to load profile", ex); throw new SchemaValidationFault(); } //check if the Resource already exists if (isResourceCreated(resource.getID())) { // update the existing resource logger.warn("A Resource with ID "+ resource.getID()+" is already registered"); UpdateResourceMessage upmess = new UpdateResourceMessage(); upmess.setUniqueID(resource.getID()); upmess.setXmlProfile(mess.getProfile()); upmess.setType(mess.getType()); this.updateResource(upmess); //throw new ProfileAlreadyRegisteredFault(); } else { //try to create resource try { logger.debug("Creating the stateful resource for " + resource.getID()); ProfileResource presource = (ProfileResource) ProfileContext.getContext().getWSHome().create(ProfileContext.getContext().makeKey(resource.getID()),resource); presource.getPersistenceDelegate().store(presource); } catch (Exception ex) { String msg = "Error creating Resource"; logger.error(msg,ex); throw new RemoteException(msg); } try { GCUBEEvent event = new GCUBEEvent(); event.setPayload(resource); ServiceContext.getContext().getTopicProducer().notify(ServiceContext.RegistryTopic.CREATE, event); updateCounterInfo (resource.getID(), ResourceType.valueOf(mess.getType()), OperationType.create, Calendar.getInstance()); } catch (Exception e) { logger.warn("Error updating Counting info for resource with ID " + resource.getID(), e); } } StringWriter writer = new StringWriter(); try { logger.debug("Persisting the stateful resource for " + resource.getID()); resource.store(writer); } catch (Exception e) { logger.error("Persistence failed for " + resource.getID(), e); } logger.info("Profile " + resource.getID() + " created "); return writer.toString(); } /** * Updates Resource Profiles (in case of an update of an ID not present it invokes calls the Create resource operation) * * @param mess Complex Object that contains a String representing the XML profile to update and the diligentID * @return UpdateResourceResponse * @throws RemoteException Exception * @throws SchemaValidationException Exception */ @SuppressWarnings("unchecked") public UpdateResourceResponse updateResource(UpdateResourceMessage mess) throws RemoteException,SchemaValidationFault,GCUBEFault { logSecurityInfo("updateResource"); logger.info("UpdateResource operation invoked"); String ID = mess.getUniqueID(); String xmlProfile = mess.getXmlProfile(); GCUBEResource resource = null; CreateResourceMessage input =null; //validating input parameters if (ID == null || ID.compareTo("") ==0) { logger.debug(" ID missing "); throw new RemoteException("Error, ID missing"); } if (xmlProfile == null || xmlProfile.compareTo("") ==0) { logger.debug("Profile missing" ); throw new RemoteException("Error, profile missing"); } //check if the profile exist if (!isResourceCreated(ID)) { input = new CreateResourceMessage(); input.setProfile(xmlProfile); input.setType(mess.getType()); this.createResource(input); return new UpdateResourceResponse(); } try { resource = ResourceType.valueOf(mess.getType()).getResourceClass(); resource.load(new StringReader(xmlProfile)); getProfileResource(ID).updateResource(resource); } catch (Exception e) { logger.error("Error updating profile for ID "+ e); throw new RemoteException(e.toString()); } try { updateCounterInfo (ID,ResourceType.valueOf(mess.getType()),OperationType.update, Calendar.getInstance()); GCUBEEvent event = new GCUBEEvent(); event.setPayload(resource); ServiceContext.getContext().getTopicProducer().notify(ServiceContext.RegistryTopic.UPDATE, event); } catch (Exception e) { logger.warn("Error updating counting info for resource with ID " + resource.getID(), e); } logger.info("Profile " + mess.getUniqueID() + " updated"); return new UpdateResourceResponse(); } /** * Removes a Resource profile identified by the given the resource ID * * * @param inputMessage Defined into WSDL file * @return RemoveResourceResponse * @throws RemoteException Exceptions */ public RemoveResourceResponse removeResource (RemoveResourceMessage inputMessage) throws RemoteException,GCUBEFault{ logSecurityInfo("removeResource"); logger.info("RemoveResource operation invoked"); String ID = inputMessage.getUniqueID(); String type = inputMessage.getType(); if (ID == null || ID.compareTo("") ==0) { logger.warn("Resource ID is missing"); throw new RemoteException("Resource ID is missing"); } //check if the UniqueID exist /*GCUBEResource resource = null; try { resource = RegistryUtil.getProfileFromIS(ID,this.getResourceClass(type).getClass()); } catch (Exception e1) { logger.error("Error gettign profile from IS "); return new RemoveResourceResponse(); }*/ //if( resource == null) return new RemoveResourceResponse(); //else { logger.debug("trying to remove the resource from the IS-IC"); try { new ProfileManager().removeFromISIC(ID, type, ServiceContext.getContext().getCredentials()); logger.debug("resource removed"); } catch (Exception e) { logger.error("Unable to remove the resource", e); throw ServiceContext.getContext().getDefaultException("", e).toFault("Unable to remove the resource: the remote IS-IC returns an error"); } //} try { if (type.compareTo(GCUBEHostingNode.TYPE) == 0) RegistryUtil.unregisterRIRelatedToGHN(ID,this); } catch (Exception e) { logger.error("Error removing profile related to this GHNID for ID ", e); } if (this.isResourceCreated(ID)){ //destroy the resource try{ ProfileContext.getContext().getWSHome().remove(ProfileContext.getContext().makeKey(ID)); logger.info(" Resource Destroyed"); } catch (Exception e) { logger.error("Error removing resource for ID ", e); throw new RemoteException(); } try { GCUBEEvent event = new GCUBEEvent(); GCUBEResource resource =GHNContext.getImplementation(GCUBEResource.class); resource.setID(ID); event.setPayload(resource); ServiceContext.getContext().getTopicProducer().notify(ServiceContext.RegistryTopic.REMOVE, event); updateCounterInfo(ID, ResourceType.valueOf(type), OperationType.destroy, Calendar.getInstance()); } catch (Exception e) { logger.warn("Error updating counting info for resource with ID " + ID ,e); } } return new RemoveResourceResponse(); } /** * Log Security info * * @param methodName The Method Name */ private void logSecurityInfo(String methodName) { logger.info("Security info for method "+ methodName ); String identity = SecurityManager.getManager().getCaller(); logger.info("The caller is: " + identity); } /** * Checks if the Resource has been created * * @param id the Resource ID * @return the resource ( null if the resource has not been created yet */ protected synchronized ProfileResource getProfileResource(String id ){ try { return (ProfileResource) ProfileContext.getContext().getWSHome().find(ProfileContext.getContext().makeKey(id)); } catch (Exception e ){ logger.debug("A profile with the given id "+ id+" has not been created yet"); } return null; } /** * * @param id * @return */ protected synchronized boolean isResourceCreated(String id) { if (getProfileResource(id) != null) return true; else return false; } /** * Updates the RegistryFactoryResource RPs for notification * * * @param ID resource ID * @param type the resource type * @param operationType the type of Operation performed on the Profile * @param updateTime The last operation Time * @throws Exception Exception */ @SuppressWarnings("unchecked") private synchronized void updateCounterInfo(String ID, ResourceType resType, OperationType opType, Calendar updateTime) throws Exception{ RegistryProperty property = new RegistryProperty(); property.setUniqueID(ID); property.setOperationType(opType.name()); property.setChangeTime(updateTime); //select the type of the resource to update for (Method method :this.getResource().getClass().getDeclaredMethods()) { if (method.getName().contains(resType.name()) && method.getName().contains("set")) { method.invoke(this.getResource(),property); break; } } this.getResource().getPersistenceDelegate().store(this.getResource()); } /** * return the resource * * @return NotifierResource * @throws RemoteException Exception */ private RegistryFactoryResource getResource() throws RemoteException { Object resource = null; try { resource = FactoryContext.getContext().getWSHome().find(FactoryContext.getContext().makeKey(NOTIFICATOR_RESOURCE_KEY)); } catch (Exception e) { logger.error(" Unable to access resource", e); } RegistryFactoryResource factoryResource = (RegistryFactoryResource) resource; return factoryResource; } public String updateScopeInProfile(UpdateScopeInProfileMessage message)throws GCUBEFault{return null;} public String removeScopeInProfile(RemoveScopeInProfileMessage message)throws GCUBEFault{return null;} public String updateState(UpdateStateMessage message)throws GCUBEFault{return null;} }