/*
 * Copyright 2017 Crown Copyright
 *
 * 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 stroom.cluster.lock.impl.db;

import stroom.node.api.NodeCallUtil;
import stroom.node.api.NodeInfo;
import stroom.node.api.NodeService;
import stroom.util.jersey.WebTargetFactory;
import stroom.util.shared.ResourcePaths;

import javax.inject.Inject;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

class ClusterLockResourceImpl implements ClusterLockResource {
    private final NodeService nodeService;
    private final NodeInfo nodeInfo;
    private final WebTargetFactory webTargetFactory;
    private final ClusterLockClusterHandler clusterLockClusterHandler;

    @Inject
    ClusterLockResourceImpl(final NodeService nodeService,
                            final NodeInfo nodeInfo,
                            final WebTargetFactory webTargetFactory,
                            final ClusterLockClusterHandler clusterLockClusterHandler) {
        this.nodeService = nodeService;
        this.nodeInfo = nodeInfo;
        this.webTargetFactory = webTargetFactory;
        this.clusterLockClusterHandler = clusterLockClusterHandler;
    }

    @Override
    public Boolean tryLock(final String nodeName, final ClusterLockKey key) {
        // If this is the node that was contacted then call the handler.
        if (NodeCallUtil.shouldExecuteLocally(nodeInfo, nodeName)) {
            return clusterLockClusterHandler.tryLock(key);
        }
        return executeRemotely(ClusterLockResource.TRY_PATH_PART, nodeName, key);
    }

    @Override
    public Boolean releaseLock(final String nodeName, final ClusterLockKey key) {
        // If this is the node that was contacted then call the handler.
        if (NodeCallUtil.shouldExecuteLocally(nodeInfo, nodeName)) {
            return clusterLockClusterHandler.release(key);
        }
        return executeRemotely(ClusterLockResource.RELEASE_PATH_PART, nodeName, key);
    }

    @Override
    public Boolean keepLockAlive(final String nodeName, final ClusterLockKey key) {
        // If this is the node that was contacted then call the handler.
        if (NodeCallUtil.shouldExecuteLocally(nodeInfo, nodeName)) {
            return clusterLockClusterHandler.keepAlive(key);
        }
        return executeRemotely(ClusterLockResource.KEEP_ALIVE_PATH_PART, nodeName, key);
    }

    private Boolean executeRemotely(final String subPath, final String nodeName, final ClusterLockKey key) {
        final String url = NodeCallUtil.getBaseEndpointUrl(nodeInfo, nodeService, nodeName)
                + ResourcePaths.buildAuthenticatedApiPath(
                ClusterLockResource.BASE_PATH,
                subPath,
                nodeName);

        try {
            final Response response = webTargetFactory
                    .create(url)
                    .request(MediaType.APPLICATION_JSON)
                    .put(Entity.json(key));
            if (response.getStatus() != 200) {
                throw new WebApplicationException(response);
            }
            return response.readEntity(Boolean.class);
        } catch (Throwable e) {
            throw NodeCallUtil.handleExceptionsOnNodeCall(nodeName, url, e);
        }
    }
}
@@ -781,16 +781,106 @@
 actory;%0A
+import stroom.util.shared.AutoLogged;%0Aimport stroom.util.shared.AutoLogged.OperationType;%0A
 import s
@@ -941,16 +941,46 @@
 Inject;%0A
+import javax.inject.Provider;%0A
 import j
@@ -1119,16 +1119,107 @@
 ponse;%0A%0A
+import static stroom.util.shared.AutoLogged.OperationType.UNLOGGED;%0A%0A@AutoLogged(UNLOGGED)%0A
 class Cl
@@ -1287,24 +1287,33 @@
 ivate final 
+Provider%3C
 NodeService 
@@ -1303,32 +1303,33 @@
 ider%3CNodeService
+%3E
  nodeService;%0A  
@@ -1340,32 +1340,41 @@
 ivate final 
+Provider%3C
 NodeInfo
  nodeInfo;%0A 
@@ -1353,32 +1353,33 @@
 rovider%3CNodeInfo
+%3E
  nodeInfo;%0A    p
@@ -1387,24 +1387,33 @@
 ivate final 
+Provider%3C
 WebTargetFac
@@ -1408,32 +1408,33 @@
 WebTargetFactory
+%3E
  webTargetFactor
@@ -1450,24 +1450,33 @@
 ivate final 
+Provider%3C
 ClusterLockC
@@ -1480,32 +1480,33 @@
 ckClusterHandler
+%3E
  clusterLockClus
@@ -1560,24 +1560,33 @@
 eImpl(final 
+Provider%3C
 NodeService 
@@ -1584,16 +1584,17 @@
 eService
+%3E
  nodeSer
@@ -1633,24 +1633,33 @@
   final 
+Provider%3C
 NodeInfo
  nodeInf
@@ -1650,16 +1650,17 @@
 NodeInfo
+%3E
  nodeInf
@@ -1696,16 +1696,25 @@
   final 
+Provider%3C
 WebTarge
@@ -1721,16 +1721,17 @@
 tFactory
+%3E
  webTarg
@@ -1771,24 +1771,33 @@
       final 
+Provider%3C
 ClusterLockC
@@ -1809,16 +1809,17 @@
 rHandler
+%3E
  cluster
@@ -2250,32 +2250,38 @@
 Locally(nodeInfo
+.get()
 , nodeName)) %7B%0A 
@@ -2324,16 +2324,22 @@
 Handler.
+get().
 tryLock(
@@ -2658,32 +2658,38 @@
 Locally(nodeInfo
+.get()
 , nodeName)) %7B%0A 
@@ -2732,16 +2732,22 @@
 Handler.
+get().
 release(
@@ -3076,24 +3076,30 @@
 lly(nodeInfo
+.get()
 , nodeName))
@@ -3146,16 +3146,22 @@
 Handler.
+get().
 keepAliv
@@ -3450,16 +3450,22 @@
 nodeInfo
+.get()
 , nodeSe
@@ -3469,16 +3469,22 @@
 eService
+.get()
 , nodeNa
@@ -3714,16 +3714,22 @@
 tFactory
+.get()
 %0A       

Add Providers and Autologger anno