This project has retired. For details please refer to its Attic page.
JUDDIApiImpl.java

JUDDIApiImpl.java

/*
 * Copyright 2001-2008 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.apache.juddi.api.impl;

import java.io.StringWriter;
import java.math.BigInteger;
import java.rmi.RemoteException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.ws.Holder;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.juddi.ClassUtil;
import static org.apache.juddi.api.impl.JUDDIApiImpl.sub;
import org.apache.juddi.api.util.JUDDIQuery;
import org.apache.juddi.api.util.QueryStatus;
import org.apache.juddi.api_v3.AdminSaveBusinessWrapper;
import org.apache.juddi.api_v3.AdminSaveTModelWrapper;
import org.apache.juddi.api_v3.Clerk;
import org.apache.juddi.api_v3.ClerkDetail;
import org.apache.juddi.api_v3.ClerkList;
import org.apache.juddi.api_v3.ClientSubscriptionInfoDetail;
import org.apache.juddi.api_v3.DeleteClerk;
import org.apache.juddi.api_v3.DeleteClientSubscriptionInfo;
import org.apache.juddi.api_v3.DeleteNode;
import org.apache.juddi.api_v3.DeletePublisher;
import org.apache.juddi.api_v3.GetAllClientSubscriptionInfoDetail;
import org.apache.juddi.api_v3.GetAllPublisherDetail;
import org.apache.juddi.api_v3.GetClientSubscriptionInfoDetail;
import org.apache.juddi.api_v3.GetEntityHistoryMessageRequest;
import org.apache.juddi.api_v3.GetEntityHistoryMessageResponse;
import org.apache.juddi.api_v3.GetFailedReplicationChangeRecordsMessageRequest;
import org.apache.juddi.api_v3.GetFailedReplicationChangeRecordsMessageResponse;
import org.apache.juddi.api_v3.GetPublisherDetail;
import org.apache.juddi.api_v3.NodeDetail;
import org.apache.juddi.api_v3.NodeList;
import org.apache.juddi.api_v3.PublisherDetail;
import org.apache.juddi.api_v3.SaveClerk;
import org.apache.juddi.api_v3.SaveClientSubscriptionInfo;
import org.apache.juddi.api_v3.SaveNode;
import org.apache.juddi.api_v3.SavePublisher;
import org.apache.juddi.api_v3.SubscriptionWrapper;
import org.apache.juddi.api_v3.SyncSubscription;
import org.apache.juddi.api_v3.SyncSubscriptionDetail;
import org.apache.juddi.config.AppConfig;
import org.apache.juddi.config.PersistenceManager;
import org.apache.juddi.config.Property;
import org.apache.juddi.mapping.MappingApiToModel;
import org.apache.juddi.mapping.MappingModelToApi;
import org.apache.juddi.model.BusinessEntity;
import org.apache.juddi.model.ChangeRecord;
import org.apache.juddi.model.ClientSubscriptionInfo;
import org.apache.juddi.model.Node;
import org.apache.juddi.model.Publisher;
import org.apache.juddi.model.ReplicationConfiguration;
import org.apache.juddi.model.Tmodel;
import org.apache.juddi.model.UddiEntityPublisher;
import org.apache.juddi.replication.ReplicationNotifier;
import org.apache.juddi.subscription.NotificationList;
import org.apache.juddi.subscription.notify.TemporaryMailContainer;
import org.apache.juddi.subscription.notify.USERFRIENDLYSMTPNotifier;
import org.apache.juddi.v3.client.transport.Transport;
import org.apache.juddi.v3.error.ErrorMessage;
import org.apache.juddi.v3.error.FatalErrorException;
import org.apache.juddi.v3.error.InvalidKeyPassedException;
import org.apache.juddi.v3.error.InvalidValueException;
import org.apache.juddi.v3.error.UserMismatchException;
import org.apache.juddi.v3_service.JUDDIApiPortType;
import org.apache.juddi.validation.ValidateClerk;
import org.apache.juddi.validation.ValidateClientSubscriptionInfo;
import org.apache.juddi.validation.ValidateNode;
import org.apache.juddi.validation.ValidatePublish;
import org.apache.juddi.validation.ValidatePublisher;
import org.apache.juddi.validation.ValidateReplication;
import org.uddi.api_v3.AuthToken;
import org.uddi.api_v3.BusinessInfo;
import org.uddi.api_v3.BusinessInfos;
import org.uddi.api_v3.Contact;
import org.uddi.api_v3.DeleteTModel;
import org.uddi.api_v3.DispositionReport;
import org.uddi.api_v3.GetRegisteredInfo;
import org.uddi.api_v3.InfoSelection;
import org.uddi.api_v3.PersonName;
import org.uddi.api_v3.RegisteredInfo;
import org.uddi.api_v3.Result;
import org.uddi.api_v3.SaveBusiness;
import org.uddi.api_v3.SaveTModel;
import org.uddi.api_v3.TModelInfo;
import org.uddi.api_v3.TModelInfos;
import org.uddi.repl_v3.ChangeRecords;
import org.uddi.repl_v3.CommunicationGraph;
import org.uddi.repl_v3.Operator;
import org.uddi.repl_v3.OperatorStatusType;
import org.uddi.sub_v3.GetSubscriptionResults;
import org.uddi.sub_v3.Subscription;
import org.uddi.sub_v3.SubscriptionResultsList;
import org.uddi.v3_service.DispositionReportFaultMessage;
import org.uddi.v3_service.UDDISubscriptionPortType;

/**
 * Implements the jUDDI API service. These methods are outside of the UDDI spec
 * and are specific to jUDDI. They are primarily used for administrative
 * functions.
 *
 * @author <a href="mailto:jfaath@apache.org">Jeff Faath</a>
 * @author <a href="mailto:kstam@apache.org">Kurt T Stam</a>
 * @author <a href="mailto:alexoree@apache.org">Alex O'Ree</a>
 */
@WebService(serviceName = "JUDDIApiService",
        endpointInterface = "org.apache.juddi.v3_service.JUDDIApiPortType",
        targetNamespace = "urn:juddi-apache-org:v3_service"
        //, wsdlLocation = "classpath:/juddi_api_v1.wsdl"
)
public class JUDDIApiImpl extends AuthenticatedService implements JUDDIApiPortType {

        private Log log = LogFactory.getLog(this.getClass());
        private UDDIServiceCounter serviceCounter = ServiceCounterLifecycleResource.getServiceCounter(this.getClass());

        /**
         * Saves publisher(s) to the persistence layer. This method is specific
         * to jUDDI. Administrative privilege required.
         *
         * @param body
         * @return PublisherDetail
         * @throws DispositionReportFaultMessage
         */
        public PublisherDetail savePublisher(SavePublisher body)
                throws DispositionReportFaultMessage {
                long startTime = System.currentTimeMillis();
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, body.getAuthInfo());

                        new ValidatePublish(publisher).validateSavePublisher(em, body);

                        PublisherDetail result = new PublisherDetail();

                        List<org.apache.juddi.api_v3.Publisher> apiPublisherList = body.getPublisher();
                        for (org.apache.juddi.api_v3.Publisher apiPublisher : apiPublisherList) {

                                org.apache.juddi.model.Publisher modelPublisher = new org.apache.juddi.model.Publisher();

                                MappingApiToModel.mapPublisher(apiPublisher, modelPublisher);

                                Object existingUddiEntity = em.find(modelPublisher.getClass(), modelPublisher.getAuthorizedName());
                                if (existingUddiEntity != null) {
                                        em.remove(existingUddiEntity);
                                }

                                em.persist(modelPublisher);

                                result.getPublisher().add(apiPublisher);
                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.SAVE_PUBLISHER,
                                QueryStatus.SUCCESS, procTime);
                        return result;
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.SAVE_PUBLISHER,
                                QueryStatus.FAILED, procTime);
                        throw drfm;
                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }
        }

        /**
         * Deletes publisher(s) from the persistence layer. This method is
         * specific to jUDDI. Administrative privilege required. Also removes
         * all registered business entities of the user and marks all created
         * tModels as "deleted" but not does not remove the tModel from
         * persistence. All subscriptions are also destroyed
         *
         * @param body
         * @throws DispositionReportFaultMessage
         */
        @Override
        public void deletePublisher(DeletePublisher body)
                throws DispositionReportFaultMessage {
                long startTime = System.currentTimeMillis();
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, body.getAuthInfo());

                        new ValidatePublish(publisher).validateDeletePublisher(em, body);

                        List<String> entityKeyList = body.getPublisherId();
                        List<Publisher> deletedPubs = new ArrayList<Publisher>();
                        for (String entityKey : entityKeyList) {
                                Publisher obj = em.find(org.apache.juddi.model.Publisher.class, entityKey);
                                deletedPubs.add(obj);
                                //get an authtoken for this publisher so that we can get its registeredInfo
                                UDDISecurityImpl security = new UDDISecurityImpl();
                                AuthToken authToken = security.getAuthToken(entityKey);

                                GetRegisteredInfo r = new GetRegisteredInfo();
                                r.setAuthInfo(authToken.getAuthInfo());
                                r.setInfoSelection(InfoSelection.ALL);

                                log.info("removing all businesses owned by publisher " + entityKey + ".");
                                UDDIPublicationImpl publish = new UDDIPublicationImpl();
                                RegisteredInfo registeredInfo = publish.getRegisteredInfo(r);
                                BusinessInfos businessInfos = registeredInfo.getBusinessInfos();
                                if (businessInfos != null && businessInfos.getBusinessInfo() != null) {
                                        Iterator<BusinessInfo> iter = businessInfos.getBusinessInfo().iterator();
                                        while (iter.hasNext()) {
                                                BusinessInfo businessInfo = iter.next();
                                                Object business = em.find(org.apache.juddi.model.BusinessEntity.class, businessInfo.getBusinessKey());
                                                em.remove(business);
                                        }
                                }

                                log.info("mark all tmodels for publisher " + entityKey + " as deleted.");
                                TModelInfos tmodelInfos = registeredInfo.getTModelInfos();
                                if (tmodelInfos != null && tmodelInfos.getTModelInfo() != null) {
                                        Iterator<TModelInfo> iter = tmodelInfos.getTModelInfo().iterator();
                                        while (iter.hasNext()) {
                                                TModelInfo tModelInfo = iter.next();
                                                Tmodel tmodel = (Tmodel) em.find(org.apache.juddi.model.Tmodel.class, tModelInfo.getTModelKey());
                                                tmodel.setDeleted(true);
                                                em.persist(tmodel);
                                        }
                                }
                                log.info("remove all persisted AuthTokens for publisher " + entityKey + ".");
                                Query q1 = em.createQuery("DELETE FROM AuthToken auth WHERE auth.authorizedName = ?1");
                                q1.setParameter(1, entityKey);
                                q1.executeUpdate();
                                log.info("remove all subscriptions for publisher " + entityKey + ".");
                                q1 = em.createQuery("DELETE FROM Subscription s WHERE s.authorizedName = ?1");
                                q1.setParameter(1, entityKey);
                                q1.executeUpdate();

                                log.info("removing publisher " + entityKey + ".");
                                //delete the publisher
                                em.remove(obj);
                        }

                        tx.commit();
                        for (Publisher p: deletedPubs){
                                USERFRIENDLYSMTPNotifier.notifyAccountDeleted(new TemporaryMailContainer(null, p, (Publisher) publisher));
                        }
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.DELETE_PUBLISHER,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.DELETE_PUBLISHER,
                                QueryStatus.FAILED, procTime);
                        throw drfm;
                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }
        }

        /**
         * Retrieves publisher(s) from the persistence layer. This method is
         * specific to jUDDI. Administrative privilege required.
         *
         * @param body
         * @return PublisherDetail
         * @throws DispositionReportFaultMessage
         */
        public PublisherDetail getPublisherDetail(GetPublisherDetail body)
                throws DispositionReportFaultMessage {
                long startTime = System.currentTimeMillis();
                new ValidatePublisher(null).validateGetPublisherDetail(body);

                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        this.getEntityPublisher(em, body.getAuthInfo());

                        PublisherDetail result = new PublisherDetail();

                        List<String> publisherIdList = body.getPublisherId();
                        for (String publisherId : publisherIdList) {
                                org.apache.juddi.model.Publisher modelPublisher = null;
                                try {
                                        modelPublisher = em.find(org.apache.juddi.model.Publisher.class, publisherId);
                                } catch (ClassCastException e) {
                                }
                                if (modelPublisher == null) {
                                        throw new InvalidKeyPassedException(new ErrorMessage("errors.invalidkey.PublisherNotFound", publisherId));
                                }

                                org.apache.juddi.api_v3.Publisher apiPublisher = new org.apache.juddi.api_v3.Publisher();

                                MappingModelToApi.mapPublisher(modelPublisher, apiPublisher);

                                result.getPublisher().add(apiPublisher);
                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_PUBLISHER_DETAIL,
                                QueryStatus.SUCCESS, procTime);
                        return result;
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_PUBLISHER_DETAIL,
                                QueryStatus.FAILED, procTime);
                        throw drfm;
                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

        }

        /**
         * Retrieves all publisher from the persistence layer. This method is
         * specific to jUDDI. Administrative privilege required. Use caution
         * when calling, result set is not bound. If there are many publishers,
         * it is possible to have a result set that is too large
         *
         * @param body
         * @return PublisherDetail
         * @throws DispositionReportFaultMessage
         * @throws RemoteException
         */
        @SuppressWarnings("unchecked")
        public PublisherDetail getAllPublisherDetail(GetAllPublisherDetail body)
                throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                new ValidatePublisher(null).validateGetAllPublisherDetail(body);

                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        this.getEntityPublisher(em, body.getAuthInfo());

                        PublisherDetail result = new PublisherDetail();

                        Query query = em.createQuery("SELECT p from Publisher as p");
                        List<Publisher> modelPublisherList = query.getResultList();

                        for (Publisher modelPublisher : modelPublisherList) {

                                org.apache.juddi.api_v3.Publisher apiPublisher = new org.apache.juddi.api_v3.Publisher();

                                MappingModelToApi.mapPublisher(modelPublisher, apiPublisher);

                                result.getPublisher().add(apiPublisher);
                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_PUBLISHER_DETAIL,
                                QueryStatus.SUCCESS, procTime);
                        return result;
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_PUBLISHER_DETAIL,
                                QueryStatus.FAILED, procTime);
                        throw drfm;
                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }
        }

        /**
         * Completely deletes a tModel from the persistence layer.
         * Administrative privilege required. All entities that reference this
         * tModel will no longer be able to use the tModel if jUDDI Option
         * Enforce referential Integrity is enabled.<br>
         * Required permission, you must be am administrator
         * {@link Property#JUDDI_ENFORCE_REFERENTIAL_INTEGRITY}. In addition,
         * tModels that are owned by another node via replication cannot be
         * deleted using this method and will throw an exception
         *
         *
         * @param body
         * @throws DispositionReportFaultMessage
         */
        @Override
        public void adminDeleteTModel(DeleteTModel body)
                throws DispositionReportFaultMessage {
                long startTime = System.currentTimeMillis();
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, body.getAuthInfo());

                        new ValidatePublish(publisher).validateAdminDeleteTModel(em, body);

                        //TODO if referiental integrity is turned on, check to see if this is referenced anywhere and prevent the delete
                        List<ChangeRecord> changes = new ArrayList<ChangeRecord>();
                        List<String> entityKeyList = body.getTModelKey();
                        for (String entityKey : entityKeyList) {
                                org.apache.juddi.model.Tmodel obj = em.find(org.apache.juddi.model.Tmodel.class, entityKey);

                                if (obj == null) {
                                        throw new InvalidKeyPassedException(new ErrorMessage("errors.invalidkey.TModelNotFound", entityKey));
                                }
                                if (!obj.getNodeId().equals(getNode())) {
                                        throw new InvalidKeyPassedException(new ErrorMessage("errors.invalidkey.TModelNodeOwner", entityKey + " this node " + getNode() + " owning node " + obj.getNodeId()));
                                }
                                em.remove(obj);
                                changes.add(UDDIPublicationImpl.getChangeRecord_deleteTModelDelete(entityKey, getNode(), df));

                        }

                        tx.commit();
                        for (ChangeRecord cr : changes) {
                                ReplicationNotifier.enqueue(cr);
                        }
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_DELETE_TMODEL,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_DELETE_TMODEL,
                                QueryStatus.FAILED, procTime);
                        throw drfm;
                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }
        }

        /**
         * Delete's a client's subscription information. This is typically used
         * for server to server subscriptions Administrative privilege required.
         *
         * @param body
         * @throws DispositionReportFaultMessage
         * @throws RemoteException
         */
        public void deleteClientSubscriptionInfo(DeleteClientSubscriptionInfo body)
                throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, body.getAuthInfo());

                        new ValidateClientSubscriptionInfo(publisher).validateDeleteClientSubscriptionInfo(em, body);

                        List<String> entityKeyList = body.getSubscriptionKey();
                        for (String entityKey : entityKeyList) {
                                Object obj = em.find(org.apache.juddi.model.ClientSubscriptionInfo.class, entityKey);
                                em.remove(obj);
                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.DELETE_CLIENT_SUB,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.DELETE_CLIENT_SUB,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

        }

        /**
         * Adds client subscription information. This effectively links a server
         * to serverr subscription to clerk Administrative privilege required.
         *
         * @param body
         * @return ClientSubscriptionInfoDetail
         * @throws DispositionReportFaultMessage
         * @throws RemoteException
         */
        public ClientSubscriptionInfoDetail saveClientSubscriptionInfo(SaveClientSubscriptionInfo body)
                throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, body.getAuthInfo());

                        new ValidateClientSubscriptionInfo(publisher).validateSaveClientSubscriptionInfo(em, body);

                        ClientSubscriptionInfoDetail result = new ClientSubscriptionInfoDetail();

                        List<org.apache.juddi.api_v3.ClientSubscriptionInfo> apiClientSubscriptionInfoList = body.getClientSubscriptionInfo();
                        for (org.apache.juddi.api_v3.ClientSubscriptionInfo apiClientSubscriptionInfo : apiClientSubscriptionInfoList) {

                                org.apache.juddi.model.ClientSubscriptionInfo modelClientSubscriptionInfo = new org.apache.juddi.model.ClientSubscriptionInfo();

                                MappingApiToModel.mapClientSubscriptionInfo(apiClientSubscriptionInfo, modelClientSubscriptionInfo);

                                Object existingUddiEntity = em.find(modelClientSubscriptionInfo.getClass(), modelClientSubscriptionInfo.getSubscriptionKey());
                                if (existingUddiEntity != null) {
                                        em.remove(existingUddiEntity);
                                }

                                em.persist(modelClientSubscriptionInfo);

                                result.getClientSubscriptionInfo().add(apiClientSubscriptionInfo);
                        }

                        tx.commit();

                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.SAVE_CLIENT_SUB,
                                QueryStatus.SUCCESS, procTime);
                        return result;
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.SAVE_CLIENT_SUB,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }
        }

        /**
         * Gets all client subscription information. This is used for server to
         * server subscriptions Administrative privilege required.
         *
         * @param body
         * @return ClientSubscriptionInfoDetail
         * @throws DispositionReportFaultMessage
         */
        @SuppressWarnings("unchecked")
        public ClientSubscriptionInfoDetail getAllClientSubscriptionInfoDetail(GetAllClientSubscriptionInfoDetail body)
                throws DispositionReportFaultMessage {
                long startTime = System.currentTimeMillis();
                new ValidateClientSubscriptionInfo(null).validateGetAllClientSubscriptionDetail(body);

                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        this.getEntityPublisher(em, body.getAuthInfo());

                        ClientSubscriptionInfoDetail result = new ClientSubscriptionInfoDetail();

                        Query query = em.createQuery("SELECT cs from ClientSubscriptionInfo as cs");
                        List<org.apache.juddi.model.ClientSubscriptionInfo> modelClientSubscriptionInfoList = query.getResultList();

                        for (ClientSubscriptionInfo modelClientSubscriptionInfo : modelClientSubscriptionInfoList) {

                                org.apache.juddi.api_v3.ClientSubscriptionInfo apiClientSubscriptionInfo = new org.apache.juddi.api_v3.ClientSubscriptionInfo();

                                MappingModelToApi.mapClientSubscriptionInfo(modelClientSubscriptionInfo, apiClientSubscriptionInfo, em);

                                result.getClientSubscriptionInfo().add(apiClientSubscriptionInfo);
                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_CLIENT_SUB,
                                QueryStatus.SUCCESS, procTime);
                        return result;
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_CLIENT_SUB,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

        }

        /**
         * Retrieves clientSubscriptionKey(s) from the persistence layer. This
         * method is specific to jUDDI. Used for server to server subscriptions
         * Administrative privilege required.
         *
         * @param body
         * @return ClientSubscriptionInfoDetail
         * @throws DispositionReportFaultMessage
         */
        public ClientSubscriptionInfoDetail getClientSubscriptionInfoDetail(GetClientSubscriptionInfoDetail body)
                throws DispositionReportFaultMessage {
                long startTime = System.currentTimeMillis();
                new ValidateClientSubscriptionInfo(null).validateGetClientSubscriptionInfoDetail(body);

                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        this.getEntityPublisher(em, body.getAuthInfo());

                        ClientSubscriptionInfoDetail result = new ClientSubscriptionInfoDetail();

                        List<String> subscriptionKeyList = body.getClientSubscriptionKey();
                        for (String subscriptionKey : subscriptionKeyList) {

                                org.apache.juddi.model.ClientSubscriptionInfo modelClientSubscriptionInfo = null;

                                try {
                                        modelClientSubscriptionInfo = em.find(org.apache.juddi.model.ClientSubscriptionInfo.class, subscriptionKey);
                                } catch (ClassCastException e) {
                                }
                                if (modelClientSubscriptionInfo == null) {
                                        throw new InvalidKeyPassedException(new ErrorMessage("errors.invalidkey.SubscripKeyNotFound", subscriptionKey));
                                }

                                org.apache.juddi.api_v3.ClientSubscriptionInfo apiClientSubscriptionInfo = new org.apache.juddi.api_v3.ClientSubscriptionInfo();

                                MappingModelToApi.mapClientSubscriptionInfo(modelClientSubscriptionInfo, apiClientSubscriptionInfo, em);

                                result.getClientSubscriptionInfo().add(apiClientSubscriptionInfo);
                        }

                        tx.commit();

                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_CLIENT_SUB,
                                QueryStatus.SUCCESS, procTime);
                        return result;
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_CLIENT_SUB,
                                QueryStatus.FAILED, procTime);
                        throw drfm;
                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

        }

        /**
         * Saves clerk(s) to the persistence layer. This method is specific to
         * jUDDI. This is used for server to server subscriptions and for future
         * use with replication. Administrative privilege required.
         *
         * @param body
         * @return ClerkDetail
         * @throws DispositionReportFaultMessage
         */
        @Override
        public ClerkDetail saveClerk(SaveClerk body)
                throws DispositionReportFaultMessage {
                long startTime = System.currentTimeMillis();
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, body.getAuthInfo());

                        new ValidateClerk(publisher).validateSaveClerk(em, body);

                        ClerkDetail result = new ClerkDetail();

                        List<org.apache.juddi.api_v3.Clerk> apiClerkList = body.getClerk();;
                        for (org.apache.juddi.api_v3.Clerk apiClerk : apiClerkList) {

                                org.apache.juddi.model.Clerk modelClerk = new org.apache.juddi.model.Clerk();

                                MappingApiToModel.mapClerk(apiClerk, modelClerk);
                                org.apache.juddi.model.Node node2 = em.find(org.apache.juddi.model.Node.class, apiClerk.getNode().getName());
                                if (node2 == null) {
                                        //it doesn't exist yet
                                        node2 = new Node();
                                        MappingApiToModel.mapNode(apiClerk.getNode(), node2);
                                        em.persist(node2);
                                }

                                modelClerk.setNode(node2.getName());
                                Object existingUddiEntity = em.find(modelClerk.getClass(), modelClerk.getClerkName());
                                if (existingUddiEntity != null) {

                                        em.merge(modelClerk);
                                } else {
                                        em.persist(modelClerk);
                                }

                                result.getClerk().add(apiClerk);
                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.SAVE_CLERK,
                                QueryStatus.SUCCESS, procTime);
                        return result;
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.SAVE_CLERK,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }
        }

        /**
         * Saves nodes(s) to the persistence layer. This method is specific to
         * jUDDI. Administrative privilege required. This is used for server to
         * server subscriptions and for future use with replication.
         * Administrative privilege required.
         *
         * @param body
         * @return NodeDetail
         * @throws DispositionReportFaultMessage
         */
        public NodeDetail saveNode(SaveNode body)
                throws DispositionReportFaultMessage {
                long startTime = System.currentTimeMillis();
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, body.getAuthInfo());

                        new ValidateNode(publisher).validateSaveNode(em, body);

                        NodeDetail result = new NodeDetail();

                        List<org.apache.juddi.api_v3.Node> apiNodeList = body.getNode();
                        for (org.apache.juddi.api_v3.Node apiNode : apiNodeList) {

                                org.apache.juddi.model.Node modelNode = new org.apache.juddi.model.Node();

                                MappingApiToModel.mapNode(apiNode, modelNode);

                                Object existingUddiEntity = em.find(modelNode.getClass(), modelNode.getName());
                                if (existingUddiEntity != null) {
                                        em.merge(modelNode);
                                } else {
                                        em.persist(modelNode);
                                }

                                result.getNode().add(apiNode);
                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.SAVE_NODE,
                                QueryStatus.SUCCESS, procTime);
                        return result;
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.SAVE_NODE,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }
        }

        /**
         * Instructs the registry to perform a synchronous subscription
         * response.
         *
         * @param body
         * @return SyncSubscriptionDetail
         * @throws DispositionReportFaultMessage
         * @throws RemoteException
         */
        @SuppressWarnings("unchecked")
        @Override
        public SyncSubscriptionDetail invokeSyncSubscription(
                SyncSubscription body) throws DispositionReportFaultMessage,
                RemoteException {
                long startTime = System.currentTimeMillis();
                //validate
                SyncSubscriptionDetail syncSubscriptionDetail = new SyncSubscriptionDetail();

                Map<String, org.apache.juddi.api_v3.ClientSubscriptionInfo> clientSubscriptionInfoMap
                        = new HashMap<String, org.apache.juddi.api_v3.ClientSubscriptionInfo>();
                //find the clerks to go with these subscriptions
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        this.getEntityPublisher(em, body.getAuthInfo());
                        for (GetSubscriptionResults getSubscriptionResult : body.getGetSubscriptionResultsList()) {
                                String subscriptionKey = getSubscriptionResult.getSubscriptionKey();
                                org.apache.juddi.model.ClientSubscriptionInfo modelClientSubscriptionInfo = null;

                                try {
                                        modelClientSubscriptionInfo = em.find(org.apache.juddi.model.ClientSubscriptionInfo.class, subscriptionKey);
                                } catch (ClassCastException e) {
                                }
                                if (modelClientSubscriptionInfo == null) {
                                        throw new InvalidKeyPassedException(new ErrorMessage("errors.invalidkey.SubscripKeyNotFound", subscriptionKey));
                                }
                                org.apache.juddi.api_v3.ClientSubscriptionInfo apiClientSubscriptionInfo = new org.apache.juddi.api_v3.ClientSubscriptionInfo();
                                MappingModelToApi.mapClientSubscriptionInfo(modelClientSubscriptionInfo, apiClientSubscriptionInfo, em);
                                clientSubscriptionInfoMap.put(apiClientSubscriptionInfo.getSubscriptionKey(), apiClientSubscriptionInfo);
                        }

                        tx.commit();
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.INVOKE_SYNCSUB,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

                for (GetSubscriptionResults getSubscriptionResult : body.getGetSubscriptionResultsList()) {
                        try {
                                String subscriptionKey = getSubscriptionResult.getSubscriptionKey();
                                Clerk fromClerk = clientSubscriptionInfoMap.get(subscriptionKey).getFromClerk();
                                Clerk toClerk = clientSubscriptionInfoMap.get(subscriptionKey).getToClerk();
                                String clazz = fromClerk.getNode().getProxyTransport();
                                Class<?> transportClass = ClassUtil.forName(clazz, this.getClass());
                                Transport transport = (Transport) transportClass.getConstructor(String.class
                                ).newInstance(fromClerk.getNode().getName());
                                UDDISubscriptionPortType subscriptionService = transport.getUDDISubscriptionService(fromClerk.getNode().getSubscriptionUrl());
                                SubscriptionResultsList list = subscriptionService.getSubscriptionResults(getSubscriptionResult);

                                JAXBContext context = JAXBContext.newInstance(list.getClass());
                                Marshaller marshaller = context.createMarshaller();
                                StringWriter sw = new StringWriter();

                                marshaller.marshal(list, sw);

                                log.info(
                                        "Notification received by UDDISubscriptionListenerService : " + sw.toString());

                                NotificationList<String> nl = NotificationList.getInstance();

                                nl.getNotifications()
                                        .add(sw.toString());

                                //update the registry with the notification list.
                                XRegisterHelper.handle(fromClerk, toClerk, list);

                                syncSubscriptionDetail.getSubscriptionResultsList()
                                        .add(list);
                        } catch (Exception ce) {
                                log.error(ce.getMessage(), ce);
                                long procTime = System.currentTimeMillis() - startTime;
                                serviceCounter.update(JUDDIQuery.SAVE_NODE,
                                        QueryStatus.FAILED, procTime);
                                if (ce instanceof DispositionReportFaultMessage) {
                                        throw (DispositionReportFaultMessage) ce;
                                }
                                if (ce instanceof RemoteException) {
                                        DispositionReportFaultMessage x = new FatalErrorException(new ErrorMessage("errors.subscriptionnotifier.client", ce.getMessage()));
                                        throw x;
                                }
                        }
                }
                //for now sending a clean object back

                long procTime = System.currentTimeMillis() - startTime;
                serviceCounter.update(JUDDIQuery.INVOKE_SYNCSUB,
                        QueryStatus.SUCCESS, procTime);
                return syncSubscriptionDetail;
        }

        @Override
        public NodeList getAllNodes(String authInfo) throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                NodeList r = new NodeList();

                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, authInfo);

                        new ValidatePublish(publisher).validateGetAllNodes();

                        StringBuilder sql = new StringBuilder();
                        sql.append("select distinct c from Node c ");
                        sql.toString();
                        Query qry = em.createQuery(sql.toString());
                        List<org.apache.juddi.model.Node> resultList = qry.getResultList();
                        for (int i = 0; i < resultList.size(); i++) {
                                org.apache.juddi.api_v3.Node api = new org.apache.juddi.api_v3.Node();
                                MappingModelToApi.mapNode(resultList.get(i), api);
                                r.getNode().add(api);

                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_NODES,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_NODES,
                                QueryStatus.FAILED, procTime);
                        throw drfm;
                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

                return r;
        }

        @Override
        public ClerkList getAllClerks(String authInfo) throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                ClerkList ret = new ClerkList();
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, authInfo);

                        new ValidatePublish(publisher).validateGetAllNodes();

                        StringBuilder sql = new StringBuilder();
                        sql.append("select distinct c from Clerk c ");
                        sql.toString();
                        Query qry = em.createQuery(sql.toString());
                        List<org.apache.juddi.model.Clerk> resultList = qry.getResultList();
                        for (int i = 0; i < resultList.size(); i++) {
                                Clerk api = new Clerk();
                                MappingModelToApi.mapClerk(resultList.get(i), api, em);
                                ret.getClerk().add(api);

                        }
                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_CLERKS,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_CLERKS,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

                return ret;

        }

        @Override
        public void deleteNode(DeleteNode req) throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                boolean found = false;
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();
                        //TODO if the given node is in the replication config, prevent deletion
                        UddiEntityPublisher publisher = this.getEntityPublisher(em, req.getAuthInfo());
                        new ValidatePublish(publisher).validateDeleteNode(em, req, getReplicationNodes(req.getAuthInfo()));

                        org.apache.juddi.model.Node existingUddiEntity = em.find(org.apache.juddi.model.Node.class, req.getNodeID());
                        if (existingUddiEntity != null) {

                                //cascade delete all clerks tied to this node, confirm that it works
                                Query createQuery = em.createQuery("delete from Clerk c where c.node = :nodename");
                                createQuery.setParameter("nodename", req.getNodeID());
                                createQuery.executeUpdate();

                                em.remove(existingUddiEntity);
                                found = true;
                        } else {
                                throw new InvalidKeyPassedException(new ErrorMessage("errors.deleteNode.NotFound"));
                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.DELETE_NODE,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.DELETE_NODE,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

                if (!found) {

                        throw new InvalidKeyPassedException(new ErrorMessage("errors.deleteNode.NotFound", req.getNodeID()));
                }
        }

        @Override
        public void deleteClerk(DeleteClerk req) throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                boolean found = false;
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, req.getAuthInfo());

                        new ValidatePublish(publisher).validateDeleteClerk(em, req);

                        org.apache.juddi.model.Clerk existingUddiEntity = em.find(org.apache.juddi.model.Clerk.class, req.getClerkID());
                        if (existingUddiEntity
                                != null) {
                                em.remove(existingUddiEntity);
                                found = true;
                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.DELETE_CLERK,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.DELETE_CLERK,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

                if (!found) {
                        throw new InvalidKeyPassedException(new ErrorMessage("errors.deleteClerk.NotFound"));
                }

        }

        /*
         * enables tmodel owners to setup valid values for tmodel instance infos
         * to use?
         *
         * @param authInfo
         * @param values
         * @return
         * @throws DispositionReportFaultMessage
         
         @Override
         public DispositionReport setAllValidValues(String authInfo, List<ValidValues> values) throws DispositionReportFaultMessage, RemoteException {
         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
         /*  EntityManager em = PersistenceManager.getEntityManager();
         UddiEntityPublisher entityPublisher = getEntityPublisher(em, authInfo);

         new ValidateValueSetValidation(entityPublisher).validateSetAllValidValues(values);

         EntityTransaction tx = em.getTransaction();
         try {

         // is this tModel used anywhere?, if so, validate all instances against the new rule?
         tx.begin();

         //each tmodel/value set
         for (int i = 0; i < values.size(); i++) {
         //remove any existing references to the key
         ValueSetValues find = em.find(ValueSetValues.class, values.get(i).getTModekKey());

         if (find != null) {
         find.setValidatorClass(values.get(i).getValidationClass());
         em.persist(find);

         } else {
         org.apache.juddi.model.ValueSetValues vv = new ValueSetValues();
         vv.setTModelKey(values.get(i).getTModekKey());
         vv.setValidatorClass(values.get(i).getValidationClass());
         em.persist(vv);
         }
         }

         tx.commit();
         } finally {
         if (tx.isActive()) {
         tx.rollback();
         }
         em.close();
         }
         DispositionReport r = new DispositionReport();
         r.getResult().add(new Result());
         return r;
         }*/
        @Override
        public void adminDeleteSubscription(String authInfo, List<String> subscriptionKey) throws DispositionReportFaultMessage, RemoteException {

                long startTime = System.currentTimeMillis();

                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher requestor = this.getEntityPublisher(em, authInfo);
                        if (!((Publisher) requestor).isAdmin()) {
                                throw new UserMismatchException(new ErrorMessage("errors.AdminReqd"));
                        }
                        //new ValidateSubscription(publisher).validateDeleteSubscription(em, body);
                        List<TemporaryMailContainer> notifications = new ArrayList<TemporaryMailContainer>();
                        List<String> subscriptionKeyList = subscriptionKey;
                        for (String key : subscriptionKeyList) {
                                if (key != null && key.length() > 0) {
                                        org.apache.juddi.model.Subscription obj = em.find(org.apache.juddi.model.Subscription.class, key);
                                        Publisher publisher = em.find(Publisher.class, obj.getAuthorizedName());
                                        notifications.add(new TemporaryMailContainer(obj, publisher, (Publisher) requestor));
                                        em.remove(obj);
                                }
                        }

                        tx.commit();
                        for (TemporaryMailContainer t : notifications) {
                                USERFRIENDLYSMTPNotifier.notifySubscriptionDeleted(t);
                        }
                        notifications.clear();
                        notifications = null;
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_DELETE_SUB,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_DELETE_SUB,
                                QueryStatus.FAILED, procTime);
                        throw drfm;
                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

        }

        @Override
        public DispositionReport adminSaveBusiness(String authInfo, List<AdminSaveBusinessWrapper> values) throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();
                        UddiEntityPublisher requestor = this.getEntityPublisher(em, authInfo);
                        if (!((Publisher) requestor).isAdmin()) {
                                throw new UserMismatchException(new ErrorMessage("errors.AdminReqd"));
                        }

                        for (int i = 0; i < values.size(); i++) {
                                //impersonate the user
                                AuthToken authToken = sec.getAuthToken(values.get(i).getPublisherID());

                                SaveBusiness stm = new SaveBusiness();

                                stm.setAuthInfo(authToken.getAuthInfo());
                                stm.getBusinessEntity().addAll(values.get(i).getBusinessEntity());
                                pub.saveBusiness(stm);
                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_SAVE_BUSINESS,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_SAVE_BUSINESS,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

                DispositionReport r = new DispositionReport();
                return r;

        }

        @Override
        public DispositionReport adminSaveTModel(String authInfo, List<AdminSaveTModelWrapper> values) throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();
                        UddiEntityPublisher requestor = this.getEntityPublisher(em, authInfo);
                        if (!((Publisher) requestor).isAdmin()) {
                                throw new UserMismatchException(new ErrorMessage("errors.AdminReqd"));
                        }

                        for (int i = 0; i < values.size(); i++) {
                                //impersonate the user
                                AuthToken authToken = sec.getAuthToken(values.get(i).getPublisherID());
                                SaveTModel stm = new SaveTModel();
                                stm.setAuthInfo(authToken.getAuthInfo());
                                stm.getTModel().addAll(values.get(i).getTModel());
                                pub.saveTModel(stm);
                        }
                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_SAVE_TMODEL,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_SAVE_TMODEL,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

                DispositionReport r = new DispositionReport();
                return r;
        }

        @Override
        public List<SubscriptionWrapper> getAllClientSubscriptionInfo(String authInfo) throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();

                List<SubscriptionWrapper> r = new ArrayList<SubscriptionWrapper>();

                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, authInfo);
                        if (!((Publisher) publisher).isAdmin()) {
                                throw new UserMismatchException(new ErrorMessage("errors.AdminReqd"));
                        }

                        StringBuilder sql = new StringBuilder();
                        sql.append("select distinct c from Subscription c ");
                        Query qry = em.createQuery(sql.toString());
                        List<org.apache.juddi.model.Subscription> resultList = qry.getResultList();
                        for (int i = 0; i < resultList.size(); i++) {
                                Subscription sub = new Subscription();
                                MappingModelToApi.mapSubscription(resultList.get(i), sub);
                                SubscriptionWrapper x = new SubscriptionWrapper();
                                x.getSubscription().add(sub);
                                x.setPublisherIdOrUsername(resultList.get(i).getAuthorizedName());
                                r.add(x);
                        }

                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_CLIENT_SUB,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_CLIENT_SUB,
                                QueryStatus.FAILED, procTime);
                        throw drfm;
                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

                return r;
        }

        @Override
        public synchronized DispositionReport setReplicationNodes(String authInfo, org.uddi.repl_v3.ReplicationConfiguration replicationConfiguration) throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();

                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        org.uddi.repl_v3.ReplicationConfiguration oldConfig = null;
                        UddiEntityPublisher publisher = this.getEntityPublisher(em, authInfo);
                        if (!((Publisher) publisher).isAdmin()) {
                                throw new UserMismatchException(new ErrorMessage("errors.AdminReqd"));
                        }
                        new ValidateReplication(publisher).validateSetReplicationNodes(replicationConfiguration, em, getNode(), AppConfig.getConfiguration());

                        org.apache.juddi.model.ReplicationConfiguration model = null;
                        logger.info(publisher.getAuthorizedName() + " is setting the replication config from " + getRequestorsIPAddress());// + " " + sw.toString());
                        try {
                                model = (ReplicationConfiguration) em.createQuery("select c FROM ReplicationConfiguration c order by c.serialNumber desc").getSingleResult();
                        } catch (Exception ex) {
                        }
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddkkmmZ");
                        if (model == null) {
                                //this is a brand new configuration and we didn't have one before
                                model = new ReplicationConfiguration();
                                MappingApiToModel.mapReplicationConfiguration(replicationConfiguration, model, em);
                                model.setSerialNumber(System.currentTimeMillis());
                                model.setTimeOfConfigurationUpdate(sdf.format(new Date()));
                                em.persist(model);
                                //if (newReplicationNode(model)){
                                //tell the replication notifier to start transfering with
                                //the first change record
                                //}

                        } else {
                                //a config exists, remove it, add the new one
                                //spec doesn't appear to mention if recording a change history on the config is required
                                //assuming we'll keep it for now, might be useful later.
                                //em.remove(model);
                                oldConfig = new org.uddi.repl_v3.ReplicationConfiguration();
                                MappingModelToApi.mapReplicationConfiguration(model, oldConfig);

                                ReplicationConfiguration model2 = new ReplicationConfiguration();
                                MappingApiToModel.mapReplicationConfiguration(replicationConfiguration, model2, em);
                                model2.setSerialNumber(System.currentTimeMillis());

                                model2.setTimeOfConfigurationUpdate(sdf.format(new Date()));
                                em.persist(model2);

                        }

                        tx.commit();
                        UDDIReplicationImpl.notifyConfigurationChange(oldConfig, replicationConfiguration, this);
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.SET_REPLICATION_NODES,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.SET_REPLICATION_NODES,
                                QueryStatus.FAILED, procTime);
                        throw drfm;
                } catch (Exception ex) {
                        logger.error(ex, ex);
                        throw new FatalErrorException(new ErrorMessage("E_fatalError", ex.getMessage()));
                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }
                DispositionReport d = new DispositionReport();
                Result res = new Result();

                d.getResult().add(res);
                return d;
        }

        @Override
        public synchronized org.uddi.repl_v3.ReplicationConfiguration getReplicationNodes(String authInfo) throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                org.uddi.repl_v3.ReplicationConfiguration r = new org.uddi.repl_v3.ReplicationConfiguration();

                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();

                        UddiEntityPublisher publisher = this.getEntityPublisher(em, authInfo);
                        if (!((Publisher) publisher).isAdmin()) {
                                throw new UserMismatchException(new ErrorMessage("errors.AdminReqd"));
                        }

                        StringBuilder sql = new StringBuilder();
                        sql.append("select c from ReplicationConfiguration c order by c.serialNumber desc");
                        //sql.toString();
                        Query qry = em.createQuery(sql.toString());
                        qry.setMaxResults(1);

                        org.apache.juddi.model.ReplicationConfiguration resultList = (org.apache.juddi.model.ReplicationConfiguration) qry.getSingleResult();
                        MappingModelToApi.mapReplicationConfiguration(resultList, r);
                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_NODES,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.GET_ALL_NODES,
                                QueryStatus.FAILED, procTime);
                        throw drfm;
                } catch (Exception ex) {
                        //possible that there is no config to return
                        logger.debug("Error caught, is there a replication config is avaiable? Returning a default config (no replication): ", ex);

                        r.setCommunicationGraph(new CommunicationGraph());
                        Operator op = new Operator();
                        op.setOperatorNodeID(getNode());
                        op.setSoapReplicationURL(baseUrlSSL + "replication/services/replication");

                        op.getContact().add(new Contact());
                        op.getContact().get(0).getPersonName().add(new PersonName("Unknown", null));
                        op.setOperatorStatus(OperatorStatusType.NORMAL);

                        r.getOperator().add(op);
                        r.getCommunicationGraph().getNode().add(getNode());
                        r.getCommunicationGraph().getControlledMessage().add("*");
                        long procTime = System.currentTimeMillis() - startTime;
                        r.setSerialNumber(0);
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddkkmmZ");
                        r.setTimeOfConfigurationUpdate(sdf.format(new Date()));
                        r.setRegistryContact(new org.uddi.repl_v3.ReplicationConfiguration.RegistryContact());
                        try {
                                // pull from root business
                                if (!tx.isActive()) {
                                        tx = em.getTransaction();
                                }

                                BusinessEntity rootbiz = em.find(BusinessEntity.class, AppConfig.getConfiguration().getString(Property.JUDDI_NODE_ROOT_BUSINESS));
                                if (rootbiz != null) {

                                        for (int i = 0; i < rootbiz.getContacts().size(); i++) {
                                                Contact c = new Contact();
                                                MappingModelToApi.mapContact(rootbiz.getContacts().get(i), c);
                                                r.getRegistryContact().setContact(c);
                                                break;
                                        }

                                }
                                tx.rollback();

                        } catch (Exception ex1) {
                                logger.warn("unexpected error", ex1);
                        }
                        if (r.getRegistryContact().getContact() == null) {
                                r.getRegistryContact().setContact(new Contact());
                                r.getRegistryContact().getContact().getPersonName().add(new PersonName("Unknown", null));
                        }
                        serviceCounter.update(JUDDIQuery.GET_REPLICATION_NODES,
                                QueryStatus.SUCCESS, procTime);

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

                r.setMaximumTimeToGetChanges(BigInteger.ONE);
                r.setMaximumTimeToSyncRegistry(BigInteger.ONE);
                //StringWriter sw = new StringWriter();
                //JAXB.marshal(r, sw);
                //logger.info("dumping returned replication config " + sw.toString());
                return r;
        }

        static UDDISubscriptionImpl sub = new UDDISubscriptionImpl();
        static UDDISecurityImpl sec = new UDDISecurityImpl();
        static UDDIPublicationImpl pub = new UDDIPublicationImpl();

        @Override
        public void adminSaveSubscription(String authInfo, String publisherOrUsername, Holder<List<Subscription>> subscriptions) throws DispositionReportFaultMessage {
                long startTime = System.currentTimeMillis();
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();
                        UddiEntityPublisher requestor = this.getEntityPublisher(em, authInfo);
                        if (!((Publisher) requestor).isAdmin()) {
                                throw new UserMismatchException(new ErrorMessage("errors.AdminReqd"));
                        }
                        //impersonate the user
                        AuthToken authToken = sec.getAuthToken(publisherOrUsername);
                        sub.saveSubscription(authToken.getAuthInfo(), subscriptions);
                        tx.commit();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_SAVE_SUB,
                                QueryStatus.SUCCESS, procTime);
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_SAVE_SUB,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }

        }

        /**
         * {@inheritDoc }
         *
         * @param body
         * @return item history or null if not found
         * @throws DispositionReportFaultMessage
         * @throws RemoteException
         */
        @Override
        public GetEntityHistoryMessageResponse getEntityHistory(GetEntityHistoryMessageRequest body) throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                if (body == null) {
                        throw new InvalidValueException(new ErrorMessage("errors.NullInput"));
                }
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();
                        UddiEntityPublisher requestor = this.getEntityPublisher(em, body.getAuthInfo());
                        if (!((Publisher) requestor).isAdmin()) {
                                throw new UserMismatchException(new ErrorMessage("errors.AdminReqd"));
                        }
                        if (body.getMaxRecords() <= 0) {
                                body.setMaxRecords(20);
                        }
                        if (body.getOffset() < 0) {
                                body.setOffset(0);
                        }
                        Query createQuery = em.createQuery("select m from ChangeRecord m where m.entityKey = :key order by m.id DESC");
                        createQuery.setMaxResults((int) body.getMaxRecords());
                        createQuery.setParameter("key", body.getEntityKey());
                        createQuery.setFirstResult((int) body.getOffset());
                        List<ChangeRecord> resultList = createQuery.getResultList();
                        GetEntityHistoryMessageResponse res = new GetEntityHistoryMessageResponse();
                        res.setChangeRecords(new ChangeRecords());
                        for (ChangeRecord cr : resultList) {
                                res.getChangeRecords().getChangeRecord().add(MappingModelToApi.mapChangeRecord(cr));
                        }

                        tx.rollback();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_GET_HISTORY,
                                QueryStatus.SUCCESS, procTime);
                        return res;
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_GET_HISTORY,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }
        }

        /**
         * {@inheritDoc }
         *
         * @param body
         * @return
         * @throws DispositionReportFaultMessage
         * @throws RemoteException
         */
        @Override
        public GetFailedReplicationChangeRecordsMessageResponse getFailedReplicationChangeRecords(
                GetFailedReplicationChangeRecordsMessageRequest body)
                throws DispositionReportFaultMessage, RemoteException {
                //public GetFailedReplicationChangeRecordsMessageResponse getFailedReplicationChangeRecords(GetFailedReplicationChangeRecordsMessageRequest body) throws DispositionReportFaultMessage, RemoteException {
                long startTime = System.currentTimeMillis();
                if (body == null) {
                        throw new InvalidValueException(new ErrorMessage("errors.NullInput"));
                }
                EntityManager em = PersistenceManager.getEntityManager();
                EntityTransaction tx = em.getTransaction();
                try {
                        tx.begin();
                        UddiEntityPublisher requestor = this.getEntityPublisher(em, body.getAuthInfo());
                        if (!((Publisher) requestor).isAdmin()) {
                                throw new UserMismatchException(new ErrorMessage("errors.AdminReqd"));
                        }
                        if (body.getMaxRecords() <= 0) {
                                body.setMaxRecords(20);
                        }
                        if (body.getOffset() < 0) {
                                body.setOffset(0);
                        }
                        Query createQuery = em.createQuery("select m from ChangeRecord m where m.isAppliedLocally=false order by m.id DESC ");
                        createQuery.setMaxResults((int) body.getMaxRecords());
                        createQuery.setFirstResult((int) body.getOffset());
                        List<ChangeRecord> resultList = createQuery.getResultList();
                        GetFailedReplicationChangeRecordsMessageResponse res = new GetFailedReplicationChangeRecordsMessageResponse();
                        res.setChangeRecords(new ChangeRecords());
                        for (ChangeRecord cr : resultList) {
                                res.getChangeRecords().getChangeRecord().add(MappingModelToApi.mapChangeRecord(cr));
                        }

                        tx.rollback();
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_GET_FAILED_CRS,
                                QueryStatus.SUCCESS, procTime);
                        return res;
                } catch (DispositionReportFaultMessage drfm) {
                        long procTime = System.currentTimeMillis() - startTime;
                        serviceCounter.update(JUDDIQuery.ADMIN_GET_FAILED_CRS,
                                QueryStatus.FAILED, procTime);
                        throw drfm;

                } finally {
                        if (tx.isActive()) {
                                tx.rollback();
                        }
                        em.close();
                }
        }
}