diff --git a/org.adempiere.base/src/org/compiere/model/MScheduler.java b/org.adempiere.base/src/org/compiere/model/MScheduler.java index 385e28e868..ff46fd5584 100644 --- a/org.adempiere.base/src/org/compiere/model/MScheduler.java +++ b/org.adempiere.base/src/org/compiere/model/MScheduler.java @@ -96,7 +96,14 @@ public class MScheduler extends X_AD_Scheduler */ public String getServerID () { - return "Scheduler" + get_ID(); + if (get_ID() == 0 && get_IDOld() > 0) + { + return "Scheduler" + get_IDOld(); + } + else + { + return "Scheduler" + get_ID(); + } } // getServerID /** diff --git a/org.adempiere.base/src/org/idempiere/distributed/ICacheService.java b/org.adempiere.base/src/org/idempiere/distributed/ICacheService.java index 28261d29ba..4cc393176f 100644 --- a/org.adempiere.base/src/org/idempiere/distributed/ICacheService.java +++ b/org.adempiere.base/src/org/idempiere/distributed/ICacheService.java @@ -3,6 +3,7 @@ package org.idempiere.distributed; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; public interface ICacheService { @@ -11,4 +12,28 @@ public interface ICacheService { public List getList(String name); public Set getSet(String name); + + /** + * Tries to acquire the lock for the specified key. + * If the lock is not available, then the current thread becomes disabled for thread scheduling purposes and lies dormant + * until one of two things happens - the lock is acquired by the current thread, or the specified waiting time elapses. + * + * @param map + * @param key + * @param timeout + * @param timeunit + * @return true if lock is acquired, false otherwise + * @throws InterruptedException + */ + public boolean tryLock(Map map, K key, long timeout, TimeUnit timeunit) throws InterruptedException; + + /** + * Releases the lock for the specified key. It never blocks and returns immediately. If the current thread is the holder + * of this lock, then the hold count is decremented. If the hold count is zero, then the lock is released. + * If the current thread is not the holder of this lock, then IllegalMonitorStateException is thrown. + * + * @param map + * @param key + */ + public void unLock(Map map, K key); } diff --git a/org.adempiere.server/META-INF/MANIFEST.MF b/org.adempiere.server/META-INF/MANIFEST.MF index 85e29c3d63..b20ca8a4c6 100644 --- a/org.adempiere.server/META-INF/MANIFEST.MF +++ b/org.adempiere.server/META-INF/MANIFEST.MF @@ -23,6 +23,8 @@ Import-Package: javax.jms;version="1.1.0", org.apache.ecs.xhtml, org.apache.poi.hssf.usermodel, org.osgi.framework;version="1.6.0", + org.osgi.service.component.annotations;version="1.3.0", + org.osgi.service.event;version="1.4.0", org.osgi.util.tracker;version="1.5.0", org.restlet, org.restlet.data, diff --git a/org.adempiere.server/OSGI-INF/org.adempiere.server.scheduler.model.event.SchedulerModelEventHandler.xml b/org.adempiere.server/OSGI-INF/org.adempiere.server.scheduler.model.event.SchedulerModelEventHandler.xml new file mode 100644 index 0000000000..42c68f1fce --- /dev/null +++ b/org.adempiere.server/OSGI-INF/org.adempiere.server.scheduler.model.event.SchedulerModelEventHandler.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/org.adempiere.server/src/main/server/org/adempiere/server/scheduler/model/event/SchedulerModelEventHandler.java b/org.adempiere.server/src/main/server/org/adempiere/server/scheduler/model/event/SchedulerModelEventHandler.java new file mode 100644 index 0000000000..98996151bc --- /dev/null +++ b/org.adempiere.server/src/main/server/org/adempiere/server/scheduler/model/event/SchedulerModelEventHandler.java @@ -0,0 +1,133 @@ +/********************************************************************** +* This file is part of iDempiere ERP Open Source * +* http://www.idempiere.org * +* * +* Copyright (C) Contributors * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 2 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the Free Software * +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * +* MA 02110-1301, USA. * +* * +* Contributors: * +* - Trek Global Corporation * +* - Heng Sin Low * +**********************************************************************/ +package org.adempiere.server.scheduler.model.event; + +import java.util.logging.Level; + +import org.adempiere.base.event.AbstractEventHandler; +import org.adempiere.base.event.IEventManager; +import org.adempiere.base.event.IEventTopics; +import org.compiere.model.I_AD_Scheduler; +import org.compiere.model.MScheduler; +import org.compiere.server.AdempiereServerMgr; +import org.compiere.server.IServerManager; +import org.compiere.util.CLogger; +import org.compiere.util.Trx; +import org.compiere.util.TrxEventListener; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.event.Event; + +/** + * @author hengsin + * + */ +@Component(name = "org.adempiere.server.scheduler.model.event.SchedulerModelEventHandler", + reference = {@Reference(name = "eventManager", service = IEventManager.class, bind = "bindEventManager", + unbind = "unbindEventManager", cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.STATIC)}) +public class SchedulerModelEventHandler extends AbstractEventHandler { + + /** + * default constructor + */ + public SchedulerModelEventHandler() { + } + + /* (non-Javadoc) + * @see org.adempiere.base.event.AbstractEventHandler#doHandleEvent(org.osgi.service.event.Event) + */ + @Override + protected void doHandleEvent(Event event) { + if(event.getTopic().equals(IEventTopics.PO_BEFORE_CHANGE)) { + MScheduler scheduler = (MScheduler) getPO(event); + if (scheduler.isActive() && !scheduler.is_new() && scheduler.is_ValueChanged(I_AD_Scheduler.COLUMNNAME_AD_Schedule_ID)) { + Trx trx = Trx.get(scheduler.get_TrxName(), false); + trx.addTrxEventListener(new TrxEventListener() { + + @Override + public void afterRollback(Trx trx, boolean success) { + } + + @Override + public void afterCommit(Trx trx, boolean success) { + if (success) { + //restart if server instance is local + IServerManager serverMgr = AdempiereServerMgr.get(false); + if (serverMgr != null) { + try { + int state = serverMgr.getServerStatus(scheduler.getServerID()); + if (state == IServerManager.SERVER_STATE_STARTED) { + String error = serverMgr.stop(scheduler.getServerID()); + if (error == null) { + serverMgr.start(scheduler.getServerID()); + } + } + } catch (Exception e) { + CLogger.getCLogger(getClass()).log(Level.SEVERE, e.getMessage(), e); + } + } + } + } + + @Override + public void afterClose(Trx trx) { + } + }); + } + } else if(event.getTopic().equals(IEventTopics.PO_AFTER_CHANGE)) { + MScheduler scheduler = (MScheduler) getPO(event); + if (!scheduler.isActive()) { + //remove from local servermgr + IServerManager serverMgr = AdempiereServerMgr.get(false); + if (serverMgr != null) { + if (serverMgr.getServerInstance(scheduler.getServerID()) != null) + serverMgr.removeScheduler(scheduler); + } + } + } else if(event.getTopic().equals(IEventTopics.PO_AFTER_DELETE)) { + MScheduler scheduler = (MScheduler) getPO(event); + //remove from local servermgr + IServerManager serverMgr = AdempiereServerMgr.get(false); + if (serverMgr != null) { + if (serverMgr.getServerInstance(scheduler.getServerID()) != null) + serverMgr.removeScheduler(scheduler); + } + } + } + + /* (non-Javadoc) + * @see org.adempiere.base.event.AbstractEventHandler#initialize() + */ + @Override + protected void initialize() { + registerTableEvent(IEventTopics.PO_BEFORE_CHANGE, I_AD_Scheduler.Table_Name); + registerTableEvent(IEventTopics.PO_AFTER_CHANGE, I_AD_Scheduler.Table_Name); + registerTableEvent(IEventTopics.PO_AFTER_DELETE, I_AD_Scheduler.Table_Name); + } +} diff --git a/org.adempiere.server/src/main/server/org/compiere/server/AdempiereServerMgr.java b/org.adempiere.server/src/main/server/org/compiere/server/AdempiereServerMgr.java index f2ef0d8668..4c139f6b65 100644 --- a/org.adempiere.server/src/main/server/org/compiere/server/AdempiereServerMgr.java +++ b/org.adempiere.server/src/main/server/org/compiere/server/AdempiereServerMgr.java @@ -20,12 +20,14 @@ import java.sql.Timestamp; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.logging.Level; +import org.adempiere.base.IServiceHolder; import org.adempiere.base.Service; import org.adempiere.server.AdempiereServerActivator; import org.adempiere.server.IServerFactory; @@ -35,7 +37,9 @@ import org.compiere.model.MScheduler; import org.compiere.model.MSession; import org.compiere.util.CLogger; import org.compiere.util.Env; -import org.idempiere.server.cluster.ClusterServerMgr; +import org.idempiere.distributed.ICacheService; +import org.idempiere.distributed.IClusterMember; +import org.idempiere.distributed.IClusterService; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleListener; import org.osgi.framework.ServiceReference; @@ -133,6 +137,34 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer map = getServerOwnerMap(); + if (map != null) { + ICacheService cacheService = getCacheService(); + try { + String reloadLockKey = "cluster.server.owner.map.reload"; + if (cacheService.tryLock(map, reloadLockKey, 30, TimeUnit.SECONDS)) { + try { + List toRemove = new ArrayList<>(); + for(Map.Entry entry : map.entrySet()) { + if (entry.getValue().equals(clusterId)) { + toRemove.add(entry.getKey()); + } + } + for(String key : toRemove) { + map.remove(key); + } + } finally { + cacheService.unLock(map, reloadLockKey); + } + } + } catch (Exception e) { + return "Failed to lock cluster server owner map"; + } + } + } + int noServers = 0; m_servers=new ArrayList(); processorClass = new HashSet(); @@ -163,6 +195,31 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer map = getServerOwnerMap(); + if (map != null) { + ICacheService cacheService = getCacheService(); + try { + if (cacheService.tryLock(map, server.getServerID(), 30, TimeUnit.SECONDS)) { + try { + String memberId = map.get(server.getServerID()); + if (memberId != null && !memberId.equals(clusterId)) { + continue; + } else if (memberId == null) { + map.put(server.getServerID(), clusterId); + } + } finally { + cacheService.unLock(map, server.getServerID()); + } + } else { + continue; + } + } catch (Exception e) { + continue; + } + } + } m_servers.add(new LocalServerController(server)); } } @@ -171,19 +228,19 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer serverFactoryList = Service.locator().list(IServerFactory.class).getServices(); @@ -194,16 +251,80 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer map = getServerOwnerMap(); + if (map != null) { + ICacheService cacheService = getCacheService(); + try { + if (cacheService.tryLock(map, server.getServerID(), 30, TimeUnit.SECONDS)) { + try { + String memberId = map.get(server.getServerID()); + if (memberId != null && !memberId.equals(clusterId)) { + continue; + } else if (memberId == null) { + map.put(server.getServerID(), clusterId); + } + } finally { + cacheService.unLock(map, server.getServerID()); + } + } else { + continue; + } + } catch (Exception e) { + continue; + } + } + } + m_servers.add(new LocalServerController(server, false)); + return start(serverId); + } } } } } - return false; + return null; } + @Override + public synchronized String removeScheduler(MScheduler scheduler) { + String serverId = scheduler.getServerID(); + LocalServerController serverController = getLocalServerController(serverId); + if (serverController == null) + return null; + + if (serverController.isAlive()) { + String error = stop(serverId); + if (error != null) { + return error; + } + } + + for (int i = 0; i < m_servers.size(); i++) { + serverController = m_servers.get(i); + if (serverId.equals(serverController.server.getServerID())) { + m_servers.remove(i); + + String clusterId = getClusterMemberId(); + if (clusterId != null) { + Map map = getServerOwnerMap(); + if (map != null) { + String ownerId = map.get(serverId); + if (ownerId != null && ownerId.equals(clusterId)) { + map.remove(serverId); + } + } + } + return null; + } + } + + return null; + + } + /** * Get Server Context * @return ctx @@ -473,7 +594,7 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer responses = new ArrayList<>(); LocalServerController[] controllers = getLocalServerControllers(); for (LocalServerController controller : controllers) { @@ -590,9 +711,14 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer scheduleFuture; - public LocalServerController(AdempiereServer server) { + private LocalServerController(AdempiereServer server) { + this(server, true); + } + + private LocalServerController(AdempiereServer server, boolean start) { this.server = server; - start(); + if (start) + start(); } public void start() { @@ -713,4 +839,34 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer holder = Service.locator().locate(IClusterService.class); + IClusterService service = holder != null ? holder.getService() : null; + return service; + } + + private String getClusterMemberId() { + IClusterService service = getClusterService(); + if (service != null) { + IClusterMember local = service.getLocalMember(); + if (local != null) + return local.getId(); + } + return null; + } + + private ICacheService getCacheService( ) { + IServiceHolder holder = Service.locator().locate(ICacheService.class); + ICacheService service = holder != null ? holder.getService() : null; + return service; + } + + private Map getServerOwnerMap() { + ICacheService service = getCacheService(); + if (service != null) { + return service.getMap("cluster.server.owner.map"); + } + return null; + } } // AdempiereServerMgr diff --git a/org.adempiere.server/src/main/server/org/compiere/server/IServerManager.java b/org.adempiere.server/src/main/server/org/compiere/server/IServerManager.java index 5faeb5c45e..32b460dd54 100644 --- a/org.adempiere.server/src/main/server/org/compiere/server/IServerManager.java +++ b/org.adempiere.server/src/main/server/org/compiere/server/IServerManager.java @@ -27,6 +27,8 @@ package org.compiere.server; import java.sql.Timestamp; +import org.compiere.model.MScheduler; + /** * * @author hengsin @@ -118,4 +120,16 @@ public interface IServerManager { */ public String getDescription(); + /** + * @param scheduler + * @return error + */ + public String addScheduler(MScheduler scheduler); + + /** + * + * @param scheduler + * @return error + */ + public String removeScheduler(MScheduler scheduler); } \ No newline at end of file diff --git a/org.adempiere.server/src/main/server/org/idempiere/server/cluster/ClusterServerMgr.java b/org.adempiere.server/src/main/server/org/idempiere/server/cluster/ClusterServerMgr.java index 9902a6897b..6b4d957ead 100644 --- a/org.adempiere.server/src/main/server/org/idempiere/server/cluster/ClusterServerMgr.java +++ b/org.adempiere.server/src/main/server/org/idempiere/server/cluster/ClusterServerMgr.java @@ -39,16 +39,19 @@ import java.util.concurrent.Future; import org.adempiere.base.IServiceHolder; import org.adempiere.base.Service; import org.compiere.Adempiere; +import org.compiere.model.MScheduler; import org.compiere.server.IServerManager; import org.compiere.server.ServerCount; import org.compiere.server.ServerInstance; import org.idempiere.distributed.IClusterMember; import org.idempiere.distributed.IClusterService; +import org.idempiere.server.cluster.callable.AddSchedulerCallable; import org.idempiere.server.cluster.callable.GetAllCallable; import org.idempiere.server.cluster.callable.GetServerCallable; import org.idempiere.server.cluster.callable.GetServerCountCallable; import org.idempiere.server.cluster.callable.GetStartTimeCallable; import org.idempiere.server.cluster.callable.ReloadCallable; +import org.idempiere.server.cluster.callable.RemoveSchedulerCallable; import org.idempiere.server.cluster.callable.Response; import org.idempiere.server.cluster.callable.RunNowCallable; import org.idempiere.server.cluster.callable.StartAllCallable; @@ -374,48 +377,59 @@ public class ClusterServerMgr implements IServerManager { } } - /** - * find server instance from non-local nodes - * @param serverId - * @return ServerInstance - */ - public ServerInstance getServerInstanceAtOtherMembers(String serverId) { + @Override + public String addScheduler(MScheduler scheduler) { IClusterService service = getClusterService(); if (service == null) - return null; + return "Cluster service not available"; - GetServerCallable callable = new GetServerCallable(serverId); - Collection members = service.getMembers(); - if (members == null || members.isEmpty()) - return null; - final IClusterMember local = service.getLocalMember(); - if (local == null) - return null; - List others = new ArrayList<>(); - members.forEach(e -> { - if (!e.getId().equals(local.getId())) { - others.add(e); - } - }); - if (others.size() > 0) { - Map> futureMap = service.execute(callable, others); - if (futureMap != null) { - try { - Set>> results = futureMap.entrySet(); - for(Entry> f : results) { - ServerInstance i = f.getValue().get(); - if (i != null) { - i.setClusterMember(f.getKey()); - return i; - } + AddSchedulerCallable callable = new AddSchedulerCallable(scheduler); + Map> futureMap = service.execute(callable, service.getMembers()); + if (futureMap != null) { + try { + Collection> results = futureMap.values(); + for(Future f : results) { + Response response = f.get(); + if (response != null && response.getServerId() != null) { + return response.getError(); } - } catch (InterruptedException e) { - throw new RuntimeException(e.getMessage(), e); - } catch (ExecutionException e) { - throw new RuntimeException(e.getMessage(), e); } + } catch (InterruptedException e) { + throw new RuntimeException(e.getMessage(), e); + } catch (ExecutionException e) { + throw new RuntimeException(e.getMessage(), e); } + return null; + } else { + return "Failed to send add scheduler request through cluster servie"; + } + } + + @Override + public String removeScheduler(MScheduler scheduler) { + IClusterService service = getClusterService(); + if (service == null) + return "Cluster service not available"; + + RemoveSchedulerCallable callable = new RemoveSchedulerCallable(scheduler); + Map> futureMap = service.execute(callable, service.getMembers()); + if (futureMap != null) { + try { + Collection> results = futureMap.values(); + for(Future f : results) { + Response response = f.get(); + if (response != null && response.getServerId() != null) { + return response.getError(); + } + } + } catch (InterruptedException e) { + throw new RuntimeException(e.getMessage(), e); + } catch (ExecutionException e) { + throw new RuntimeException(e.getMessage(), e); + } + return null; + } else { + return "Failed to send remove scheduler request through cluster servie"; } - return null; } } \ No newline at end of file diff --git a/org.adempiere.server/src/main/server/org/idempiere/server/cluster/callable/AddSchedulerCallable.java b/org.adempiere.server/src/main/server/org/idempiere/server/cluster/callable/AddSchedulerCallable.java new file mode 100644 index 0000000000..3970422975 --- /dev/null +++ b/org.adempiere.server/src/main/server/org/idempiere/server/cluster/callable/AddSchedulerCallable.java @@ -0,0 +1,73 @@ +/********************************************************************** +* This file is part of iDempiere ERP Open Source * +* http://www.idempiere.org * +* * +* Copyright (C) Contributors * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 2 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the Free Software * +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * +* MA 02110-1301, USA. * +* * +* Contributors: * +* - Trek Global Corporation * +* - Heng Sin Low * +**********************************************************************/ +package org.idempiere.server.cluster.callable; + +import java.io.Serializable; +import java.util.concurrent.Callable; + +import org.compiere.model.MScheduler; +import org.compiere.server.AdempiereServerMgr; +import org.compiere.server.IServerManager; + +/** + * @author hengsin + * + */ +public class AddSchedulerCallable implements Callable, Serializable { + + /** + * generated serial id + */ + private static final long serialVersionUID = -9074664311726118178L; + private MScheduler scheduler; + + /** + * @param serverId + */ + public AddSchedulerCallable(MScheduler scheduler) { + this.scheduler = scheduler; + } + + @Override + public Response call() throws Exception { + Response response = new Response(); + IServerManager serverMgr = AdempiereServerMgr.get(false); + if (serverMgr != null) { + String error = serverMgr.addScheduler(scheduler); + if (error != null) { + response.error = error; + response.serverId = scheduler.getServerID(); + } else { + if (serverMgr.getServerInstance(scheduler.getServerID()) != null) { + response.error = null; + response.serverId = scheduler.getServerID(); + } + } + } + + return response; + } +} diff --git a/org.adempiere.server/src/main/server/org/idempiere/server/cluster/callable/RemoveSchedulerCallable.java b/org.adempiere.server/src/main/server/org/idempiere/server/cluster/callable/RemoveSchedulerCallable.java new file mode 100644 index 0000000000..dc3911c7db --- /dev/null +++ b/org.adempiere.server/src/main/server/org/idempiere/server/cluster/callable/RemoveSchedulerCallable.java @@ -0,0 +1,67 @@ +/********************************************************************** +* This file is part of iDempiere ERP Open Source * +* http://www.idempiere.org * +* * +* Copyright (C) Contributors * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 2 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the Free Software * +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * +* MA 02110-1301, USA. * +* * +* Contributors: * +* - Trek Global Corporation * +* - Heng Sin Low * +**********************************************************************/ +package org.idempiere.server.cluster.callable; + +import java.io.Serializable; +import java.util.concurrent.Callable; + +import org.compiere.model.MScheduler; +import org.compiere.server.AdempiereServerMgr; +import org.compiere.server.IServerManager; + +/** + * @author hengsin + * + */ +public class RemoveSchedulerCallable implements Callable, Serializable { + + /** + * generated serial id + */ + private static final long serialVersionUID = 7929697664683268446L; + private MScheduler scheduler; + + /** + * @param serverId + */ + public RemoveSchedulerCallable(MScheduler scheduler) { + this.scheduler = scheduler; + } + + @Override + public Response call() throws Exception { + Response response = new Response(); + IServerManager serverMgr = AdempiereServerMgr.get(false); + if (serverMgr != null) { + if (serverMgr.getServerInstance(scheduler.getServerID()) != null) { + response.error = serverMgr.removeScheduler(scheduler); + response.serverId = scheduler.getServerID(); + } + } + + return response; + } +} diff --git a/org.idempiere.hazelcast.service/src/org/idempiere/hazelcast/service/CacheServiceImpl.java b/org.idempiere.hazelcast.service/src/org/idempiere/hazelcast/service/CacheServiceImpl.java index 0b82f90517..29503eb297 100644 --- a/org.idempiere.hazelcast.service/src/org/idempiere/hazelcast/service/CacheServiceImpl.java +++ b/org.idempiere.hazelcast.service/src/org/idempiere/hazelcast/service/CacheServiceImpl.java @@ -16,9 +16,12 @@ package org.idempiere.hazelcast.service; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; import org.idempiere.distributed.ICacheService; +import com.hazelcast.core.IMap; + /** * @author hengsin * @@ -58,4 +61,21 @@ public class CacheServiceImpl implements ICacheService { return null; } + @Override + public boolean tryLock(Map map, K key, long timeout, TimeUnit timeunit) throws InterruptedException { + if (map instanceof IMap) { + IMap imap = (IMap) map; + return imap.tryLock(key, timeout, timeunit); + } + return false; + } + + @Override + public void unLock(Map map, K key) { + if (map instanceof IMap) { + IMap imap = (IMap) map; + imap.unlock(key); + } + } + }