diff --git a/edexOsgi/com.raytheon.uf.common.registry.ebxml/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.registry.ebxml/META-INF/MANIFEST.MF index 05dd4b7887..c0d17b0e39 100644 --- a/edexOsgi/com.raytheon.uf.common.registry.ebxml/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.registry.ebxml/META-INF/MANIFEST.MF @@ -13,7 +13,8 @@ Export-Package: com.raytheon.uf.common.registry, com.raytheon.uf.common.registry.ebxml.slots, com.raytheon.uf.common.registry.handler, com.raytheon.uf.common.registry.services, - com.raytheon.uf.common.registry.services.rest + com.raytheon.uf.common.registry.services.rest, + com.raytheon.uf.common.registry.services.rest.response Require-Bundle: org.apache.commons.codec;bundle-version="1.4.0", com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174", com.raytheon.uf.common.util;bundle-version="1.12.1174", diff --git a/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/RegistryRESTServices.java b/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/RegistryRESTServices.java index 9988e3eaf4..bc7740c60e 100644 --- a/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/RegistryRESTServices.java +++ b/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/RegistryRESTServices.java @@ -33,6 +33,7 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.raytheon.uf.common.registry.constants.RegistryAvailability; import com.raytheon.uf.common.registry.services.rest.IRegistryAvailableRestService; +import com.raytheon.uf.common.registry.services.rest.IRegistryDataAccessService; import com.raytheon.uf.common.registry.services.rest.IRegistryObjectsRestService; import com.raytheon.uf.common.registry.services.rest.IRepositoryItemsRestService; import com.raytheon.uf.common.serialization.SerializationUtil; @@ -50,6 +51,7 @@ import com.raytheon.uf.common.status.UFStatus; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 5/21/2013 2022 bphillip Initial implementation + * 7/29/2013 2191 bphillip Implemented registry data access service * * * @author bphillip @@ -87,6 +89,16 @@ public class RegistryRESTServices { } }); + /** Map of known registry data access services */ + private static LoadingCache registryDataAccessServiceMap = CacheBuilder + .newBuilder().expireAfterAccess(1, TimeUnit.HOURS) + .build(new CacheLoader() { + public IRegistryDataAccessService load(String key) { + return JAXRSClientFactory.create(key, + IRegistryDataAccessService.class); + } + }); + /** * The logger */ @@ -99,11 +111,9 @@ public class RegistryRESTServices { * @param baseURL * The base URL of the registry * @return The service implementation - * @throws RegistryServiceException - * If an invalid URL is provided */ public static IRegistryObjectsRestService getRegistryObjectService( - String baseURL) throws RegistryServiceException { + String baseURL) { try { return registryObjectServiceMap.get(baseURL); } catch (ExecutionException e) { @@ -124,8 +134,6 @@ public class RegistryRESTServices { * @return The object * @throws JAXBException * If errors occur while serializing the object - * @throws RegistryServiceException - * If an invalid URL is provided */ public static T getRegistryObject( Class expectedType, String baseURL, String objectId) @@ -140,11 +148,9 @@ public class RegistryRESTServices { * @param baseURL * The base URL of the registry * @return The service implementation - * @throws RegistryServiceException - * If an invalid URL is provided */ public static IRepositoryItemsRestService getRepositoryItemService( - String baseURL) throws RegistryServiceException { + String baseURL) { try { return repositoryItemServiceMap.get(baseURL); } catch (ExecutionException e) { @@ -161,11 +167,9 @@ public class RegistryRESTServices { * @param repositoryItemId * The id of the object * @return The repository item - * @throws RegistryServiceException - * If an invalid URL is provided */ public static byte[] getRepositoryItem(String baseURL, - String repositoryItemId) throws RegistryServiceException { + String repositoryItemId) { return getRepositoryItemService(baseURL).getRepositoryItem( repositoryItemId); } @@ -176,11 +180,9 @@ public class RegistryRESTServices { * @param baseURL * The base URL of the registry * @return THe registry available service implementation - * @throws RegistryServiceException - * If an invalid URL is provided */ public static IRegistryAvailableRestService getRegistryAvailableService( - String baseURL) throws RegistryServiceException { + String baseURL) { try { return registryAvailabilityServiceMap.get(baseURL); } catch (ExecutionException e) { @@ -204,8 +206,25 @@ public class RegistryRESTServices { } catch (Throwable t) { statusHandler.error( "Registry at [" + baseURL + "] not available: ", - t.getLocalizedMessage()); + t.getMessage()); return false; } } + + /** + * Gets the data access service for the specified registry URL + * + * @param baseURL + * The baseURL of the registry + * @return The data access service for the specified registry URL + */ + public static IRegistryDataAccessService getRegistryDataAccessService( + String baseURL) { + try { + return registryDataAccessServiceMap.get(baseURL); + } catch (ExecutionException e) { + throw new RegistryServiceException( + "Error getting Registry Availability Rest Service", e); + } + } } diff --git a/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/rest/IRegistryDataAccessService.java b/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/rest/IRegistryDataAccessService.java new file mode 100644 index 0000000000..f09ec837b9 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/rest/IRegistryDataAccessService.java @@ -0,0 +1,71 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.registry.services.rest; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +import com.raytheon.uf.common.registry.RegistryException; +import com.raytheon.uf.common.registry.services.rest.response.RestCollectionResponse; + +/** + * + * REST service interface for various registry data access methods + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * 7/29/2013    2191        bphillip    Initial implementation
+ * 
+ * + * @author bphillip + * @version 1 + */ +public interface IRegistryDataAccessService { + + /** + * Gets the ids of registry objects of the given object type + * + * @param objectType + * The object type to get ids for + * @return List of ids for registry objects of the given type + */ + @GET + @Path("/rest/dataAccess/getRegistryObjectIds/{objectType}") + public RestCollectionResponse getRegistryObjectIdsOfType( + @PathParam("objectType") String objectType); + + /** + * Removes any subscriptions for the given site + * + * @param siteId + * The site to remove the subscriptions for + * @throws RegistryException + * If errors occur while removing the subscriptions + */ + @GET + @Path("/rest/dataAccess/removeSubscriptionsFor/{siteId}") + public void removeSubscriptionsForSite(@PathParam("siteId") String siteId) + throws RegistryException; +} diff --git a/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/rest/response/IRestResponse.java b/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/rest/response/IRestResponse.java new file mode 100644 index 0000000000..af9b529549 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/rest/response/IRestResponse.java @@ -0,0 +1,50 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.registry.services.rest.response; + +import javax.xml.bind.annotation.XmlRootElement; + +import com.raytheon.uf.common.serialization.ISerializableObject; + +/** + * + * A response from a registry REST service call + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * 7/29/2013    2191        bphillip    Initial implementation
+ * 
+ * + * @author bphillip + * @version 1 + */ +@XmlRootElement +public interface IRestResponse extends + ISerializableObject { + + public OBJECT_TYPE getPayload(); + + public void setPayload(OBJECT_TYPE payload); + +} diff --git a/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/rest/response/RestCollectionResponse.java b/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/rest/response/RestCollectionResponse.java new file mode 100644 index 0000000000..a9ee40ff36 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.registry.ebxml/src/com/raytheon/uf/common/registry/services/rest/response/RestCollectionResponse.java @@ -0,0 +1,67 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.registry.services.rest.response; + +import java.util.Collection; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlTransient; + +/** + * + * Response object for returning a collection from a REST service + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * 7/29/2013    2191        bphillip    Initial implementation
+ * 
+ * + * @author bphillip + * @version 1 + */ +@XmlRootElement +public class RestCollectionResponse implements + IRestResponse> { + + @XmlElements({ @XmlElement(name = "item") }) + private Collection set; + + public RestCollectionResponse() { + + } + + @Override + @XmlTransient + public Collection getPayload() { + return set; + } + + @Override + public void setPayload(Collection payload) { + this.set = payload; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/com/raytheon/uf/common/registry/schemas/ebxml/util/XMLGregorianCalendarType.java b/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/com/raytheon/uf/common/registry/schemas/ebxml/util/XMLGregorianCalendarType.java index bd5a529f14..781f19e983 100644 --- a/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/com/raytheon/uf/common/registry/schemas/ebxml/util/XMLGregorianCalendarType.java +++ b/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/com/raytheon/uf/common/registry/schemas/ebxml/util/XMLGregorianCalendarType.java @@ -46,6 +46,7 @@ import org.hibernate.usertype.UserType; * ------------ ---------- ----------- -------------------------- * Feb 21, 2012 #184 bphillip Initial creation * 4/9/2013 1802 bphillip Added null check + * 7/29/2013 2191 bphillip Fixed equals method * * * @@ -77,7 +78,11 @@ public class XMLGregorianCalendarType implements UserType { public boolean equals(Object x, Object y) throws HibernateException { if (x instanceof XMLGregorianCalendar && y instanceof XMLGregorianCalendar) { - return x.equals(y); + try { + return x.equals(y); + } catch (ClassCastException e) { + return y.equals(x); + } } else { return false; } diff --git a/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/RunnableWithTransaction.java b/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/RunnableWithTransaction.java new file mode 100644 index 0000000000..1d6955d3f3 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/RunnableWithTransaction.java @@ -0,0 +1,84 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.database; + +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * + * Implementation of a runnable who's run method is encapsulated in a Hibernate + * transaction. This class is used for executing asynchronous actions that + * require a Hibernate transaction. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * 7/29/2013    2191        bphillip    Initial implementation
+ * 
+ * + * @author bphillip + * @version 1 + */ +public abstract class RunnableWithTransaction implements Runnable { + + /** The Hibernate transaction template used to get a transaction */ + private TransactionTemplate txTemplate; + + /** + * Creates a new RunnableWithTransaction object + */ + public RunnableWithTransaction() { + + } + + /** + * Creates a new RunnableWithTransaction object + * + * @param txTemplate + * The transaction template to use + */ + public RunnableWithTransaction(TransactionTemplate txTemplate) { + this.txTemplate = txTemplate; + } + + public void run() { + txTemplate.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus status) { + runWithTransaction(); + } + }); + } + + /** + * This method is executed transactionally + */ + public abstract void runWithTransaction(); + + public void setTxTemplate(TransactionTemplate txTemplate) { + this.txTemplate = txTemplate; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/META-INF/MANIFEST.MF index dc192a47bc..d0af5e773b 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/META-INF/MANIFEST.MF @@ -16,4 +16,5 @@ Require-Bundle: com.raytheon.uf.common.registry.schemas.ebxml;bundle-version="1. com.raytheon.uf.common.dataplugin;bundle-version="1.12.1174", org.springframework;bundle-version="2.5.6", com.raytheon.uf.common.time;bundle-version="1.12.1174", - com.raytheon.uf.edex.core;bundle-version="1.12.1174" + com.raytheon.uf.edex.core;bundle-version="1.12.1174", + com.google.guava;bundle-version="1.0.0" diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/res/spring/registry-replication-datadelivery.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/res/spring/registry-replication-datadelivery.xml index b495f6f915..9a65b71ce4 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/res/spring/registry-replication-datadelivery.xml +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/res/spring/registry-replication-datadelivery.xml @@ -3,9 +3,17 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> + + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/availability/FederatedRegistryMonitor.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/availability/FederatedRegistryMonitor.java new file mode 100644 index 0000000000..174a52cd40 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/availability/FederatedRegistryMonitor.java @@ -0,0 +1,130 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.datadelivery.registry.availability; + +import java.util.Calendar; + +import oasis.names.tc.ebxml.regrep.xsd.rim.v4.DateTimeValueType; +import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectType; +import oasis.names.tc.ebxml.regrep.xsd.rim.v4.SlotType; +import oasis.names.tc.ebxml.regrep.xsd.rim.v4.VersionInfoType; + +import org.springframework.transaction.support.TransactionTemplate; + +import com.raytheon.uf.common.registry.constants.StatusTypes; +import com.raytheon.uf.common.registry.ebxml.RegistryUtil; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.edex.database.RunnableWithTransaction; +import com.raytheon.uf.edex.registry.ebxml.dao.RegistryObjectDao; +import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; +import com.raytheon.uf.edex.registry.ebxml.util.EbxmlObjectUtil; + +/** + * + * Periodically writes a record to the database as long as this registry is + * connected to the federation. This class is primarily used to determine if, + * upon startup, this registry must synchronize with the federation to get the + * state of the registry up to date + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * 7/29/2013    2191        bphillip    Initial implementation
+ * 
+ * + * @author bphillip + * @version 1 + */ +public class FederatedRegistryMonitor extends RunnableWithTransaction { + + /** The logger instance */ + private static final IUFStatusHandler statusHandler = UFStatus + .getHandler(FederatedRegistryMonitor.class); + + /** ID of the object to write to the registry */ + private static final String REGISTRY_AVAILABLE_ID = "RegistryAvailability"; + + /** Data access object for registry objects */ + private RegistryObjectDao registryObjectDao; + + public FederatedRegistryMonitor() { + super(); + } + + public FederatedRegistryMonitor(TransactionTemplate txTemplate, + RegistryObjectDao registryObjectDao) { + super(txTemplate); + this.registryObjectDao = registryObjectDao; + } + + public long getLastKnownUptime() { + RegistryObjectType regObj = registryObjectDao + .getById(REGISTRY_AVAILABLE_ID); + Calendar cal = null; + if (regObj == null) { + cal = TimeUtil.newCalendar(); + cal.setTimeInMillis(0); + } else { + DateTimeValueType value = (DateTimeValueType) regObj.getSlotByName( + REGISTRY_AVAILABLE_ID).getSlotValue(); + cal = value.getValue().toGregorianCalendar(); + } + return cal.getTimeInMillis(); + } + + @Override + public void runWithTransaction() { + try { + RegistryObjectType regObj = registryObjectDao + .getById(REGISTRY_AVAILABLE_ID); + if (regObj == null) { + statusHandler + .info("Availability object not found in registry. Creating new entry."); + SlotType slot = new SlotType(); + slot.setName(REGISTRY_AVAILABLE_ID); + DateTimeValueType value = new DateTimeValueType(); + value.setDateTimeValue(EbxmlObjectUtil + .getCurrentTimeAsXMLGregorianCalendar()); + slot.setSlotValue(value); + regObj = new RegistryObjectType(); + regObj.setId(REGISTRY_AVAILABLE_ID); + regObj.setLid(REGISTRY_AVAILABLE_ID); + regObj.setOwner(RegistryUtil.DEFAULT_OWNER); + regObj.setVersionInfo(new VersionInfoType()); + regObj.setStatus(StatusTypes.APPROVED); + regObj.getSlot().add(slot); + } else { + DateTimeValueType dateTime = (DateTimeValueType) regObj + .getSlotByName(REGISTRY_AVAILABLE_ID).getSlotValue(); + dateTime.setDateTimeValue(EbxmlObjectUtil + .getCurrentTimeAsXMLGregorianCalendar()); + } + + registryObjectDao.createOrUpdate(regObj); + } catch (EbxmlRegistryException e) { + statusHandler.error("Error updating federated time!", e); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/NcfRegistryFederationManager.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/NcfRegistryFederationManager.java index 83eb10df4b..70f7d2aece 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/NcfRegistryFederationManager.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/NcfRegistryFederationManager.java @@ -26,6 +26,7 @@ import java.util.List; import javax.xml.bind.JAXBException; import oasis.names.tc.ebxml.regrep.wsdl.registry.services.v4.LifecycleManager; +import oasis.names.tc.ebxml.regrep.wsdl.registry.services.v4.MsgRegistryException; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.AssociationType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.FederationType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.OrganizationType; @@ -38,6 +39,7 @@ import com.raytheon.uf.common.registry.constants.StatusTypes; import com.raytheon.uf.common.registry.ebxml.RegistryUtil; import com.raytheon.uf.common.serialization.SerializationException; import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; +import com.raytheon.uf.edex.registry.ebxml.init.RegistryInitializedListener; /** * @@ -50,12 +52,14 @@ import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 5/22/2013 1707 bphillip Initial implementation + * 7/29/2013 2191 bphillip Implemented registry sync for registries that have been down for an extended period of time * * * @author bphillip * @version 1 */ -public class NcfRegistryFederationManager extends RegistryFederationManager { +public class NcfRegistryFederationManager extends RegistryFederationManager + implements RegistryInitializedListener { /** * Creates a new NcfRegistryFederationManager @@ -103,7 +107,12 @@ public class NcfRegistryFederationManager extends RegistryFederationManager { objects.add(primaryContact); objects.add(federationAssociation); submitObjects(objects); - replicationManager.submitRemoteSubscriptions(registry.getBaseURL()); + replicationManager.submitRemoteSubscriptions(registry); + try { + replicationManager.checkDownTime(); + } catch (MsgRegistryException e) { + throw new EbxmlRegistryException("Error checkint down time!", e); + } } else { statusHandler.info("Federation is disabled for this registry."); } diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/RegistryFederationManager.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/RegistryFederationManager.java index c601727ea8..cde2bf66d9 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/RegistryFederationManager.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/RegistryFederationManager.java @@ -21,6 +21,7 @@ package com.raytheon.uf.edex.datadelivery.registry.federation; import java.io.File; import java.util.List; +import java.util.concurrent.ScheduledExecutorService; import javax.xml.bind.JAXBException; @@ -50,7 +51,6 @@ import com.raytheon.uf.edex.datadelivery.registry.replication.RegistryReplicatio import com.raytheon.uf.edex.registry.ebxml.dao.RegistryDao; import com.raytheon.uf.edex.registry.ebxml.dao.RegistryObjectDao; import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; -import com.raytheon.uf.edex.registry.ebxml.init.RegistryInitializedListener; /** * @@ -64,6 +64,7 @@ import com.raytheon.uf.edex.registry.ebxml.init.RegistryInitializedListener; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 5/22/2013 1707 bphillip Initial implementation + * 7/29/2013 2191 bphillip Implemented registry sync for registries that have been down for an extended period of time * * * @author bphillip @@ -71,13 +72,18 @@ import com.raytheon.uf.edex.registry.ebxml.init.RegistryInitializedListener; */ @Service @Transactional -public abstract class RegistryFederationManager implements - RegistryInitializedListener { +public abstract class RegistryFederationManager { /** The logger instance */ protected static final IUFStatusHandler statusHandler = UFStatus .getHandler(RegistryFederationManager.class); + /** + * The scheduler service used for registering this registry with the + * federation + */ + protected ScheduledExecutorService scheduler; + /** The federation identifier */ public static final String FEDERATION_ID = "Registry Federation"; @@ -174,6 +180,7 @@ public abstract class RegistryFederationManager implements + " Federation Membership Association"); association.setLid(association.getId()); association.setObjectType(RegistryObjectTypes.ASSOCIATION); + association.setOwner(federationProperties.getSiteIdentifier()); association.setType(AssociationTypes.HAS_FEDERATION_MEMBER); association.setStatus(StatusTypes.APPROVED); association.setName(RegistryUtil.getInternationalString(registry diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/WfoRegistryFederationManager.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/WfoRegistryFederationManager.java index fbc039bfbb..16845550ee 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/WfoRegistryFederationManager.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/federation/WfoRegistryFederationManager.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -44,9 +43,7 @@ import oasis.names.tc.ebxml.regrep.xsd.rim.v4.SlotType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.StringValueType; import org.springframework.stereotype.Service; -import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import com.raytheon.uf.common.registry.constants.CanonicalQueryTypes; @@ -56,7 +53,9 @@ import com.raytheon.uf.common.registry.constants.QueryReturnTypes; import com.raytheon.uf.common.registry.services.RegistryRESTServices; import com.raytheon.uf.common.registry.services.RegistrySOAPServices; import com.raytheon.uf.common.serialization.SerializationException; +import com.raytheon.uf.edex.database.RunnableWithTransaction; import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; +import com.raytheon.uf.edex.registry.ebxml.init.RegistryInitializedListener; /** * @@ -69,6 +68,7 @@ import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 5/22/2013 1707 bphillip Initial implementation + * 7/29/2013 2191 bphillip Implemented registry sync for registries that have been down for an extended period of time * * * @author bphillip @@ -76,17 +76,12 @@ import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; */ @Service @Transactional -public class WfoRegistryFederationManager extends RegistryFederationManager { +public class WfoRegistryFederationManager extends RegistryFederationManager + implements RegistryInitializedListener { /** The address of the NCF */ private String ncfAddress; - /** - * The scheduler service used for registering this registry with the - * federation - */ - private ScheduledExecutorService scheduler; - /** The transaction template used to manually handle transactions */ private TransactionTemplate txTemplate; @@ -173,7 +168,7 @@ public class WfoRegistryFederationManager extends RegistryFederationManager { objects.add(federationAssociation); submitObjects(objects); replicationManager.setSubscriptionProcessingEnabled(true); - replicationManager.submitRemoteSubscriptions(registry.getBaseURL()); + replicationManager.submitRemoteSubscriptions(registry); } protected FederationType getFederation() throws EbxmlRegistryException { @@ -222,7 +217,7 @@ public class WfoRegistryFederationManager extends RegistryFederationManager { * @author bphillip * @version 1 */ - private class RegisterWithFederationTask implements Runnable { + private class RegisterWithFederationTask extends RunnableWithTransaction { /** * Denotes if this task has successfully registered this registry with @@ -234,44 +229,39 @@ public class WfoRegistryFederationManager extends RegistryFederationManager { * Creates a new RegisterwithFederationTask */ public RegisterWithFederationTask() { + super(txTemplate); } @Override - public void run() { + public void runWithTransaction() { if (!success) { - txTemplate.execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult( - TransactionStatus status) { - try { - try { - if (RegistryRESTServices - .isRegistryAvailable(ncfAddress)) { - statusHandler - .info("NCF Registry is available. Attempting to join federation..."); - } else { - statusHandler - .error("NCF is currently unreachable. Local registry is unable to join the federation at this time. Retrying in 10 seconds..."); - replicationManager - .setSubscriptionProcessingEnabled(false); - success = false; - return; - } - registerWithFederation(); - success = true; - } catch (EbxmlRegistryException e) { - statusHandler.error( - "Error registering with federation", e); - success = false; - } - } catch (Throwable e) { - throw new RuntimeException( - "Error initializing EBXML database!", e); + try { + try { + if (RegistryRESTServices + .isRegistryAvailable(ncfAddress)) { + statusHandler + .info("NCF Registry is available. Attempting to join federation..."); + } else { + statusHandler + .error("NCF is currently unreachable. Local registry is unable to join the federation at this time. Retrying in 10 seconds..."); + replicationManager + .setSubscriptionProcessingEnabled(false); + success = false; + return; } - + registerWithFederation(); + replicationManager.checkDownTime(); + success = true; + } catch (EbxmlRegistryException e) { + statusHandler.error( + "Error registering with federation", e); + success = false; } - }); + } catch (Throwable e) { + throw new RuntimeException( + "Error initializing EBXML database!", e); + } } } } diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/replication/RegistryRemoveTask.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/replication/RegistryRemoveTask.java new file mode 100644 index 0000000000..90e6e6ed1d --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/replication/RegistryRemoveTask.java @@ -0,0 +1,72 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.datadelivery.registry.replication; + +import org.springframework.transaction.support.TransactionTemplate; + +import com.raytheon.uf.edex.database.RunnableWithTransaction; +import com.raytheon.uf.edex.registry.ebxml.dao.RegistryObjectDao; + +/** + * + * A task to remove an object from the registry asynchonously + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * 7/29/2013    2191        bphillip    Initial implementation
+ * 
+ * + * @author bphillip + * @version 1 + */ +public class RegistryRemoveTask extends RunnableWithTransaction { + + /** Data Access object for registry objects */ + private RegistryObjectDao dao; + + /** The id of the registry object this task is removing */ + private String idToRemove; + + /** + * Creates a new AsyncRemove object + * + * @param txTemplate + * The Hibernate transaction template + * @param lcm + * The lifecycle manager + * @param idToRemove + * The ide of the registry object to remove + */ + public RegistryRemoveTask(TransactionTemplate txTemplate, + RegistryObjectDao dao, String idToRemove) { + super(txTemplate); + this.dao = dao; + } + + @Override + public void runWithTransaction() { + dao.delete(dao.getById(idToRemove)); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/replication/RegistryReplicationManager.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/replication/RegistryReplicationManager.java index 9efd0186af..6b600fdd9b 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/replication/RegistryReplicationManager.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/replication/RegistryReplicationManager.java @@ -21,7 +21,12 @@ package com.raytheon.uf.edex.datadelivery.registry.replication; import java.io.File; import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -35,17 +40,23 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.ws.wsaddressing.W3CEndpointReference; import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder; +import oasis.names.tc.ebxml.regrep.wsdl.registry.services.v4.MsgRegistryException; import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.Mode; import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.SubmitObjectsRequest; +import oasis.names.tc.ebxml.regrep.xsd.query.v4.QueryRequest; +import oasis.names.tc.ebxml.regrep.xsd.query.v4.QueryResponse; +import oasis.names.tc.ebxml.regrep.xsd.query.v4.ResponseOptionType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.DeliveryInfoType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.QueryType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectListType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectType; +import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.SlotType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.StringValueType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.SubscriptionType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.VersionInfoType; +import org.springframework.transaction.support.TransactionTemplate; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -57,6 +68,7 @@ import com.raytheon.uf.common.registry.constants.CanonicalQueryTypes; import com.raytheon.uf.common.registry.constants.DeliveryMethodTypes; import com.raytheon.uf.common.registry.constants.Namespaces; import com.raytheon.uf.common.registry.constants.NotificationOptionTypes; +import com.raytheon.uf.common.registry.constants.QueryReturnTypes; import com.raytheon.uf.common.registry.constants.RegistryObjectTypes; import com.raytheon.uf.common.registry.constants.StatusTypes; import com.raytheon.uf.common.registry.ebxml.RegistryUtil; @@ -66,7 +78,12 @@ import com.raytheon.uf.common.serialization.JAXBManager; import com.raytheon.uf.common.serialization.SerializationException; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.common.util.CollectionUtil; +import com.raytheon.uf.edex.datadelivery.registry.availability.FederatedRegistryMonitor; +import com.raytheon.uf.edex.registry.ebxml.dao.RegistryObjectDao; +import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; +import com.raytheon.uf.edex.registry.ebxml.services.query.QueryConstants; import com.raytheon.uf.edex.registry.ebxml.util.EbxmlObjectUtil; /** @@ -81,6 +98,7 @@ import com.raytheon.uf.edex.registry.ebxml.util.EbxmlObjectUtil; * ------------ ---------- ----------- -------------------------- * 4/24/2013 1675 bphillip Initial implementation * 6/4/2013 1707 bphillip Changed to use new NotificationServer objects + * 7/29/2013 2191 bphillip Implemented registry sync for registries that have been down for an extended period of time * * * @author bphillip @@ -92,12 +110,21 @@ public class RegistryReplicationManager { private static final IUFStatusHandler statusHandler = UFStatus .getHandler(RegistryReplicationManager.class); + private FederatedRegistryMonitor federatedRegistryMonitor; + + private static final long MAX_DOWN_TIME_DURATION = TimeUtil.MILLIS_PER_DAY + * 2 - TimeUtil.MILLIS_PER_HOUR; + /** Scheduler service for monitoring subscription submission tasks */ private ScheduledExecutorService scheduler; /** The servers that we are subscribing to */ private NotificationServers servers; + private RegistryObjectDao dao; + + private TransactionTemplate txTemplate; + /** * The JAXBManager instance for marshalling/unmarshalling objects */ @@ -127,10 +154,15 @@ public class RegistryReplicationManager { * @throws SerializationException */ public RegistryReplicationManager(boolean subscriptionProcessingEnabled, - String notificationServerConfigFileName) throws JAXBException, + String notificationServerConfigFileName, RegistryObjectDao dao, + FederatedRegistryMonitor availabilityMonitor, + TransactionTemplate txTemplate) throws JAXBException, SerializationException { this.subscriptionProcessingEnabled = subscriptionProcessingEnabled; this.replicationConfigFileName = notificationServerConfigFileName; + this.dao = dao; + this.txTemplate = txTemplate; + this.federatedRegistryMonitor = availabilityMonitor; jaxbManager = new JAXBManager(NotificationServers.class, SubscriptionType.class); File notificationServerConfigFile = PathManagerFactory.getPathManager() @@ -147,6 +179,201 @@ public class RegistryReplicationManager { scheduler = Executors.newSingleThreadScheduledExecutor(); } + /** + * Checks how long a registry has been down. If the registry has been down + * for over 2 days, the registry is synchronized with one of the federation + * members + * + * @throws MsgRegistryException + * If errors occur during registry synchronization + * @throws EbxmlRegistryException + * If errors occur during registry synchronization + */ + public void checkDownTime() throws MsgRegistryException, + EbxmlRegistryException { + long currentTime = TimeUtil.currentTimeMillis(); + long lastKnownUp = federatedRegistryMonitor.getLasKnownUptime(); + long downTime = currentTime - lastKnownUp; + statusHandler + .info("Registry has been down since: " + + new Date(currentTime - downTime) + + ". Checking if synchronization with the federation is necessary..."); + + // The registry has been down for ~2 days, this requires a + // synchronization of the + // data from the federation + if (currentTime - lastKnownUp > MAX_DOWN_TIME_DURATION) { + statusHandler + .warn("Registry has been down for ~2 days. Initiating federated data synchronization...."); + List notificationServers = servers + .getRegistryReplicationServers(); + if (servers == null + || CollectionUtil.isNullOrEmpty(servers + .getRegistryReplicationServers())) { + statusHandler + .warn("No servers configured for replication. Unable to synchronize data with federation!"); + } else { + NotificationHostConfiguration registryToSyncFrom = null; + for (NotificationHostConfiguration config : notificationServers) { + statusHandler.info("Checking availability of registry at: " + + config.getRegistryBaseURL()); + if (RegistryRESTServices.isRegistryAvailable(config + .getRegistryBaseURL())) { + registryToSyncFrom = config; + break; + } + + statusHandler.info("Registry at " + + config.getRegistryBaseURL() + + " is not available..."); + } + + // No available registry was found! + if (registryToSyncFrom == null) { + statusHandler + .warn("No available registries found! Registry data will not be synchronized with the federation!"); + } else { + synchronizeRegistryWithFederation(registryToSyncFrom + .getRegistryBaseURL()); + } + } + + } + + statusHandler.info("Starting federated uptime monitor..."); + scheduler.scheduleAtFixedRate(federatedRegistryMonitor, 0, 1, + TimeUnit.MINUTES); + } + + private void synchronizeRegistryWithFederation(String remoteRegistryUrl) + throws MsgRegistryException, EbxmlRegistryException { + ExecutorService executor = Executors.newFixedThreadPool(25); + for (String objectType : objectTypes) { + Set localIds = new HashSet(); + Set remoteIds = new HashSet(); + statusHandler + .info("Getting registry object Ids from local registry..."); + Collection response = RegistryRESTServices + .getRegistryDataAccessService( + RegistryUtil.LOCAL_REGISTRY_ADDRESS) + .getRegistryObjectIdsOfType(objectType).getPayload(); + if (response != null) { + localIds.addAll(response); + } + statusHandler.info(localIds.size() + " objects of type " + + objectType + " present in local registry."); + statusHandler.info("Getting registry object Ids from " + + remoteRegistryUrl + "..."); + response = RegistryRESTServices + .getRegistryDataAccessService(remoteRegistryUrl) + .getRegistryObjectIdsOfType(objectType).getPayload(); + if (response != null) { + remoteIds.addAll(response); + } + statusHandler.info(remoteIds.size() + " objects of type " + + objectType + " present on registry at " + + remoteRegistryUrl); + statusHandler.info("Synchronizing objects of type " + objectType + + "..."); + + /* + * Iterate through local objects and compare them with the remote + * object inventory to determine if they need to be updated or + * deleted locally + */ + for (String localId : localIds) { + if (remoteIds.contains(localId)) { + RegistryObjectType objectToSubmit; + try { + objectToSubmit = getRemoteObject(remoteRegistryUrl, + localId); + } catch (Exception e) { + statusHandler.error("Error getting remote object: " + + localId, e); + continue; + } + objectToSubmit.addSlot(EbxmlObjectUtil.HOME_SLOT_NAME, + remoteRegistryUrl); + RegistrySubmitTask submitTask = new RegistrySubmitTask( + txTemplate, dao, objectToSubmit, remoteRegistryUrl); + executor.submit(submitTask); + } else { + RegistryRemoveTask removeTask = new RegistryRemoveTask( + txTemplate, dao, localId); + executor.submit(removeTask); + } + } + + /* + * Iterate through the remote objects to see if there are any + * objects on the remote registry that do not exist local. If found, + * retrieve them and add them to the local registry + */ + for (String remoteId : remoteIds) { + if (!localIds.contains(remoteId)) { + RegistryObjectType objectToSubmit; + try { + objectToSubmit = getRemoteObject(remoteRegistryUrl, + remoteId); + } catch (Exception e) { + statusHandler.error("Error getting remote object: " + + remoteId, e); + continue; + } + objectToSubmit.addSlot(EbxmlObjectUtil.HOME_SLOT_NAME, + remoteRegistryUrl); + RegistrySubmitTask submitTask = new RegistrySubmitTask( + txTemplate, dao, objectToSubmit, remoteRegistryUrl); + executor.submit(submitTask); + } + } + } + + // Wait for all threads to complete + executor.shutdown(); + try { + executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + } catch (InterruptedException e) { + statusHandler + .error("Registry synchronization using [" + + remoteRegistryUrl + + "] did not complete successfully!", e); + throw new EbxmlRegistryException( + "Task executor did not shutdown properly!", e); + } + + statusHandler.info("Registry synchronization using [" + + remoteRegistryUrl + "] completed successfully!"); + } + + private RegistryObjectType getRemoteObject(String remoteRegistryUrl, + String objectId) throws Exception { + final QueryType queryType = new QueryType(); + queryType.setQueryDefinition(CanonicalQueryTypes.GET_OBJECT_BY_ID); + Set slots = new HashSet(); + final SlotType slot = new SlotType(); + slot.setName(QueryConstants.ID); + final StringValueType slotValue = new StringValueType(); + slotValue.setStringValue(objectId); + slot.setSlotValue(slotValue); + slots.add(slot); + queryType.setSlot(slots); + + QueryRequest queryRequest = new QueryRequest(); + queryRequest.setResponseOption(new ResponseOptionType( + QueryReturnTypes.REGISTRY_OBJECT, true)); + queryRequest.setFederated(false); + queryRequest.setQuery(queryType); + QueryResponse response = RegistrySOAPServices.getQueryServiceForHost( + remoteRegistryUrl).executeQuery(queryRequest); + if (!CollectionUtil.isNullOrEmpty(response.getRegistryObjects())) { + return response.getRegistryObjects().get(0); + } else { + throw new EbxmlRegistryException("Object " + objectId + + " not found on remote server!"); + } + } + /** * Static method only used during the Spring container to inject the object * types to subscribe to for registry replication @@ -166,7 +393,7 @@ public class RegistryReplicationManager { * @param baseURL * The url of the registry to send the subscriptions to */ - public void submitRemoteSubscriptions(String baseURL) { + public void submitRemoteSubscriptions(RegistryType registry) { if (subscriptionProcessingEnabled) { statusHandler.info("Registry Replication is enabled."); @@ -187,7 +414,7 @@ public class RegistryReplicationManager { statusHandler .info("Submitting subscriptions to registry replication servers..."); for (NotificationHostConfiguration config : replicationRegistries) { - scheduleSubscriptionSubmission(config, baseURL); + scheduleSubscriptionSubmission(config, registry); } } } @@ -201,9 +428,9 @@ public class RegistryReplicationManager { * The url of the registry to submit the subscriptions to */ private void scheduleSubscriptionSubmission( - NotificationHostConfiguration config, String baseURL) { + NotificationHostConfiguration config, RegistryType registry) { final SubmitSubscriptionTask submitSubscriptionTask = new SubmitSubscriptionTask( - config, baseURL); + config, registry); final ScheduledFuture future = scheduler.scheduleAtFixedRate( submitSubscriptionTask, 0, 10, TimeUnit.SECONDS); scheduler.schedule(new Runnable() { @@ -227,7 +454,7 @@ public class RegistryReplicationManager { * replication subscriptions to */ private void submitSubscriptionsToHost( - NotificationHostConfiguration config, String localRegistryBaseURL) { + NotificationHostConfiguration config, RegistryType localRegistry) { statusHandler .info("Generating registry replication subscriptions for registry at [" + config.getRegistrySiteName() @@ -239,7 +466,7 @@ public class RegistryReplicationManager { SubscriptionType subscription; try { subscription = createSubscription(config.getRegistryBaseURL(), - objectType, localRegistryBaseURL); + objectType, localRegistry); } catch (Exception e) { throw new RegistryException("Error creating subscription", e); } @@ -267,10 +494,10 @@ public class RegistryReplicationManager { * If errors occur while creating the subscription object */ private SubscriptionType createSubscription(String host, String objectType, - String localRegistryBaseURL) throws Exception { + RegistryType registry) throws Exception { // Set normal registry object fields String subscriptionDetail = "Replication Subscription for [" - + objectType + "] objects for server [" + localRegistryBaseURL + + objectType + "] objects for server [" + registry.getBaseURL() + "]"; SubscriptionType sub = new SubscriptionType(); sub.setId(subscriptionDetail); @@ -283,7 +510,7 @@ public class RegistryReplicationManager { version.setVersionName("1"); version.setUserVersionName("1"); sub.setVersionInfo(version); - sub.setOwner("Subscription Owner"); + sub.setOwner(registry.getOwner()); sub.setStatus(StatusTypes.APPROVED); sub.setStartTime(EbxmlObjectUtil.getTimeAsXMLGregorianCalendar(0)); @@ -304,7 +531,7 @@ public class RegistryReplicationManager { String endpointType = DeliveryMethodTypes.SOAP; W3CEndpointReferenceBuilder builder = new W3CEndpointReferenceBuilder(); builder.address(RegistrySOAPServices.getNotificationListenerServiceUrl( - localRegistryBaseURL).toString()); + registry.getBaseURL()).toString()); W3CEndpointReference ref = builder.build(); DOMResult dom = new DOMResult(); ref.writeTo(dom); @@ -355,8 +582,8 @@ public class RegistryReplicationManager { /** The server configuration */ private NotificationHostConfiguration config; - /** The base URL of the remote registry */ - private String baseURL; + /** The remote registry */ + private RegistryType registry; /** * Creates a new SubmitSubscriptionTask @@ -367,15 +594,16 @@ public class RegistryReplicationManager { * The base URL of the remote registry */ public SubmitSubscriptionTask(NotificationHostConfiguration config, - String baseURL) { + RegistryType registry) { this.config = config; - this.baseURL = baseURL; + this.registry = registry; } @Override public void run() { if (!success) { - String remoteRegistryBaseURL = config.getRegistryBaseURL(); + final String remoteRegistryBaseURL = config + .getRegistryBaseURL(); statusHandler.info("Checking if remote registry at [" + remoteRegistryBaseURL + "] is available..."); @@ -390,7 +618,25 @@ public class RegistryReplicationManager { return; } try { - submitSubscriptionsToHost(config, baseURL); + statusHandler + .info("Removing remote subscriptions prior to submission of new subscriptions"); + RegistryRESTServices.getRegistryDataAccessService( + config.getRegistryBaseURL()) + .removeSubscriptionsForSite(registry.getOwner()); + submitSubscriptionsToHost(config, registry); + + /* + * Adds a hook to remove the subscriptions from the remote + * server when this server shuts down + */ + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + RegistryRESTServices.getRegistryDataAccessService( + remoteRegistryBaseURL) + .removeSubscriptionsForSite( + registry.getOwner()); + } + }); success = true; } catch (Exception e) { statusHandler diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/replication/RegistrySubmitTask.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/replication/RegistrySubmitTask.java new file mode 100644 index 0000000000..f20b2dd76a --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.registry/src/com/raytheon/uf/edex/datadelivery/registry/replication/RegistrySubmitTask.java @@ -0,0 +1,76 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.datadelivery.registry.replication; + +import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectType; + +import org.springframework.transaction.support.TransactionTemplate; + +import com.raytheon.uf.edex.database.RunnableWithTransaction; +import com.raytheon.uf.edex.registry.ebxml.dao.RegistryObjectDao; +import com.raytheon.uf.edex.registry.ebxml.util.EbxmlObjectUtil; + +/** + * + * A task to submit an object to the registry asynchonously + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * 7/29/2013    2191        bphillip    Initial implementation
+ * 
+ * + * @author bphillip + * @version 1 + */ +public class RegistrySubmitTask extends RunnableWithTransaction { + + /** The Registry Object data access object */ + private RegistryObjectDao dao; + + /** The id of the registry object this task is submitting */ + private RegistryObjectType objectToSubmit; + + public RegistrySubmitTask(TransactionTemplate txTemplate, + RegistryObjectDao dao, RegistryObjectType objectToSubmit, + String retrievedFrom) { + super(txTemplate); + this.dao = dao; + this.objectToSubmit = objectToSubmit; + if (this.objectToSubmit.getSlotByName(EbxmlObjectUtil.HOME_SLOT_NAME) == null) { + this.objectToSubmit.addSlot(EbxmlObjectUtil.HOME_SLOT_NAME, + retrievedFrom); + } + } + + @Override + public void runWithTransaction() { + RegistryObjectType existingObject = dao.getById(objectToSubmit.getId()); + if (existingObject == null) { + dao.create(objectToSubmit); + } else { + dao.merge(objectToSubmit, existingObject); + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/META-INF/services/com.raytheon.uf.common.serialization.ISerializableObject b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/META-INF/services/com.raytheon.uf.common.serialization.ISerializableObject index eb9bbd468e..dddf55c133 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/META-INF/services/com.raytheon.uf.common.serialization.ISerializableObject +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/META-INF/services/com.raytheon.uf.common.serialization.ISerializableObject @@ -1 +1,2 @@ -com.raytheon.uf.edex.registry.ebxml.services.query.adhoc.AdhocQueryExpression \ No newline at end of file +com.raytheon.uf.edex.registry.ebxml.services.query.adhoc.AdhocQueryExpression +com.raytheon.uf.edex.registry.ebxml.services.rest.RestResponse \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/spring/ebxml-impl.xml b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/spring/ebxml-impl.xml index bcdb64cca8..199901af86 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/spring/ebxml-impl.xml +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/spring/ebxml-impl.xml @@ -37,6 +37,7 @@ class="com.raytheon.uf.edex.registry.ebxml.services.RegistryGarbageCollector"> +
diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/spring/ebxml-webservices.xml b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/spring/ebxml-webservices.xml index 6ccfe6d02e..170066f5a8 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/spring/ebxml-webservices.xml +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/spring/ebxml-webservices.xml @@ -69,6 +69,11 @@ + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/resources/com.raytheon.uf.edex.registry.ebxml.properties b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/resources/com.raytheon.uf.edex.registry.ebxml.properties index e73a7beda5..818e303b6b 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/resources/com.raytheon.uf.edex.registry.ebxml.properties +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/resources/com.raytheon.uf.edex.registry.ebxml.properties @@ -1,5 +1,5 @@ # The period which registry subscriptions are processed ebxml-subscription-process.cron=0+0/1+*+*+*+? -ebxml-garbage-collect-process.cron=0/30+*+*+*+*+? +ebxml-garbage-collect-process.cron=0/1+*+*+*+*+? # Master switch enabling email transmission ebxml-email.enabled=false \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/AuditableEventTypeDao.java b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/AuditableEventTypeDao.java index 3c6d234796..78d322e268 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/AuditableEventTypeDao.java +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/AuditableEventTypeDao.java @@ -61,6 +61,7 @@ import com.raytheon.uf.edex.registry.ebxml.util.EbxmlObjectUtil; * 4/9/2013 1802 bphillip Removed exception catching * Apr 17, 2013 1914 djohnson Use strategy for subscription processing. * May 02, 2013 1910 djohnson Broke out registry subscription notification to a service class. + * 7/29/2013 2191 bphillip Changed method to get expired events * * * @@ -94,9 +95,6 @@ public class AuditableEventTypeDao extends /** Cutoff parameter for the query to get the expired events */ private static final String GET_EXPIRED_EVENTS_QUERY_CUTOFF_PARAMETER = "cutoff"; - /** Batch size for the query to get expired events */ - private static final int GET_EXPIRED_EVENTS_QUERY_BATCH_SIZE = 2500; - /** Query to get Expired AuditableEvents */ private static final String GET_EXPIRED_EVENTS_QUERY = "FROM AuditableEventType event where event.timestamp < :" + GET_EXPIRED_EVENTS_QUERY_CUTOFF_PARAMETER; @@ -115,25 +113,20 @@ public class AuditableEventTypeDao extends } /** - * Deletes auditable events older than 48 hrs old + * Gets auditable events older than 48 hrs old * * @throws EbxmlRegistryException * If errors occur purging auditable events */ @Transactional(propagation = Propagation.REQUIRED) - public void deleteExpiredEvents() throws EbxmlRegistryException { + public List getExpiredEvents(int limit) + throws EbxmlRegistryException { Calendar cutoffTime = TimeUtil.newGmtCalendar(); cutoffTime.add(Calendar.HOUR_OF_DAY, -AUDITABLE_EVENT_RETENTION_TIME); - List expiredEvents = this.executeHQLQuery( - GET_EXPIRED_EVENTS_QUERY, GET_EXPIRED_EVENTS_QUERY_BATCH_SIZE, + return this.executeHQLQuery(GET_EXPIRED_EVENTS_QUERY, limit, GET_EXPIRED_EVENTS_QUERY_CUTOFF_PARAMETER, EbxmlObjectUtil .getTimeAsXMLGregorianCalendar(cutoffTime .getTimeInMillis())); - if (!expiredEvents.isEmpty()) { - statusHandler.info("Deleting " + expiredEvents.size() - + " Auditable Events prior to: " + cutoffTime.getTime()); - this.template.deleteAll(expiredEvents); - } } /** diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/RegistryObjectDao.java b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/RegistryObjectDao.java index f3c312153f..71d5fae469 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/RegistryObjectDao.java +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/RegistryObjectDao.java @@ -23,7 +23,6 @@ import java.util.List; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectType; -import com.raytheon.uf.edex.database.DataAccessLayerException; import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; /** @@ -38,6 +37,7 @@ import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; * 3/13/2013 1082 bphillip Initial creation * 4/9/2013 1802 bphillip Removed exception catching * 6/4/2013 2022 bphillip Added delete objects of type method + * 7/29/2013 2191 bphillip Added new methods to support registry synchronization * * * @@ -48,25 +48,31 @@ public class RegistryObjectDao extends RegistryObjectTypeDao { /** Delete object type parameterized statement */ - private static final String DELETE_OBJECT_TYPE = "DELETE RegistryObjectType regObj where regObj.objectType=:objectType"; + private static final String GET_IDS_BY_OBJECT_TYPE = "SELECT regObj.id FROM RegistryObjectType regObj WHERE regObj.objectType=:objectType"; public RegistryObjectDao() { } /** - * Deletes objects of a specific type from the registry + * Gets the object ids of objects of the given object type * * @param objectType - * The object type to delete - * @throws DataAccessLayerException - * If errors occur on the delete + * The object type to get the ids for + * @return The list of object ids of objects of the given type */ - public void deleteObjectsOfType(String objectType) - throws DataAccessLayerException { - int objectsDeleted = this.executeHQLStatement(DELETE_OBJECT_TYPE, - "objectType", objectType); - statusHandler.info(objectsDeleted + " objects of type " + objectType - + " deleted from registry"); + public List getRegistryObjectIdsOfType(String objectType) { + return this.executeHQLQuery(GET_IDS_BY_OBJECT_TYPE, "objectType", + objectType); + } + + /** + * Deletes a persistent object + * + * @param obj + * The persistent object to delete + */ + public void deleteWithoutMerge(RegistryObjectType obj) { + this.template.delete(obj); } /** diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/SlotTypeDao.java b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/SlotTypeDao.java index 787284aa70..5b59b50679 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/SlotTypeDao.java +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/SlotTypeDao.java @@ -23,9 +23,6 @@ import java.util.List; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.SlotType; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; - import com.raytheon.uf.edex.database.dao.SessionManagedDao; /** @@ -39,6 +36,7 @@ import com.raytheon.uf.edex.database.dao.SessionManagedDao; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 7/11/2013 1707 bphillip Initial implementation + * 7/29/2013 2191 bphillip Modified method to get orphaned slots * * * @author bphillip @@ -71,35 +69,34 @@ public class SlotTypeDao extends SessionManagedDao { + "select child_slot_key from ebxml.emailaddress_slot " + "UNION " + "select child_slot_key from ebxml.postaladdress_slot " - + ")"; - - /** Keys parameter for the query to get the orphaned slot objects */ - private static final String GET_BY_ID_QUERY_KEYS_PARAMETER = "keys"; - - /** Result batch size for the query to get the orphaned slot objects */ - private static final int GET_BY_ID_QUERY_BATCH_SIZE = 1000; - - private static final String GET_BY_ID_QUERY = "FROM SlotType slot where slot.key in (:" - + GET_BY_ID_QUERY_KEYS_PARAMETER + ")"; + + ") limit %s"; @Override protected Class getEntityClass() { return SlotType.class; } + /** + * Gets orphaned slot ids + * + * @param limit + * The maximum number of results to return + * @return List of orphaned ids of size limit + */ @SuppressWarnings("unchecked") - @Transactional(propagation = Propagation.REQUIRED) - public void deleteOrphanedSlots() { - List orphanedSlotIds = this.getSessionFactory() - .getCurrentSession().createSQLQuery(ORPHANED_SLOT_QUERY).list(); - if (!orphanedSlotIds.isEmpty()) { + public List getOrphanedSlotIds(int limit) { + return this + .getSessionFactory() + .getCurrentSession() + .createSQLQuery( + String.format(ORPHANED_SLOT_QUERY, + String.valueOf(limit))).list(); + } - List slots = this.executeHQLQuery(GET_BY_ID_QUERY, - GET_BY_ID_QUERY_BATCH_SIZE, GET_BY_ID_QUERY_KEYS_PARAMETER, - orphanedSlotIds); - statusHandler.info("Removing " + orphanedSlotIds.size() - + " orphaned slots..."); - this.deleteAll(slots); + public void deleteBySlotId(Integer id) { + SlotType slot = this.getById(id); + if (slot != null) { + this.template.delete(slot); } } } diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/RegistryGarbageCollector.java b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/RegistryGarbageCollector.java index a146442cec..6434368906 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/RegistryGarbageCollector.java +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/RegistryGarbageCollector.java @@ -19,8 +19,22 @@ **/ package com.raytheon.uf.edex.registry.ebxml.services; +import java.util.List; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import oasis.names.tc.ebxml.regrep.xsd.rim.v4.AuditableEventType; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionTemplate; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.database.RunnableWithTransaction; import com.raytheon.uf.edex.registry.ebxml.dao.AuditableEventTypeDao; import com.raytheon.uf.edex.registry.ebxml.dao.SlotTypeDao; import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; @@ -38,27 +52,48 @@ import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 7/11/2013 1707 bphillip Initial implementation + * 7/29/2013 2191 bphillip Added executors to remove orphaned slots and expired events * * * @author bphillip * @version 1 */ +@Service +@Transactional public class RegistryGarbageCollector { + /** The logger instance */ + private static final IUFStatusHandler statusHandler = UFStatus + .getHandler(RegistryGarbageCollector.class); + /** Sentinel to denote if the garbage collection is currently running */ private AtomicBoolean running = new AtomicBoolean(false); + /** The executor service to remove orphaned slots */ + private ThreadPoolExecutor orphanedSlotExecutor; + + /** The executor service to remove expired events */ + private ThreadPoolExecutor expiredEventExecutor; + + /** The transaction template to use for asynchronous tasks */ + private TransactionTemplate txTemplate; + /** Data access object for SlotType */ private SlotTypeDao slotDao; /** Data access object for AuditableEventType */ private AuditableEventTypeDao eventDao; + private static final int QUEUE_MAX_SIZE = 500; + /** * Creates a new GarbageCollector object */ public RegistryGarbageCollector() { - + orphanedSlotExecutor = new ThreadPoolExecutor(1, 3, 1L, + TimeUnit.MINUTES, new LinkedBlockingQueue(250)); + expiredEventExecutor = new ThreadPoolExecutor(1, 3, 1L, + TimeUnit.MINUTES, new LinkedBlockingQueue(250)); } /** @@ -70,24 +105,119 @@ public class RegistryGarbageCollector { * The auditable event dao to use */ public RegistryGarbageCollector(SlotTypeDao slotDao, - AuditableEventTypeDao eventDao) { + AuditableEventTypeDao eventDao, TransactionTemplate txTemplate) { + this(); this.slotDao = slotDao; this.eventDao = eventDao; + this.txTemplate = txTemplate; + } /** * Cleans up the registry by removing unused and/or orphaned objects */ - public void gc() throws EbxmlRegistryException { + public void gc() { + if (!running.compareAndSet(false, true)) { return; } try { - eventDao.deleteExpiredEvents(); - slotDao.deleteOrphanedSlots(); + purgeOrphanedSlots(); + purgeExpiredEvents(); + } catch (EbxmlRegistryException e) { + statusHandler.error("Error purging auditable events!", e); } finally { running.set(false); } } + /** + * Purges orphaned slots in the registry + */ + private void purgeOrphanedSlots() { + /* + * Determines how many more orphaned slots can be added to the queue + * based on the existing queue size + */ + int limit = QUEUE_MAX_SIZE - orphanedSlotExecutor.getQueue().size(); + if (limit > QUEUE_MAX_SIZE * .25) { + List orphanedSlotIds = slotDao.getOrphanedSlotIds(limit); + for (Integer slotId : orphanedSlotIds) { + try { + orphanedSlotExecutor.submit(new RemoveOrphanedSlot( + txTemplate, slotId)); + } catch (RejectedExecutionException e) { + // Could not add more to the queue since it is full + } + } + } + } + + /** + * Purges expired events older than 2 days + * + * @throws EbxmlRegistryException + * If errors occur while enqueuing events to be deleted + */ + private void purgeExpiredEvents() throws EbxmlRegistryException { + int limit = QUEUE_MAX_SIZE - expiredEventExecutor.getQueue().size(); + if (limit > QUEUE_MAX_SIZE * .25) { + List expiredEvents = eventDao + .getExpiredEvents(limit); + for (AuditableEventType event : expiredEvents) { + try { + expiredEventExecutor.submit(new RemoveExpiredEvent( + txTemplate, event)); + } catch (RejectedExecutionException e) { + // Could not add more to the queue since it is full + } + } + } + + } + + /** + * Task to remove orphaned slots that is run asynchronously + * + * @author bphillip + * + */ + private class RemoveOrphanedSlot extends RunnableWithTransaction { + + /** The id of the orphaned slot to be removed by this task */ + private Integer slotId; + + public RemoveOrphanedSlot(TransactionTemplate txTemplate, Integer slotId) { + super(txTemplate); + this.slotId = slotId; + } + + @Override + public void runWithTransaction() { + slotDao.deleteBySlotId(slotId); + } + } + + /** + * Task to remove expired auditable eventss + * + * @author bphillip + * + */ + private class RemoveExpiredEvent extends RunnableWithTransaction { + + /** The event to be removed */ + private AuditableEventType event; + + public RemoveExpiredEvent(TransactionTemplate txTemplate, + AuditableEventType event) { + super(txTemplate); + this.event = event; + } + + @Override + public void runWithTransaction() { + eventDao.delete(event); + } + } } diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/lifecycle/LifecycleManagerImpl.java b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/lifecycle/LifecycleManagerImpl.java index 352a9ac507..97e6375eea 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/lifecycle/LifecycleManagerImpl.java +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/lifecycle/LifecycleManagerImpl.java @@ -40,7 +40,6 @@ import oasis.names.tc.ebxml.regrep.xsd.query.v4.ResponseOptionType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.AssociationType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.ClassificationNodeType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.ClassificationSchemeType; -import oasis.names.tc.ebxml.regrep.xsd.rim.v4.ExtensibleObjectType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.ObjectRefType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.QueryType; import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectType; @@ -329,7 +328,8 @@ public class LifecycleManagerImpl implements LifecycleManager { statusHandler .info("Client has selected to check object references before submitting objects."); ValidateObjectsRequest validateObjectsRequest = new ValidateObjectsRequest(); - validateObjectsRequest.setOriginalObjects(request.getRegistryObjectList()); + validateObjectsRequest.setOriginalObjects(request + .getRegistryObjectList()); // Uses the validation service directly, not going through the // web-service client interface @@ -338,8 +338,10 @@ public class LifecycleManagerImpl implements LifecycleManager { EbxmlObjectUtil.spiObjectFactory .createValidateObjectsResponse()); - final List validationExceptions = validationResponse.getException(); - final List responseExceptions = response.getException(); + final List validationExceptions = validationResponse + .getException(); + final List responseExceptions = response + .getException(); if (!validationExceptions.isEmpty()) { // Only care about unresolved references @@ -636,7 +638,7 @@ public class LifecycleManagerImpl implements LifecycleManager { } private void checkReplica(SubmitObjectsRequest request, - ExtensibleObjectType object1, ExtensibleObjectType object2) + RegistryObjectType object1, RegistryObjectType object2) throws MsgRegistryException { boolean fromNotification = request .getSlotValue(EbxmlObjectUtil.HOME_SLOT_NAME) != null; @@ -645,7 +647,11 @@ public class LifecycleManagerImpl implements LifecycleManager { String object2Home = object2 .getSlotValue(EbxmlObjectUtil.HOME_SLOT_NAME); + if (object1.getOwner().equals(object2.getOwner())) { + return; + } if (fromNotification) { + if (object1Home != null && object2Home == null) { throw EbxmlExceptionUtil.createMsgRegistryException( "Cannot overwrite local object with replica", diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/notification/RegistryNotificationManager.java b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/notification/RegistryNotificationManager.java index d83bbeb7f5..d66b3cbdd6 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/notification/RegistryNotificationManager.java +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/notification/RegistryNotificationManager.java @@ -44,7 +44,6 @@ import com.raytheon.uf.common.registry.constants.StatusTypes; import com.raytheon.uf.common.registry.ebxml.RegistryUtil; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; -import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.edex.registry.ebxml.dao.AuditableEventTypeDao; import com.raytheon.uf.edex.registry.ebxml.dao.NotificationTypeDao; import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; @@ -164,39 +163,32 @@ public class RegistryNotificationManager { subscription, objectsOfInterest); if (!eventsOfInterest.isEmpty()) { - try { - for (NotificationListenerWrapper listener : listeners) { - int subListCount = eventsOfInterest.size() / SIZE_LIMIT; - int lastListSize = eventsOfInterest.size() % SIZE_LIMIT; - for (int i = 0; i < subListCount; i++) { - NotificationType notification = getNotification( - subscription, listener.address, - objectsOfInterest, eventsOfInterest.subList( - SIZE_LIMIT * i, SIZE_LIMIT * i - + SIZE_LIMIT)); - if (!notification.getEvent().isEmpty()) { - sendNotification(listener, notification, - listener.address); - } + for (NotificationListenerWrapper listener : listeners) { + int subListCount = eventsOfInterest.size() / SIZE_LIMIT; + int lastListSize = eventsOfInterest.size() % SIZE_LIMIT; + for (int i = 0; i < subListCount; i++) { + NotificationType notification = getNotification( + subscription, + listener.address, + objectsOfInterest, + eventsOfInterest.subList(SIZE_LIMIT * i, SIZE_LIMIT + * i + SIZE_LIMIT)); + if (!notification.getEvent().isEmpty()) { + sendNotification(listener, notification, + listener.address); } - if (lastListSize > 0) { - NotificationType notification = getNotification( - subscription, - listener.address, - objectsOfInterest, - eventsOfInterest.subList(SIZE_LIMIT - * subListCount, SIZE_LIMIT - * subListCount + lastListSize)); - if (!notification.getEvent().isEmpty()) { - sendNotification(listener, notification, - listener.address); - } - } - } - } catch (Exception e) { - statusHandler.handle(Priority.PROBLEM, - "Unable to determine notification destinations.", e); + if (lastListSize > 0) { + NotificationType notification = getNotification( + subscription, listener.address, objectsOfInterest, + eventsOfInterest.subList(SIZE_LIMIT * subListCount, + SIZE_LIMIT * subListCount + lastListSize)); + if (!notification.getEvent().isEmpty()) { + sendNotification(listener, notification, + listener.address); + } + } + } } } diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/notification/RegistrySubscriptionManager.java b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/notification/RegistrySubscriptionManager.java index 8601af6b7f..579a02c887 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/notification/RegistrySubscriptionManager.java +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/notification/RegistrySubscriptionManager.java @@ -310,11 +310,7 @@ public class RegistrySubscriptionManager implements if (subscriptionShouldRun(sub)) { try { processSubscription(subNotificationListener); - } catch (EbxmlRegistryException e) { - statusHandler.error( - "Errors occurred while processing subscription [" - + sub.getId() + "]", e); - } catch (MsgRegistryException e) { + } catch (Throwable e) { statusHandler.error( "Errors occurred while processing subscription [" + sub.getId() + "]", e); diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/rest/RegistryDataAccessService.java b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/rest/RegistryDataAccessService.java new file mode 100644 index 0000000000..69344ec18b --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/services/rest/RegistryDataAccessService.java @@ -0,0 +1,145 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.registry.ebxml.services.rest; + +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +import oasis.names.tc.ebxml.regrep.wsdl.registry.services.v4.LifecycleManager; +import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.RemoveObjectsRequest; +import oasis.names.tc.ebxml.regrep.xsd.rim.v4.DeliveryInfoType; +import oasis.names.tc.ebxml.regrep.xsd.rim.v4.ObjectRefListType; +import oasis.names.tc.ebxml.regrep.xsd.rim.v4.ObjectRefType; +import oasis.names.tc.ebxml.regrep.xsd.rim.v4.SubscriptionType; +import oasis.names.tc.ebxml.regrep.xsd.rs.v4.RegistryResponseStatus; +import oasis.names.tc.ebxml.regrep.xsd.rs.v4.RegistryResponseType; + +import org.springframework.transaction.annotation.Transactional; + +import com.raytheon.uf.common.registry.RegistryException; +import com.raytheon.uf.common.registry.services.rest.IRegistryDataAccessService; +import com.raytheon.uf.common.registry.services.rest.response.RestCollectionResponse; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.registry.ebxml.dao.RegistryObjectDao; + +/** + * + * Implementation of the registry data access service interface + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * 7/29/2013    2191        bphillip    Initial implementation
+ * 
+ * + * @author bphillip + * @version 1 + */ +@Transactional +public class RegistryDataAccessService implements IRegistryDataAccessService { + + /** The logger */ + private static final IUFStatusHandler statusHandler = UFStatus + .getHandler(RegistryDataAccessService.class); + + /** Data access object for registry objects */ + private RegistryObjectDao registryObjectDao; + + /** Lifecyclemanager */ + private LifecycleManager lcm; + + @GET + @Path("/rest/dataAccess/getRegistryObjectIds/{objectType}") + public RestCollectionResponse getRegistryObjectIdsOfType( + @PathParam("objectType") String objectType) { + statusHandler.info("Getting registry object ids of type [" + objectType + + "]..."); + RestCollectionResponse response = new RestCollectionResponse(); + response.setPayload(registryObjectDao + .getRegistryObjectIdsOfType(objectType)); + return response; + } + + @GET + @Path("/rest/dataAccess/removeSubscriptionsFor/{siteId}") + public void removeSubscriptionsForSite(@PathParam("siteId") String siteId) { + statusHandler.info("Removing subscriptions for: " + siteId); + List subscriptions = registryObjectDao + .executeHQLQuery( + "from SubscriptionType sub where sub.owner=:siteId", + "siteId", siteId); + if (subscriptions.isEmpty()) { + statusHandler.info("No subscriptions present for site: " + siteId); + } else { + List deliveryInfoKeys = new ArrayList(); + ObjectRefListType refList = new ObjectRefListType(); + for (SubscriptionType sub : subscriptions) { + refList.getObjectRef().add(new ObjectRefType(sub.getId())); + for (DeliveryInfoType deliveryInfo : sub.getDeliveryInfo()) { + deliveryInfoKeys.add(deliveryInfo.getKey()); + } + } + RemoveObjectsRequest removeRequest = new RemoveObjectsRequest(); + removeRequest.setId("Remote subscription removal request for " + + siteId); + removeRequest.setComment("Removal of remote subscriptions for " + + siteId); + removeRequest.setObjectRefList(refList); + try { + RegistryResponseType response = lcm + .removeObjects(removeRequest); + if (response.getStatus().equals(RegistryResponseStatus.SUCCESS)) { + registryObjectDao + .executeHQLStatement( + "DELETE FROM DeliveryInfoType deliveryInfo where deliveryInfo.key in (:keys)", + "keys", deliveryInfoKeys); + statusHandler + .info("Successfully removed subscriptions for site " + + siteId); + } else { + statusHandler + .info("Failed to remove subscriptions for site " + + siteId); + } + } catch (Exception e) { + throw new RegistryException( + "Error removing subscriptions for site " + siteId, e); + } + + } + } + + public void setRegistryObjectDao(RegistryObjectDao registryObjectDao) { + this.registryObjectDao = registryObjectDao; + } + + public void setLcm(LifecycleManager lcm) { + this.lcm = lcm; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/web/webServiceBeans.xml b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/web/webServiceBeans.xml index edaae04b7f..47e13c8468 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/web/webServiceBeans.xml +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/web/webServiceBeans.xml @@ -88,6 +88,7 @@ +