Author: nzamosenchuk
Date: 2010-02-05 08:29:35 -0500 (Fri, 05 Feb 2010)
New Revision: 1698
Added:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/CacheableJDBCLockManagerImpl.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockDBInitializer.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockJDBCConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockJDBCContainer.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/OracleLockDBInitializer.java
Removed:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockDBInitializer.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockJDBCConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockPersistentDataManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/OracleLockDBInitializer.java
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockImpl.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/SessionLockManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/SessionLockManagerImpl.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheLockImpl.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManagerImpl.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableSessionLockManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockData.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/core/lock/TestLockPerstistentDataManager.java
Log:
EXOJCR-472: Implemented base JBC-JDBC lock manager together with Karpenko Sergey.
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockImpl.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockImpl.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockImpl.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -59,7 +59,7 @@
return lockData.getLockToken(session.getId());
}
- public boolean isLive()
+ public boolean isLive() throws LockException
{
return lockData.isLive();
}
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/SessionLockManager.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/SessionLockManager.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/SessionLockManager.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -97,9 +97,10 @@
* node
* @return <code>true</code> if this node is locked either as a result of
a lock held by this node
* or by a deep lock on a node above this node; otherwise returns
<code>false</code>
+ * @throws LockException
* @see javax.jcr.Node#isLocked
*/
- boolean isLocked(NodeData node);
+ boolean isLocked(NodeData node) throws LockException;
/**
* Returns <code>true</code> if the specified session holds a lock on the
given node; otherwise
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/SessionLockManagerImpl.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/SessionLockManagerImpl.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/SessionLockManagerImpl.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -100,7 +100,7 @@
/**
* {@inheritDoc}
*/
- public boolean isLocked(NodeData node)
+ public boolean isLocked(NodeData node) throws LockException
{
return lockManager.isLocked(node);
}
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheLockImpl.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheLockImpl.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheLockImpl.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -75,7 +75,7 @@
/**
* {@inheritDoc}
*/
- public boolean isLive()
+ public boolean isLive() throws LockException
{
if (!live)
{
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManager.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManager.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManager.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -54,8 +54,9 @@
* @param nodeIdentifier
*
* @return boolean
+ * @throws LockException TODO
*/
- boolean isLockLive(String nodeIdentifier);
+ boolean isLockLive(String nodeIdentifier) throws LockException;
/**
* Search lock in storage. SearchType shows which locks should be returned.
@@ -65,7 +66,7 @@
* @param searchType - combination of SEARCH_EXECMATCH, SEARCH_CLOSEDPARENT,
SEARCH_CLOSEDCHILD search types
* @return LockData or null
*/
- public LockData getLockData(NodeData node, int searchType);
+ public LockData getLockData(NodeData node, int searchType) throws LockException;
/**
* Replace old lockData with new one. Node ID, token can't be replaced.
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManagerImpl.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManagerImpl.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManagerImpl.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -358,7 +358,7 @@
* @param nodeId - locked node id
* @return
*/
- public boolean isLockLive(String nodeId)
+ public boolean isLockLive(String nodeId) throws LockException
{
try
{
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableSessionLockManager.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableSessionLockManager.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableSessionLockManager.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -186,7 +186,7 @@
/**
* {@inheritDoc}
*/
- public boolean isLocked(NodeData node)
+ public boolean isLocked(NodeData node) throws LockException
{
LockData lData =
lockManager
@@ -289,7 +289,7 @@
* @param nodeId - node ID string
* @return boolean
*/
- protected boolean cotainsPendingLock(String nodeId)
+ public boolean cotainsPendingLock(String nodeId)
{
return pendingLocks.contains(nodeId);
}
@@ -318,7 +318,7 @@
* @param nodeId - ID of locked node
* @return pending lock or null
*/
- protected LockData getPendingLock(String nodeId)
+ public LockData getPendingLock(String nodeId)
{
if (pendingLocks.contains(nodeId))
{
@@ -336,7 +336,7 @@
* @param nodeIdentifier - locked node id
* @return
*/
- protected boolean isLockLive(String nodeIdentifier)
+ protected boolean isLockLive(String nodeIdentifier) throws LockException
{
if (lockManager.isLockLive(nodeIdentifier))
@@ -349,7 +349,7 @@
}
}
- protected void notifyLockPersisted(String nodeIdentifier)
+ public void notifyLockPersisted(String nodeIdentifier)
{
pendingLocks.remove(nodeIdentifier);
}
@@ -359,7 +359,7 @@
*
* @param nodeIdentifier - unlocked node identifier
*/
- protected void notifyLockRemoved(String nodeIdentifier)
+ public void notifyLockRemoved(String nodeIdentifier)
{
lockedNodes.remove(nodeIdentifier);
}
Deleted:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockDBInitializer.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockDBInitializer.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockDBInitializer.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -1,391 +0,0 @@
-/*
- * Copyright (C) 2003-2010 eXo Platform SAS.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation; either version 3
- * 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,
see<http://www.gnu.org/licenses/>.
- */
-package org.exoplatform.services.jcr.impl.core.lock.jbosscache;
-
-import org.exoplatform.services.jcr.impl.storage.jdbc.init.DBInitializerException;
-import org.exoplatform.services.log.ExoLogger;
-import org.exoplatform.services.log.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Created by The eXo Platform SAS.
- *
- * <br/>Date:
- *
- * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
- * @version $Id: LockDBInitializer.java 111 2008-11-11 11:11:11Z serg $
- */
-public class LockDBInitializer
-{
- static public String SQL_DELIMITER = ";";
-
- static public String SQL_DELIMITER_COMMENT_PREFIX = "/*$DELIMITER:";
-
- static public String SQL_TABLE_NAME_PATTERN = "${table.name}";
-
- static public String SQL_CREATETABLE =
"^(CREATE(\\s)+TABLE(\\s)+(IF(\\s)+NOT(\\s)+EXISTS(\\s)+)*){1}";
-
- static public String SQL_CREATEVIEW =
"^(CREATE(\\s)+VIEW(\\s)+(IF(\\s)+NOT(\\s)+EXISTS(\\s)+)*){1}";
-
- static public String SQL_OBJECTNAME =
"((JCR_[A-Z_]+){1}(\\s*?|(\\(\\))*?)+)+?";
-
- static public String SQL_CREATEINDEX =
"^(CREATE(\\s)+(UNIQUE(\\s)+)*INDEX(\\s)+){1}";
-
- static public String SQL_ONTABLENAME =
"(ON(\\s)+(JCR_[A-Z_]+){1}(\\s*?|(\\(\\))*?)+){1}";
-
- static public String SQL_CREATESEQUENCE =
"^(CREATE(\\s)+SEQUENCE(\\s)+){1}";
-
- static public String SQL_CREATETRIGGER =
"^(CREATE(\\s)+(OR(\\s){1}REPLACE(\\s)+)*TRIGGER(\\s)+){1}";
-
- static public String SQL_TRIGGERNAME =
"(([A-Z_]+JCR_[A-Z_]+){1}(\\s*?|(\\(\\))*?)+)+?";
-
- protected final Log log = ExoLogger.getLogger("jcr.LockDBInitializer");
-
- protected final Connection connection;
-
- protected final String containerName;
-
- protected final String script;
-
- //protected final boolean multiDb;
-
- protected final Pattern creatTablePattern;
-
- protected final Pattern creatViewPattern;
-
- protected final Pattern dbObjectNamePattern;
-
- protected final Pattern creatIndexPattern;
-
- protected final Pattern onTableNamePattern;
-
- protected final Pattern creatSequencePattern;
-
- protected final Pattern creatTriggerPattern;
-
- protected final Pattern dbTriggerNamePattern;
-
- public LockDBInitializer(String containerName, Connection connection, String
scriptPath) throws IOException
- {
- this.connection = connection;
- this.script = script(scriptPath);
- this.containerName = containerName;
-
- this.creatTablePattern = Pattern.compile(SQL_CREATETABLE,
Pattern.CASE_INSENSITIVE);
- this.creatViewPattern = Pattern.compile(SQL_CREATEVIEW, Pattern.CASE_INSENSITIVE);
- this.dbObjectNamePattern = Pattern.compile(SQL_OBJECTNAME,
Pattern.CASE_INSENSITIVE);
- this.creatIndexPattern = Pattern.compile(SQL_CREATEINDEX,
Pattern.CASE_INSENSITIVE);
- this.onTableNamePattern = Pattern.compile(SQL_ONTABLENAME,
Pattern.CASE_INSENSITIVE);
- this.creatSequencePattern = Pattern.compile(SQL_CREATESEQUENCE,
Pattern.CASE_INSENSITIVE);
- this.creatTriggerPattern = Pattern.compile(SQL_CREATETRIGGER,
Pattern.CASE_INSENSITIVE);
- this.dbTriggerNamePattern = Pattern.compile(SQL_TRIGGERNAME,
Pattern.CASE_INSENSITIVE);
- }
-
- protected String script(String scriptPath) throws IOException
- {
- return readScriptResource(scriptPath);
- }
-
- protected String readScriptResource(String path) throws IOException
- {
- InputStream is = this.getClass().getResourceAsStream(path);
- InputStreamReader isr = new InputStreamReader(is);
- try
- {
- StringBuilder sbuff = new StringBuilder();
- char[] buff = new char[is.available()];
- int r = 0;
- while ((r = isr.read(buff)) > 0)
- {
- sbuff.append(buff, 0, r);
- }
-
- return sbuff.toString();
- }
- finally
- {
- try
- {
- is.close();
- }
- catch (IOException e)
- {
- }
- }
- }
-
- public String cleanWhitespaces(String string)
- {
- if (string != null)
- {
- char[] cc = string.toCharArray();
- for (int ci = cc.length - 1; ci > 0; ci--)
- {
- if (Character.isWhitespace(cc[ci]))
- {
- cc[ci] = ' ';
- }
- }
- return new String(cc);
- }
- return string;
- }
-
- protected boolean isTableExists(Connection conn, String tableName) throws
SQLException
- {
- ResultSet trs = conn.getMetaData().getTables(null, null, tableName, null);
- boolean res = false;
- while (trs.next())
- {
- res = true; // check for columns/table type matching etc.
- }
- return res;
- }
-
- protected boolean isIndexExists(Connection conn, String tableName, String indexName)
throws SQLException
- {
- ResultSet irs = conn.getMetaData().getIndexInfo(null, null, tableName, false,
true);
- boolean res = false;
- while (irs.next())
- {
- if (irs.getShort("TYPE") != DatabaseMetaData.tableIndexStatistic
- &&
irs.getString("INDEX_NAME").equalsIgnoreCase(indexName))
- res = true; // check for index params matching etc.
- }
- return res;
- }
-
- protected boolean isSequenceExists(Connection conn, String sequenceName) throws
SQLException
- {
- return false;
- }
-
- protected boolean isTriggerExists(Connection conn, String triggerName) throws
SQLException
- {
- return false;
- }
-
- public boolean isObjectExists(Connection conn, String sql) throws SQLException
- {
- Matcher tMatcher = creatTablePattern.matcher(sql);
- if (tMatcher.find())
- {
- // CREATE TABLE
- tMatcher = dbObjectNamePattern.matcher(sql);
- if (tMatcher.find())
- {
- // got table name
- String tableName = sql.substring(tMatcher.start(), tMatcher.end());
- if (isTableExists(conn, tableName))
- {
- if (log.isDebugEnabled())
- log.debug("Table is already exists " + tableName);
- return true;
- }
- }
- }
- else if ((tMatcher = creatViewPattern.matcher(sql)).find())
- {
- // CREATE VIEW
- tMatcher = dbObjectNamePattern.matcher(sql);
- if (tMatcher.find())
- {
- // got view name
- String tableName = sql.substring(tMatcher.start(), tMatcher.end());
- if (isTableExists(conn, tableName))
- {
- if (log.isDebugEnabled())
- log.debug("View is already exists " + tableName);
- return true;
- }
- }
- }
- else if ((tMatcher = creatIndexPattern.matcher(sql)).find())
- {
- // CREATE INDEX
- tMatcher = dbObjectNamePattern.matcher(sql);
- if (tMatcher.find())
- {
- // got index name
- String indexName = sql.substring(tMatcher.start(), tMatcher.end());
- if ((tMatcher = onTableNamePattern.matcher(sql)).find())
- {
- String onTableName = sql.substring(tMatcher.start(), tMatcher.end());
- if ((tMatcher = dbObjectNamePattern.matcher(onTableName)).find())
- {
- String tableName = onTableName.substring(tMatcher.start(),
tMatcher.end());
- if (isIndexExists(conn, tableName, indexName))
- {
- if (log.isDebugEnabled())
- log.debug("Index is already exists " + indexName);
- return true;
- }
- }
- else
- {
- log.warn("Index found but $TABLE_NAME is not detected '"
+ sql + "'");
- }
- }
- else
- {
- log.warn("Index found but ON $TABLE_NAME clause is not detected
'" + sql + "'");
- }
- }
- else
- {
- log.warn("Create index clause found but $INDEX_NAME is not detected
'" + sql + "'");
- }
- }
- else if ((tMatcher = creatSequencePattern.matcher(sql)).find())
- {
- tMatcher = dbObjectNamePattern.matcher(sql);
- if (tMatcher.find())
- {
- // got sequence name
- String sequenceName = sql.substring(tMatcher.start(), tMatcher.end());
- if (isSequenceExists(conn, sequenceName))
- {
- if (log.isDebugEnabled())
- log.debug("Sequence is already exists " + sequenceName);
- return true;
- }
- }
- }
- else if ((tMatcher = creatTriggerPattern.matcher(sql)).find())
- {
- tMatcher = dbTriggerNamePattern.matcher(sql);
- if (tMatcher.find())
- {
- // got trigger name
- String triggerName = sql.substring(tMatcher.start(), tMatcher.end());
- if (isTriggerExists(conn, triggerName))
- {
- if (log.isDebugEnabled())
- log.debug("Trigger is already exists " + triggerName);
- return true;
- }
- }
- }
- else
- {
- if (log.isDebugEnabled())
- log.debug("Command is not detected for check '" + sql +
"'");
- }
-
- return false;
- }
-
- public void init() throws DBInitializerException
- {
- String[] scripts = null;
- if (script.startsWith(SQL_DELIMITER_COMMENT_PREFIX))
- {
- // read custom prefix
- try
- {
- String s = script.substring(SQL_DELIMITER_COMMENT_PREFIX.length());
- int endOfDelimIndex = s.indexOf("*/");
- String delim = s.substring(0, endOfDelimIndex).trim();
- s = s.substring(endOfDelimIndex + 2).trim();
- scripts = s.split(delim);
- }
- catch (IndexOutOfBoundsException e)
- {
- log.warn("Error of parse SQL-script file. Invalid DELIMITER
configuration. Valid format is '"
- + SQL_DELIMITER_COMMENT_PREFIX + "XXX*/' at begin of the
SQL-script file, where XXX - DELIMITER string."
- + " Spaces will be trimed. ", e);
- log.info("Using DELIMITER:[" + SQL_DELIMITER + "]");
- scripts = script.split(SQL_DELIMITER);
- }
- }
- else
- {
- scripts = script.split(SQL_DELIMITER);
- }
-
- String sql = null;
- try
- {
- connection.setAutoCommit(false);
-
- for (String scr : scripts)
- {
- String s = cleanWhitespaces(scr.trim());
- if (s.length() > 0)
- {
- if (isObjectExists(connection, sql = s))
- continue;
-
- if (log.isDebugEnabled())
- log.debug("Execute script: \n[" + sql + "]");
-
- connection.createStatement().executeUpdate(sql);
- }
- }
-
- //rootInit(connection);
-
- connection.commit();
- log.info("DB schema of DataSource: '" + containerName +
"' initialized succesfully");
- }
- catch (SQLException e)
- {
- try
- {
- connection.rollback();
- }
- catch (SQLException re)
- {
- log.error("Rollback error " + e, e);
- }
-
- SQLException next = e.getNextException();
- String errorTrace = "";
- while (next != null)
- {
- errorTrace += next.getMessage() + "; ";
- next = e.getNextException();
- }
- Throwable cause = e.getCause();
- String msg =
- "Could not create db schema of DataSource: '" + containerName +
"'. Reason: " + e.getMessage() + "; "
- + errorTrace + (cause != null ? " (Cause: " + cause.getMessage()
+ ")" : "") + ". Last command: " + sql;
-
- throw new DBInitializerException(msg, e);
- }
- finally
- {
- try
- {
- connection.close();
- }
- catch (SQLException e)
- {
- log.error("Error of a connection closing. " + e, e);
- }
- }
- }
-}
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockData.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockData.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockData.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -107,7 +107,7 @@
* is seconds!
* @param birthday
*/
- protected LockData(String nodeIdentifier, String lockTokenHash, boolean deep, boolean
sessionScoped, String owner,
+ public LockData(String nodeIdentifier, String lockTokenHash, boolean deep, boolean
sessionScoped, String owner,
long timeOut, long birthday)
{
this.nodeIdentifier = nodeIdentifier;
@@ -246,12 +246,12 @@
/**
* @return
*/
- protected long getTimeOut()
+ public long getTimeOut()
{
return timeOut;
}
- protected long getBirthDay()
+ public long getBirthDay()
{
return birthday;
}
Deleted:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockJDBCConnection.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockJDBCConnection.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockJDBCConnection.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2003-2010 eXo Platform SAS.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation; either version 3
- * 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,
see<http://www.gnu.org/licenses/>.
- */
-package org.exoplatform.services.jcr.impl.core.lock.jbosscache;
-
-import org.exoplatform.services.log.ExoLogger;
-import org.exoplatform.services.log.Log;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.lock.LockException;
-
-/**
- * Created by The eXo Platform SAS.
- *
- * <br/>Date:
- *
- * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
- * @version $Id: LockJDBCConnection.java 111 2008-11-11 11:11:11Z serg $
- */
-public class LockJDBCConnection
-{
-
- private final Log LOG = ExoLogger.getLogger(LockPersistentDataManager.class);
-
- // queries
- protected String ADD_LOCK_DATA;
-
- protected String REMOVE_LOCK_DATA;
-
- protected String REFRESH_LOCK_DATA;
-
- protected String GET_LOCKED_NODES;
-
- protected String GET_LOCK_DATA;
-
- // column names
- protected static String COLUMN_WS_NAME = "WS_NAME";
-
- protected static String COLUMN_NODE_ID = "NODE_ID";
-
- protected static String COLUMN_TOKEN_HASH = "TOKEN_HASH";
-
- protected static String COLUMN_OWNER = "OWNER";
-
- protected static String COLUMN_IS_SESSIONSCOPED = "IS_SESSIONSCOPED";
-
- protected static String COLUMN_IS_DEEP = "IS_DEEP";
-
- protected static String COLUMN_BIRTHDAY = "BIRTHDAY";
-
- protected static String COLUMN_TIMEOUT = "TIMEOUT";
-
- // prepared statements
- private PreparedStatement insertLockData;
-
- private PreparedStatement removeLockData;
-
- private PreparedStatement refreshLockData;
-
- private PreparedStatement getLockedNodes;
-
- private PreparedStatement getLockData;
-
- private Connection dbConnection;
-
- private String wsName;
-
- /**
- * Creates LockJDBCConnection instance based on given connection to
- * database with specified workspace name.
- *
- * @param dbConnection Connection to database.
- * @param wsName Current workspace's name.
- * @throws SQLException if database exception occurs.
- */
- public LockJDBCConnection(Connection dbConnection, String wsName) throws SQLException
- {
- this.dbConnection = dbConnection;
-
- if (dbConnection.getAutoCommit())
- {
- dbConnection.setAutoCommit(false);
- }
- this.wsName = wsName;
-
- ADD_LOCK_DATA =
- "insert into JCR_LOCKS(WS_NAME, NODE_ID, TOKEN_HASH, OWNER,
IS_SESSIONSCOPED, IS_DEEP, BIRTHDAY, TIMEOUT) VALUES(?,?,?,?,?,?,?,?)";
-
- REMOVE_LOCK_DATA = "delete from JCR_LOCKS where NODE_ID=? and
WS_NAME=?";
-
- REFRESH_LOCK_DATA = "update JCR_LOCKS set BIRTHDAY=? where NODE_ID=? and
WS_NAME=?";
-
- GET_LOCKED_NODES = "select NODE_ID from JCR_LOCKS where WS_NAME=?";
-
- GET_LOCK_DATA = "select * from JCR_LOCKS where NODE_ID=? and WS_NAME=?";
- }
-
- /**
- * Inserts new lock data into DB
- *
- * @param data
- * @return
- * @throws LockException
- */
- public int addLockData(LockData data) throws LockException
- {
- if (!isOpened())
- {
- throw new IllegalStateException("Connection is closed");
- }
- try
- {
- if (insertLockData == null)
- {
- insertLockData = dbConnection.prepareStatement(ADD_LOCK_DATA);
- }
- else
- {
- insertLockData.clearParameters();
- }
- insertLockData.setString(1, wsName);
- insertLockData.setString(2, data.getNodeIdentifier());
- insertLockData.setString(3, data.getTokenHash());
- insertLockData.setString(4, data.getOwner());
- insertLockData.setBoolean(5, data.isSessionScoped());
- insertLockData.setBoolean(6, data.isDeep());
- insertLockData.setLong(7, data.getBirthDay());
- insertLockData.setLong(8, data.getTimeOut());
-
- return insertLockData.executeUpdate();
- }
- catch (SQLException e)
- {
- throw new LockException(e);
- }
- }
-
- /**
- * Removes LockData for given node identifier from database
- *
- * @param nodeID
- * @return
- * @throws LockException
- */
- public int removeLockData(String nodeID) throws LockException
- {
- if (!isOpened())
- {
- throw new IllegalStateException("Connection is closed");
- }
- try
- {
- if (removeLockData == null)
- {
- removeLockData = dbConnection.prepareStatement(REMOVE_LOCK_DATA);
- }
- else
- {
- removeLockData.clearParameters();
- }
- // REMOVE_LOCK_DATA = "delete from JCR_LOCKS where NODE_ID=? and
WS_NAME=?";
- removeLockData.setString(1, nodeID);
- removeLockData.setString(2, wsName);
-
- return removeLockData.executeUpdate();
- }
- catch (SQLException e)
- {
- throw new LockException(e);
- }
- }
-
- /**
- * Refreshes given LockData (updates birthday column)
- *
- * @param data
- * @return
- * @throws LockException
- */
- public int refreshLockData(LockData data) throws LockException
- {
- if (!isOpened())
- {
- throw new IllegalStateException("Connection is closed");
- }
- try
- {
- if (refreshLockData == null)
- {
- refreshLockData = dbConnection.prepareStatement(REFRESH_LOCK_DATA);
- }
- else
- {
- refreshLockData.clearParameters();
- }
-
- // REFRESH_LOCK_DATA = "update JCR_LOCKS set BIRTHDAY=? where NODE_ID=? and
WS_NAME=?";
- refreshLockData.setLong(1, data.getBirthDay());
- refreshLockData.setString(2, data.getNodeIdentifier());
- refreshLockData.setString(3, wsName);
-
- return refreshLockData.executeUpdate();
- }
- catch (SQLException e)
- {
- throw new LockException(e);
- }
- }
-
- /**
- * Returns the set of locked nodes identifiers
- *
- * @return
- * @throws LockException
- */
- public Set<String> getLockedNodes() throws LockException
- {
- if (!isOpened())
- {
- throw new IllegalStateException("Connection is closed");
- }
- try
- {
- if (getLockedNodes == null)
- {
- getLockedNodes = dbConnection.prepareStatement(GET_LOCKED_NODES);
- }
- else
- {
- getLockedNodes.clearParameters();
- }
- // GET_LOCKED_NODES = "select NODE_ID from JCR_LOCKS where
WS_NAME=?";
- getLockedNodes.setString(1, wsName);
- // get result set
- ResultSet result = getLockedNodes.executeQuery();
- Set<String> identifiers = new HashSet<String>();
- // traverse result set
- while (result.next())
- {
- identifiers.add(new String(result.getString(COLUMN_NODE_ID)));
- }
- return identifiers;
- }
- catch (SQLException e)
- {
- throw new LockException(e);
- }
- }
-
- /**
- * Returns LockData for given node identifier from database
- * or null if not exists
- *
- * @param identifier
- * @return
- * @throws LockException
- */
- public LockData getLockData(String identifier) throws LockException
- {
- if (!isOpened())
- {
- throw new IllegalStateException("Connection is closed");
- }
- try
- {
- if (getLockData == null)
- {
- getLockData = dbConnection.prepareStatement(GET_LOCK_DATA);
- }
- else
- {
- getLockData.clearParameters();
- }
- // GET_LOCK_DATA = "select * from JCR_LOCKS where NODE_ID=? and
WS_NAME=?";
- getLockData.setString(1, identifier);
- getLockData.setString(2, wsName);
- // get result set
- ResultSet result = getLockData.executeQuery();
- if (result.next())
- {
- return new LockData(result.getString(COLUMN_NODE_ID),
result.getString(COLUMN_TOKEN_HASH), result
- .getBoolean(COLUMN_IS_DEEP), result.getBoolean(COLUMN_IS_SESSIONSCOPED),
result.getString(COLUMN_OWNER),
- result.getLong(COLUMN_TIMEOUT), result.getLong(COLUMN_BIRTHDAY));
- }
- return null;
- }
- catch (SQLException e)
- {
- throw new LockException(e);
- }
- }
-
- /**
- * Check if connection is alive and opened
- * @return
- */
- public boolean isOpened()
- {
- try
- {
- return !dbConnection.isClosed();
- }
- catch (SQLException e)
- {
- LOG.error(e.getMessage(), e);
- return false;
- }
- }
-
- /**
- * Closes database connection
- *
- * @throws IllegalStateException
- * @throws RepositoryException
- */
- public final void close() throws IllegalStateException, RepositoryException
- {
- if (!isOpened())
- {
- throw new IllegalStateException("Connection is closed");
- }
-
- try
- {
- dbConnection.close();
- }
- catch (SQLException e)
- {
- throw new RepositoryException(e);
- }
- }
-
- /**
- * Commits and closes database connection
- *
- * @throws IllegalStateException
- * @throws RepositoryException
- */
- public final void commit() throws IllegalStateException, RepositoryException
- {
- if (!isOpened())
- {
- throw new IllegalStateException("Connection is closed");
- }
- try
- {
- if (!dbConnection.isReadOnly())
- {
- dbConnection.commit();
- }
-
- dbConnection.close();
- }
- catch (SQLException e)
- {
- throw new RepositoryException(e);
- }
- }
-
-}
Deleted:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockPersistentDataManager.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockPersistentDataManager.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockPersistentDataManager.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2010 eXo Platform SAS.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.exoplatform.services.jcr.impl.core.lock.jbosscache;
-
-import org.exoplatform.services.jcr.impl.storage.jdbc.DBConstants;
-import org.exoplatform.services.jcr.impl.storage.jdbc.DialectDetecter;
-import org.exoplatform.services.jcr.impl.storage.jdbc.init.DBInitializerException;
-import org.exoplatform.services.log.ExoLogger;
-import org.exoplatform.services.log.Log;
-
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.SQLException;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.lock.LockException;
-import javax.naming.InitialContext;
-import javax.sql.DataSource;
-
-/**
- * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
- * @author <a href="mailto:nikolazius@gmail.com">Nikolay
Zamosenchuk</a>
- * @version $Id: LockPersistentDataManager.java 34360 2009-07-22 23:58:59Z nzamosenchuk
$
- *
- */
-public class LockPersistentDataManager
-{
- private final Log log = ExoLogger.getLogger(LockPersistentDataManager.class);
-
- private DataSource dataSource;
-
- private String wsName;
-
- /**
- * @param dataSourceName DataSource name
- * @param tableName Name of DB table
- * @throws RepositoryException
- */
- public LockPersistentDataManager(String dataSourceName, String wsName) throws
RepositoryException
- {
- this.wsName = wsName;
-
- // try to resolve DataSource
- try
- {
- dataSource = (DataSource)new InitialContext().lookup(dataSourceName);
- if (dataSource != null)
- {
- // initialize DB table if needed
- try
- {
- log.info("Creating LockManager DB tables.");
- Connection jdbcConn = dataSource.getConnection();
- String dialect = DialectDetecter.detect(jdbcConn.getMetaData());
- // if table not exists, create it
- // connection is closed by DB initializer
- initDatabase(dataSourceName, jdbcConn, dialect);
- }
- catch (SQLException e)
- {
- throw new RepositoryException(e);
- }
- catch (IOException e)
- {
- throw new RepositoryException(e);
- }
- }
- else
- {
- throw new RepositoryException("Datasource '" + dataSourceName +
"' is not bound in this context.");
- }
- }
- catch (Exception e)
- {
- throw new RepositoryException(e);
- }
-
- }
-
- public LockJDBCConnection openConnection(boolean readOnly) throws LockException
- {
- try
- {
- return new LockJDBCConnection(getJDBCConnection(), wsName);
- }
- catch (SQLException e)
- {
- throw new LockException(e);
- }
- }
-
- /**
- * Returns connection to database
- * @return
- *
- * @return connection to database
- * @throws RepositoryException
- * @throws RepositoryException
- */
- private Connection getJDBCConnection() throws LockException
- {
- try
- {
- //TODO make connection as in GenericConnectionFactory
- return dataSource.getConnection();
-
- }
- catch (SQLException e)
- {
- String err =
- "Error of JDBC connection open. SQLException: " + e.getMessage() +
", SQLState: " + e.getSQLState()
- + ", VendorError: " + e.getErrorCode();
- throw new LockException(err, e);
- }
- }
-
- /**
- * Creates table in DB if not present
- *
- * @param dialect
- * @throws IOException
- * @throws DBInitializerException
- */
- protected void initDatabase(String dataSource, Connection jdbcConn, String dialect)
throws IOException,
- DBInitializerException
- {
- LockDBInitializer dbInitializer = null;
-
- // prepare DB
- if (DBConstants.DB_DIALECT_ORACLE.equals(dialect))
- {
- // oracle preparation script
- String sqlPath = "/conf/storage/lock-jdbc.ora.sql";
- dbInitializer = new OracleLockDBInitializer(dataSource, jdbcConn, sqlPath);
- }
- else
- {
- // generic preparation script
- String sqlPath = "/conf/storage/lock-jdbc.default.sql";
- dbInitializer = new LockDBInitializer(dataSource, jdbcConn, sqlPath);
- }
-
- // init DB
- dbInitializer.init();
- }
-
-}
\ No newline at end of file
Deleted:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/OracleLockDBInitializer.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/OracleLockDBInitializer.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/OracleLockDBInitializer.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2003-2010 eXo Platform SAS.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation; either version 3
- * 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,
see<http://www.gnu.org/licenses/>.
- */
-package org.exoplatform.services.jcr.impl.core.lock.jbosscache;
-
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-
-/**
- * Created by The eXo Platform SAS.
- *
- * <br/>Date:
- *
- * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
- * @version $Id: OracleLockDBInitializer.java 111 2008-11-11 11:11:11Z serg $
- */
-public class OracleLockDBInitializer extends LockDBInitializer
-{
-
- public OracleLockDBInitializer(String containerName, Connection connection, String
script) throws IOException
- {
- super(containerName, connection, script);
- }
-
- @Override
- protected boolean isSequenceExists(Connection conn, String sequenceName) throws
SQLException
- {
- try
- {
- ResultSet srs = conn.createStatement().executeQuery("SELECT " +
sequenceName + ".nextval FROM DUAL");
- if (srs.next())
- {
- return true;
- }
- srs.close();
- return false;
- }
- catch (SQLException e)
- {
- // check: ORA-02289: sequence does not exist
- if (e.getMessage().indexOf("ORA-02289") >= 0)
- return false;
- throw e;
- }
- }
-
- @Override
- protected boolean isTriggerExists(Connection conn, String triggerName) throws
SQLException
- {
- String sql = "SELECT COUNT(trigger_name) FROM all_triggers WHERE trigger_name
= '" + triggerName + "'";
- ResultSet r = conn.createStatement().executeQuery(sql);
- if (r.next())
- return r.getInt(1) > 0;
- else
- return false;
- }
-
- @Override
- protected boolean isTableExists(Connection conn, String tableName) throws
SQLException
- {
- try
- {
- conn.createStatement().executeUpdate("SELECT 1 FROM " + tableName);
- return true;
- }
- catch (SQLException e)
- {
- // check: ORA-00942: table or view does not exist
- if (e.getMessage().indexOf("ORA-00942") >= 0)
- return false;
- throw e;
- }
- }
-
- @Override
- protected boolean isIndexExists(Connection conn, String tableName, String indexName)
throws SQLException
- {
- // use of oracle system view
- String sql = "SELECT COUNT(index_name) FROM all_indexes WHERE
index_name='" + indexName + "'";
- ResultSet r = conn.createStatement().executeQuery(sql);
- if (r.next())
- return r.getInt(1) > 0;
- else
- return false;
- }
-}
Added:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/CacheableJDBCLockManagerImpl.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/CacheableJDBCLockManagerImpl.java
(rev 0)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/CacheableJDBCLockManagerImpl.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -0,0 +1,1037 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * 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,
see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.services.jcr.impl.core.lock.jbosscache.jdbc;
+
+import org.exoplatform.container.configuration.ConfigurationManager;
+import org.exoplatform.management.annotations.Managed;
+import org.exoplatform.management.annotations.ManagedDescription;
+import org.exoplatform.management.jmx.annotations.NameTemplate;
+import org.exoplatform.management.jmx.annotations.Property;
+import org.exoplatform.services.jcr.access.SystemIdentity;
+import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.config.SimpleParameterEntry;
+import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.dataflow.ChangesLogIterator;
+import org.exoplatform.services.jcr.dataflow.CompositeChangesLog;
+import org.exoplatform.services.jcr.dataflow.DataManager;
+import org.exoplatform.services.jcr.dataflow.ItemState;
+import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
+import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
+import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl;
+import org.exoplatform.services.jcr.dataflow.TransactionChangesLog;
+import org.exoplatform.services.jcr.dataflow.persistent.ItemsPersistenceListener;
+import org.exoplatform.services.jcr.datamodel.ItemData;
+import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.PropertyData;
+import org.exoplatform.services.jcr.datamodel.QPathEntry;
+import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.core.lock.LockRemover;
+import org.exoplatform.services.jcr.impl.core.lock.SessionLockManager;
+import org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManager;
+import
org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableSessionLockManager;
+import org.exoplatform.services.jcr.impl.core.lock.jbosscache.LockData;
+import org.exoplatform.services.jcr.impl.dataflow.TransientItemData;
+import org.exoplatform.services.jcr.impl.dataflow.TransientPropertyData;
+import
org.exoplatform.services.jcr.impl.dataflow.persistent.WorkspacePersistentDataManager;
+import org.exoplatform.services.jcr.impl.storage.JCRInvalidItemStateException;
+import org.exoplatform.services.jcr.jbosscache.ExoJBossCacheFactory;
+import org.exoplatform.services.jcr.observation.ExtendedEvent;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.exoplatform.services.naming.InitialContextInitializer;
+import org.exoplatform.services.transaction.TransactionService;
+import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
+import org.picocontainer.Startable;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.lock.LockException;
+import javax.transaction.TransactionManager;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * <br/>Date:
+ *
+ * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
+ * @version $Id: CacheableLockManager.java 111 2008-11-11 11:11:11Z serg $
+ */
+@Managed
+@NameTemplate(@Property(key = "service", value = "lockmanager"))
+public class CacheableJDBCLockManagerImpl implements CacheableLockManager,
ItemsPersistenceListener, Startable
+{
+ /**
+ * The name to property time out.
+ */
+ public static final String TIME_OUT = "time-out";
+
+ /**
+ * The name to property cache configuration.
+ */
+ public static final String JBOSSCACCHE_CONFIG = "jbosscache-configuration";
+
+ /**
+ * The name of data source's property
+ */
+ public static final String DATA_SOURCE = "data-source";
+
+ /**
+ * Default lock time out. 30min
+ */
+ public static final long DEFAULT_LOCK_TIMEOUT = 1000 * 60 * 30;
+
+ /**
+ * Name of lock root in jboss-cache.
+ */
+ public static final String LOCKS = "$LOCKS";
+
+ /**
+ * Attribute name where LockData will be stored.
+ */
+ public static final String LOCK_DATA = "$LOCK_DATA";
+
+ /**
+ * Logger
+ */
+ private final Log log =
ExoLogger.getLogger("jcr.lock.CacheableLockManagerImpl");
+
+ /**
+ * Data manager.
+ */
+ private final DataManager dataManager;
+
+ /**
+ * Run time lock time out.
+ */
+ private long lockTimeOut;
+
+ /**
+ * Lock remover thread.
+ */
+ private LockRemover lockRemover;
+
+ /**
+ * The current Transaction Manager
+ */
+ private TransactionManager tm;
+
+ private Cache<Serializable, Object> cache;
+
+ private LockJDBCContainer lockJDBCContainer;
+
+ private final Fqn<String> lockRoot;
+
+ /**
+ * SessionLockManagers that uses this LockManager.
+ */
+ private Map<String, CacheableSessionLockManager> sessionLockManagers;
+
+ /**
+ * Constructor.
+ *
+ * @param dataManager - workspace persistent data manager
+ * @param config - workspace entry
+ * @param context InitialContextInitializer, needed to reload context after JBoss
cache creation
+ * @param transactionService
+ * the transaction service
+ * @throws RepositoryConfigurationException
+ */
+ public CacheableJDBCLockManagerImpl(WorkspacePersistentDataManager dataManager,
WorkspaceEntry config,
+ InitialContextInitializer context, TransactionService transactionService,
ConfigurationManager cfm)
+ throws RepositoryConfigurationException, RepositoryException
+ {
+ this(dataManager, config, context, transactionService.getTransactionManager(),
cfm);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param dataManager - workspace persistent data manager
+ * @param config - workspace entry
+ * @param context InitialContextInitializer, needed to reload context after JBoss
cache creation
+ * @throws RepositoryConfigurationException
+ */
+ public CacheableJDBCLockManagerImpl(WorkspacePersistentDataManager dataManager,
WorkspaceEntry config,
+ InitialContextInitializer context, ConfigurationManager cfm) throws
RepositoryConfigurationException,
+ RepositoryException
+ {
+ this(dataManager, config, context, (TransactionManager)null, cfm);
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param dataManager - workspace persistent data manager
+ * @param config - workspace entry
+ * @param context InitialContextInitializer, needed to reload context after JBoss
cache creation
+ * @param transactionManager
+ * the transaction manager
+ * @throws RepositoryConfigurationException
+ * @throws RepositoryException
+ */
+ public CacheableJDBCLockManagerImpl(WorkspacePersistentDataManager dataManager,
WorkspaceEntry config,
+ InitialContextInitializer context, TransactionManager transactionManager,
ConfigurationManager cfm)
+ throws RepositoryConfigurationException, RepositoryException
+ {
+ lockRoot = Fqn.fromElements(LOCKS);
+
+ List<SimpleParameterEntry> paramenerts =
config.getLockManager().getParameters();
+
+ this.dataManager = dataManager;
+ if (config.getLockManager() != null)
+ {
+ if (paramenerts != null &&
config.getLockManager().getParameterValue(TIME_OUT, null) != null)
+ {
+ long timeOut = config.getLockManager().getParameterTime(TIME_OUT);
+ lockTimeOut = timeOut > 0 ? timeOut : DEFAULT_LOCK_TIMEOUT;
+ }
+ else
+ {
+ lockTimeOut =
+ config.getLockManager().getTimeout() > 0 ?
config.getLockManager().getTimeout() : DEFAULT_LOCK_TIMEOUT;
+ }
+ }
+ else
+ {
+ lockTimeOut = DEFAULT_LOCK_TIMEOUT;
+ }
+
+ sessionLockManagers = new HashMap<String, CacheableSessionLockManager>();
+
+ dataManager.addItemPersistenceListener(this);
+
+ // make cache
+ if (config.getLockManager() != null)
+ {
+ this.tm = transactionManager;
+ String dataSourceName = config.getLockManager().getParameterValue(DATA_SOURCE);
+ lockJDBCContainer = new LockJDBCContainer(dataSourceName, config.getName());
+
+ // create cache using custom factory
+ ExoJBossCacheFactory<Serializable, Object> factory =
+ new ExoJBossCacheFactory<Serializable, Object>(cfm,
transactionManager);
+
+ cache = factory.createCache(config.getLockManager());
+
+ // Add the cache loader needed to prevent TimeoutException
+ cache.create();
+ cache.start();
+
+ createStructuredNode(lockRoot);
+
+ // Context recall is a workaround of JDBCCacheLoader starting.
+ context.recall();
+ }
+ else
+ {
+ throw new RepositoryConfigurationException("Cache configuration not
found");
+ }
+ }
+
+ @Managed
+ @ManagedDescription("Remove the expired locks")
+ public void cleanExpiredLocks()
+ {
+ removeExpired();
+ }
+
+ public long getDefaultLockTimeOut()
+ {
+ return lockTimeOut;
+ }
+
+ @Managed
+ @ManagedDescription("The number of active locks")
+ public int getNumLocks()
+ {
+ int lockNum = -1;
+ try
+ {
+ LockJDBCConnection connection = this.lockJDBCContainer.openConnection();
+ lockNum = connection.getLockedNodes().size();
+ }
+ catch (LockException e)
+ {
+ // skip
+ }
+ return lockNum;
+ }
+
+ /**
+ * Return new instance of session lock manager.
+ */
+ public SessionLockManager getSessionLockManager(String sessionId)
+ {
+ CacheableSessionLockManager sessionManager = new
CacheableSessionLockManager(sessionId, this);
+ sessionLockManagers.put(sessionId, sessionManager);
+ return sessionManager;
+ }
+
+ /**
+ * Check is LockManager contains lock. No matter it is in pending or persistent
state.
+ *
+ * @param nodeId - locked node id
+ * @return
+ */
+ public boolean isLockLive(String nodeId) throws LockException
+ {
+ return this.lockExist(nodeId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isTXAware()
+ {
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
@seeorg.exoplatform.services.jcr.dataflow.persistent.ItemsPersistenceListener#onSaveItems(org.
+ * exoplatform.services.jcr.dataflow.ItemStateChangesLog)
+ */
+ public void onSaveItems(ItemStateChangesLog changesLog)
+ {
+ List<PlainChangesLog> chengesLogList = new
ArrayList<PlainChangesLog>();
+ if (changesLog instanceof TransactionChangesLog)
+ {
+ ChangesLogIterator logIterator =
((TransactionChangesLog)changesLog).getLogIterator();
+
+ while (logIterator.hasNextLog())
+ {
+ chengesLogList.add(logIterator.nextLog());
+ }
+ }
+ else if (changesLog instanceof PlainChangesLog)
+ {
+ chengesLogList.add((PlainChangesLog)changesLog);
+ }
+ else if (changesLog instanceof CompositeChangesLog)
+ {
+ for (ChangesLogIterator iter =
((CompositeChangesLog)changesLog).getLogIterator(); iter.hasNextLog();)
+ {
+ chengesLogList.add(iter.nextLog());
+ }
+ }
+
+ List<LockOperationContainer> containers = new
ArrayList<LockOperationContainer>();
+
+ for (PlainChangesLog currChangesLog : chengesLogList)
+ {
+ String sessionId = currChangesLog.getSessionId();
+
+ String nodeIdentifier;
+ try
+ {
+ switch (currChangesLog.getEventType())
+ {
+ case ExtendedEvent.LOCK :
+ if (currChangesLog.getSize() < 2)
+ {
+ log.error("Incorrect changes log of type ExtendedEvent.LOCK
size=" + currChangesLog.getSize()
+ + "<2 \n" + currChangesLog.dump());
+ break;
+ }
+ nodeIdentifier =
currChangesLog.getAllStates().get(0).getData().getParentIdentifier();
+
+ CacheableSessionLockManager session =
sessionLockManagers.get(sessionId);
+ if (session != null &&
session.cotainsPendingLock(nodeIdentifier))
+ {
+ containers.add(new LockOperationContainer(nodeIdentifier,
currChangesLog.getSessionId(),
+ ExtendedEvent.LOCK));
+ }
+ else
+ {
+ log.error("Lock must exist in pending locks.");
+ }
+ break;
+ case ExtendedEvent.UNLOCK :
+ if (currChangesLog.getSize() < 2)
+ {
+ log.error("Incorrect changes log of type ExtendedEvent.UNLOCK
size=" + currChangesLog.getSize()
+ + "<2 \n" + currChangesLog.dump());
+ break;
+ }
+
+ containers.add(new
LockOperationContainer(currChangesLog.getAllStates().get(0).getData()
+ .getParentIdentifier(), currChangesLog.getSessionId(),
ExtendedEvent.UNLOCK));
+ break;
+ default :
+ HashSet<String> removedLock = new HashSet<String>();
+ for (ItemState itemState : currChangesLog.getAllStates())
+ {
+ // this is a node and node is locked
+ if (itemState.getData().isNode() &&
lockExist(itemState.getData().getIdentifier()))
+ {
+ nodeIdentifier = itemState.getData().getIdentifier();
+ if (itemState.isDeleted())
+ {
+ removedLock.add(nodeIdentifier);
+ }
+ else if (itemState.isAdded() || itemState.isRenamed() ||
itemState.isUpdated())
+ {
+ removedLock.remove(nodeIdentifier);
+ }
+ }
+ }
+ for (String identifier : removedLock)
+ {
+ containers.add(new LockOperationContainer(identifier,
currChangesLog.getSessionId(),
+ ExtendedEvent.UNLOCK));
+ }
+ break;
+ }
+ }
+ catch (IllegalStateException e)
+ {
+ log.error(e.getLocalizedMessage(), e);
+ }
+ catch (LockException e)
+ {
+ log.error(e.getLocalizedMessage(), e);
+ }
+ }
+
+ // sort locking and unlocking operations to avoid deadlocks in JBossCache
+ Collections.sort(containers);
+ for (LockOperationContainer container : containers)
+ {
+ try
+ {
+ container.apply();
+ }
+ catch (LockException e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * Class containing operation type (LOCK or UNLOCK) and all the needed information
like node uuid and session id.
+ */
+ private class LockOperationContainer implements
Comparable<LockOperationContainer>
+ {
+
+ private String identifier;
+
+ private String sessionId;
+
+ private int type;
+
+ /**
+ * @param identifier node identifier
+ * @param sessionId id of session
+ * @param type ExtendedEvent type specifying the operation (LOCK or UNLOCK)
+ */
+ public LockOperationContainer(String identifier, String sessionId, int type)
+ {
+ super();
+ this.identifier = identifier;
+ this.sessionId = sessionId;
+ this.type = type;
+ }
+
+ /**
+ * @return node identifier
+ */
+ public String getIdentifier()
+ {
+ return identifier;
+ }
+
+ public void apply() throws LockException
+ {
+ // invoke internalLock in LOCK operation
+ if (type == ExtendedEvent.LOCK)
+ {
+ internalLock(sessionId, identifier);
+ }
+ // invoke internalUnLock in UNLOCK operation
+ else if (type == ExtendedEvent.UNLOCK)
+ {
+ internalUnLock(sessionId, identifier);
+ }
+ }
+
+ /**
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(LockOperationContainer o)
+ {
+ return identifier.compareTo(o.getIdentifier());
+ }
+ }
+
+ /**
+ * Refreshed lock data in cache
+ *
+ * @param newLockData
+ */
+ public void refreshLockData(LockData newLockData) throws LockException
+ {
+ // TODO
+ // Write to DB
+ LockJDBCConnection connection = null;
+ try
+ {
+ connection = this.lockJDBCContainer.openConnection();
+ connection.refreshLockData(newLockData);
+ connection.commit();
+ // if database consistency not failed put to cache
+ Fqn<String> fqn = makeLockFqn(newLockData.getNodeIdentifier());
+ cache.put(fqn, LOCK_DATA, newLockData);
+ }
+ catch (RepositoryException e)
+ {
+ throw new LockException(e);
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ try
+ {
+ connection.close();
+ }
+ catch (IllegalStateException e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ catch (RepositoryException e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Remove expired locks. Used from LockRemover.
+ */
+ public synchronized void removeExpired()
+ {
+ // TODO
+ final List<String> removeLockList = new ArrayList<String>();
+ try
+ {
+ // traverse through list
+ List<LockData> lockDatas = getLockList();
+ for (LockData lock : lockDatas)
+ {
+ if (!lock.isSessionScoped() && lock.getTimeToDeath() < 0)
+ {
+ removeLockList.add(lock.getNodeIdentifier());
+ }
+ }
+ // apply changes in alphabetical order to prevent deadlocks on cache
+ Collections.sort(removeLockList);
+ for (String rLock : removeLockList)
+ {
+ removeLock(rLock);
+ }
+ }
+ catch (LockException e)
+ {
+ log.error("Exception removing expired locks", e);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.picocontainer.Startable#start()
+ */
+ public void start()
+ {
+ lockRemover = new LockRemover(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.picocontainer.Startable#stop()
+ */
+ public void stop()
+ {
+ lockRemover.halt();
+ lockRemover.interrupt();
+ sessionLockManagers.clear();
+ cache.stop();
+ }
+
+ /**
+ * Copy <code>PropertyData prop<code> to new TransientItemData
+ *
+ * @param prop
+ * @return
+ * @throws RepositoryException
+ */
+ private TransientItemData copyItemData(PropertyData prop) throws RepositoryException
+ {
+ if (prop == null)
+ {
+ return null;
+ }
+
+ // make a copy, value may be null for deleting items
+ TransientPropertyData newData =
+ new TransientPropertyData(prop.getQPath(), prop.getIdentifier(),
prop.getPersistedVersion(), prop.getType(),
+ prop.getParentIdentifier(), prop.isMultiValued(), prop.getValues());
+
+ return newData;
+ }
+
+ /**
+ * Internal lock
+ *
+ * @param nodeIdentifier
+ * @throws LockException
+ */
+ private synchronized void internalLock(String sessionId, String nodeIdentifier) throws
LockException
+ {
+ CacheableSessionLockManager sessionLockManager =
sessionLockManagers.get(sessionId);
+ if (sessionLockManager != null &&
sessionLockManager.cotainsPendingLock(nodeIdentifier))
+ {
+ LockData lockData = sessionLockManager.getPendingLock(nodeIdentifier);
+
+ //TODO
+ // add to DB for first
+ LockJDBCConnection connection = null;
+ try
+ {
+ // write to database
+ connection = this.lockJDBCContainer.openConnection();
+ connection.addLockData(lockData);
+ connection.commit();
+
+ // if any SQL exception, that nothing should be placed to cache
+ Fqn<String> lockPath = makeLockFqn(lockData.getNodeIdentifier());
+ Node<Serializable, Object> node = cache.getRoot().addChild(lockPath);
+ cache.put(lockPath, LOCK_DATA, lockData);
+
+ sessionLockManager.notifyLockPersisted(nodeIdentifier);
+ }
+ catch (RepositoryException e)
+ {
+ throw new LockException(e);
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ try
+ {
+ connection.close();
+ }
+ catch (IllegalStateException e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ catch (RepositoryException e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ else
+ {
+ // no pending lock found
+ throw new LockException("No lock in pending locks");
+ }
+ }
+
+ /**
+ * Internal unlock.
+ *
+ * @param sessionId
+ * @param nodeIdentifier
+ * @throws LockException
+ */
+ private synchronized void internalUnLock(String sessionId, String nodeIdentifier)
throws LockException
+ {
+ LockData lData = getLockDataById(nodeIdentifier);
+
+ if (lData != null)
+ {
+ //TODO
+ LockJDBCConnection connection = null;
+ try
+ {
+ //first remove from database
+ connection = this.lockJDBCContainer.openConnection();
+ connection.removeLockData(nodeIdentifier);
+ connection.commit();
+
+ //second remove from cache
+ cache.removeNode(makeLockFqn(nodeIdentifier));
+ CacheableSessionLockManager sessMgr = sessionLockManagers.get(sessionId);
+ if (sessMgr != null)
+ {
+ sessMgr.notifyLockRemoved(nodeIdentifier);
+ }
+ }
+ catch (RepositoryException e)
+ {
+ throw new LockException(e);
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ try
+ {
+ connection.close();
+ }
+ catch (IllegalStateException e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ catch (RepositoryException e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ }
+
+ private boolean lockExist(String nodeId) throws LockException
+ {
+ //TODO
+ //if present in cache - then exists
+ if (cache.get(makeLockFqn(nodeId), LOCK_DATA) != null)
+ {
+ return true;
+ }
+ else
+ {
+ // not present in cache, so check in database
+ LockJDBCConnection connection = null;
+ try
+ {
+ connection = this.lockJDBCContainer.openConnection();
+ return connection.getLockData(nodeId) != null;
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ try
+ {
+ connection.close();
+ }
+ catch (IllegalStateException e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ catch (RepositoryException e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Calculates md5 hash of string.
+ *
+ * @param token
+ * @return
+ */
+ public String getLockTokenHash(String token)
+ {
+ String hash = "";
+ try
+ {
+ MessageDigest m = MessageDigest.getInstance("MD5");
+ m.update(token.getBytes(), 0, token.length());
+ hash = new BigInteger(1, m.digest()).toString(16);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ log.error("Can't get instanse of MD5 MessageDigest!", e);
+ }
+ return hash;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public LockData getLockData(NodeData data, int searchType)
+ {
+ if (data == null)
+ return null;
+ LockData retval = null;
+ try
+ {
+ if ((searchType & SEARCH_EXECMATCH) != 0)
+ {
+ retval = getLockDataById(data.getIdentifier());
+ }
+ if (retval == null && (searchType & SEARCH_CLOSEDPARENT) != 0)
+ {
+
+ NodeData parentData =
(NodeData)dataManager.getItemData(data.getParentIdentifier());
+ if (parentData != null)
+ {
+ retval = getLockDataById(parentData.getIdentifier());
+ // parent not found try to fo upper
+ if (retval == null)
+ {
+ retval = getLockData(parentData, SEARCH_CLOSEDPARENT);
+ }
+ }
+ }
+ if (retval == null && (searchType & SEARCH_CLOSEDCHILD) != 0)
+ {
+
+ List<NodeData> childData = dataManager.getChildNodesData(data);
+ for (NodeData nodeData : childData)
+ {
+ retval = getLockDataById(nodeData.getIdentifier());
+ if (retval != null)
+ break;
+ }
+ if (retval == null)
+ {
+ // child not found try to find diper
+ for (NodeData nodeData : childData)
+ {
+ retval = getLockData(nodeData, SEARCH_CLOSEDCHILD);
+ if (retval != null)
+ break;
+ }
+ }
+ }
+ }
+ catch (RepositoryException e)
+ {
+ //TODO
+ log.error(e.getMessage(), e);
+ return null;
+ }
+
+ return retval;
+ }
+
+ protected LockData getLockDataById(String nodeId) throws LockException
+ {
+ //TODO
+ LockData lData = (LockData)cache.get(makeLockFqn(nodeId), LOCK_DATA);
+
+ if (lData != null)
+ {
+ return lData;
+ }
+ else
+ {
+ LockJDBCConnection connection = null;
+ try
+ {
+ connection = this.lockJDBCContainer.openConnection();
+ return connection.getLockData(nodeId);
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ try
+ {
+ connection.close();
+ }
+ catch (IllegalStateException e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ catch (RepositoryException e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ }
+
+ protected synchronized List<LockData> getLockList() throws LockException
+ {
+
+ //TODO
+
+ LockJDBCConnection connection = null;
+ try
+ {
+ connection = this.lockJDBCContainer.openConnection();
+ Set<String> nodesId = connection.getLockedNodes();
+ List<LockData> locksData = new ArrayList<LockData>();
+ for (String nodeId : nodesId)
+ {
+ LockData lockData = (LockData)cache.get(makeLockFqn((String)nodeId),
LOCK_DATA);
+ if (lockData != null)
+ {
+ locksData.add(lockData);
+ }
+ else
+ {
+ locksData.add(connection.getLockData(nodeId));
+ }
+
+ }
+ return locksData;
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ try
+ {
+ connection.close();
+ }
+ catch (IllegalStateException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ catch (RepositoryException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove lock, used by Lock remover.
+ *
+ * @param nodeIdentifier String
+ */
+ protected void removeLock(String nodeIdentifier)
+ {
+ try
+ {
+ NodeData nData = (NodeData)dataManager.getItemData(nodeIdentifier);
+
+ //TODO EXOJCR-412, should be refactored in future.
+ //Skip removing, because that node was removed in other node of cluster.
+ if (nData == null)
+ {
+ return;
+ }
+
+ PlainChangesLog changesLog =
+ new PlainChangesLogImpl(new ArrayList<ItemState>(),
SystemIdentity.SYSTEM, ExtendedEvent.UNLOCK);
+
+ ItemData lockOwner =
+ copyItemData((PropertyData)dataManager.getItemData(nData, new
QPathEntry(Constants.JCR_LOCKOWNER, 1)));
+
+ //TODO EXOJCR-412, should be refactored in future.
+ //Skip removing, because that lock was removed in other node of cluster.
+ if (lockOwner == null)
+ {
+ return;
+ }
+
+ changesLog.add(ItemState.createDeletedState(lockOwner));
+
+ ItemData lockIsDeep =
+ copyItemData((PropertyData)dataManager.getItemData(nData, new
QPathEntry(Constants.JCR_LOCKISDEEP, 1)));
+
+ //TODO EXOJCR-412, should be refactored in future.
+ //Skip removing, because that lock was removed in other node of cluster.
+ if (lockIsDeep == null)
+ {
+ return;
+ }
+
+ changesLog.add(ItemState.createDeletedState(lockIsDeep));
+
+ // lock probably removed by other thread
+ if (lockOwner == null && lockIsDeep == null)
+ {
+ return;
+ }
+
+ dataManager.save(new TransactionChangesLog(changesLog));
+ }
+ catch (JCRInvalidItemStateException e)
+ {
+ //TODO EXOJCR-412, should be refactored in future.
+ //Skip property not found in DB, because that lock property was removed in other
node of cluster.
+ if (log.isDebugEnabled())
+ {
+ log.debug("The propperty was removed in other node of cluster.",
e);
+ }
+
+ }
+ catch (RepositoryException e)
+ {
+ log.error("Error occur during removing lock" +
e.getLocalizedMessage(), e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void closeSessionLockManager(String sessionID)
+ {
+
+ sessionLockManagers.remove(sessionID);
+ }
+
+ /**
+ * Make lock absolute Fqn, i.e. /$LOCKS/nodeID.
+ *
+ * @param itemId String
+ * @return Fqn
+ */
+ private Fqn<String> makeLockFqn(String nodeId)
+ {
+ return Fqn.fromRelativeElements(lockRoot, nodeId);
+ }
+
+ /**
+ * Will be created structured node in cache, like /$LOCKS
+ */
+ private void createStructuredNode(Fqn<String> fqn)
+ {
+ Node<Serializable, Object> node = cache.getRoot().getChild(fqn);
+ if (node == null)
+ {
+ cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
+ node = cache.getRoot().addChild(fqn);
+ }
+ node.setResident(true);
+ }
+
+}
Property changes on:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/CacheableJDBCLockManagerImpl.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Copied:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockDBInitializer.java
(from rev 1693,
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockDBInitializer.java)
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockDBInitializer.java
(rev 0)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockDBInitializer.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * 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,
see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.services.jcr.impl.core.lock.jbosscache.jdbc;
+
+import org.exoplatform.services.jcr.impl.storage.jdbc.init.DBInitializerException;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * <br/>Date:
+ *
+ * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
+ * @version $Id: LockDBInitializer.java 111 2008-11-11 11:11:11Z serg $
+ */
+public class LockDBInitializer
+{
+ static public String SQL_DELIMITER = ";";
+
+ static public String SQL_DELIMITER_COMMENT_PREFIX = "/*$DELIMITER:";
+
+ static public String SQL_TABLE_NAME_PATTERN = "${table.name}";
+
+ static public String SQL_CREATETABLE =
"^(CREATE(\\s)+TABLE(\\s)+(IF(\\s)+NOT(\\s)+EXISTS(\\s)+)*){1}";
+
+ static public String SQL_CREATEVIEW =
"^(CREATE(\\s)+VIEW(\\s)+(IF(\\s)+NOT(\\s)+EXISTS(\\s)+)*){1}";
+
+ static public String SQL_OBJECTNAME =
"((JCR_[A-Z_]+){1}(\\s*?|(\\(\\))*?)+)+?";
+
+ static public String SQL_CREATEINDEX =
"^(CREATE(\\s)+(UNIQUE(\\s)+)*INDEX(\\s)+){1}";
+
+ static public String SQL_ONTABLENAME =
"(ON(\\s)+(JCR_[A-Z_]+){1}(\\s*?|(\\(\\))*?)+){1}";
+
+ static public String SQL_CREATESEQUENCE =
"^(CREATE(\\s)+SEQUENCE(\\s)+){1}";
+
+ static public String SQL_CREATETRIGGER =
"^(CREATE(\\s)+(OR(\\s){1}REPLACE(\\s)+)*TRIGGER(\\s)+){1}";
+
+ static public String SQL_TRIGGERNAME =
"(([A-Z_]+JCR_[A-Z_]+){1}(\\s*?|(\\(\\))*?)+)+?";
+
+ protected final Log log = ExoLogger.getLogger("jcr.LockDBInitializer");
+
+ protected final Connection connection;
+
+ protected final String containerName;
+
+ protected final String script;
+
+ //protected final boolean multiDb;
+
+ protected final Pattern creatTablePattern;
+
+ protected final Pattern creatViewPattern;
+
+ protected final Pattern dbObjectNamePattern;
+
+ protected final Pattern creatIndexPattern;
+
+ protected final Pattern onTableNamePattern;
+
+ protected final Pattern creatSequencePattern;
+
+ protected final Pattern creatTriggerPattern;
+
+ protected final Pattern dbTriggerNamePattern;
+
+ public LockDBInitializer(String containerName, Connection connection, String
scriptPath) throws IOException
+ {
+ this.connection = connection;
+ this.script = script(scriptPath);
+ this.containerName = containerName;
+
+ this.creatTablePattern = Pattern.compile(SQL_CREATETABLE,
Pattern.CASE_INSENSITIVE);
+ this.creatViewPattern = Pattern.compile(SQL_CREATEVIEW, Pattern.CASE_INSENSITIVE);
+ this.dbObjectNamePattern = Pattern.compile(SQL_OBJECTNAME,
Pattern.CASE_INSENSITIVE);
+ this.creatIndexPattern = Pattern.compile(SQL_CREATEINDEX,
Pattern.CASE_INSENSITIVE);
+ this.onTableNamePattern = Pattern.compile(SQL_ONTABLENAME,
Pattern.CASE_INSENSITIVE);
+ this.creatSequencePattern = Pattern.compile(SQL_CREATESEQUENCE,
Pattern.CASE_INSENSITIVE);
+ this.creatTriggerPattern = Pattern.compile(SQL_CREATETRIGGER,
Pattern.CASE_INSENSITIVE);
+ this.dbTriggerNamePattern = Pattern.compile(SQL_TRIGGERNAME,
Pattern.CASE_INSENSITIVE);
+ }
+
+ protected String script(String scriptPath) throws IOException
+ {
+ return readScriptResource(scriptPath);
+ }
+
+ protected String readScriptResource(String path) throws IOException
+ {
+ InputStream is = this.getClass().getResourceAsStream(path);
+ InputStreamReader isr = new InputStreamReader(is);
+ try
+ {
+ StringBuilder sbuff = new StringBuilder();
+ char[] buff = new char[is.available()];
+ int r = 0;
+ while ((r = isr.read(buff)) > 0)
+ {
+ sbuff.append(buff, 0, r);
+ }
+
+ return sbuff.toString();
+ }
+ finally
+ {
+ try
+ {
+ is.close();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ public String cleanWhitespaces(String string)
+ {
+ if (string != null)
+ {
+ char[] cc = string.toCharArray();
+ for (int ci = cc.length - 1; ci > 0; ci--)
+ {
+ if (Character.isWhitespace(cc[ci]))
+ {
+ cc[ci] = ' ';
+ }
+ }
+ return new String(cc);
+ }
+ return string;
+ }
+
+ protected boolean isTableExists(Connection conn, String tableName) throws
SQLException
+ {
+ ResultSet trs = conn.getMetaData().getTables(null, null, tableName, null);
+ boolean res = false;
+ while (trs.next())
+ {
+ res = true; // check for columns/table type matching etc.
+ }
+ return res;
+ }
+
+ protected boolean isIndexExists(Connection conn, String tableName, String indexName)
throws SQLException
+ {
+ ResultSet irs = conn.getMetaData().getIndexInfo(null, null, tableName, false,
true);
+ boolean res = false;
+ while (irs.next())
+ {
+ if (irs.getShort("TYPE") != DatabaseMetaData.tableIndexStatistic
+ &&
irs.getString("INDEX_NAME").equalsIgnoreCase(indexName))
+ res = true; // check for index params matching etc.
+ }
+ return res;
+ }
+
+ protected boolean isSequenceExists(Connection conn, String sequenceName) throws
SQLException
+ {
+ return false;
+ }
+
+ protected boolean isTriggerExists(Connection conn, String triggerName) throws
SQLException
+ {
+ return false;
+ }
+
+ public boolean isObjectExists(Connection conn, String sql) throws SQLException
+ {
+ Matcher tMatcher = creatTablePattern.matcher(sql);
+ if (tMatcher.find())
+ {
+ // CREATE TABLE
+ tMatcher = dbObjectNamePattern.matcher(sql);
+ if (tMatcher.find())
+ {
+ // got table name
+ String tableName = sql.substring(tMatcher.start(), tMatcher.end());
+ if (isTableExists(conn, tableName))
+ {
+ if (log.isDebugEnabled())
+ log.debug("Table is already exists " + tableName);
+ return true;
+ }
+ }
+ }
+ else if ((tMatcher = creatViewPattern.matcher(sql)).find())
+ {
+ // CREATE VIEW
+ tMatcher = dbObjectNamePattern.matcher(sql);
+ if (tMatcher.find())
+ {
+ // got view name
+ String tableName = sql.substring(tMatcher.start(), tMatcher.end());
+ if (isTableExists(conn, tableName))
+ {
+ if (log.isDebugEnabled())
+ log.debug("View is already exists " + tableName);
+ return true;
+ }
+ }
+ }
+ else if ((tMatcher = creatIndexPattern.matcher(sql)).find())
+ {
+ // CREATE INDEX
+ tMatcher = dbObjectNamePattern.matcher(sql);
+ if (tMatcher.find())
+ {
+ // got index name
+ String indexName = sql.substring(tMatcher.start(), tMatcher.end());
+ if ((tMatcher = onTableNamePattern.matcher(sql)).find())
+ {
+ String onTableName = sql.substring(tMatcher.start(), tMatcher.end());
+ if ((tMatcher = dbObjectNamePattern.matcher(onTableName)).find())
+ {
+ String tableName = onTableName.substring(tMatcher.start(),
tMatcher.end());
+ if (isIndexExists(conn, tableName, indexName))
+ {
+ if (log.isDebugEnabled())
+ log.debug("Index is already exists " + indexName);
+ return true;
+ }
+ }
+ else
+ {
+ log.warn("Index found but $TABLE_NAME is not detected '"
+ sql + "'");
+ }
+ }
+ else
+ {
+ log.warn("Index found but ON $TABLE_NAME clause is not detected
'" + sql + "'");
+ }
+ }
+ else
+ {
+ log.warn("Create index clause found but $INDEX_NAME is not detected
'" + sql + "'");
+ }
+ }
+ else if ((tMatcher = creatSequencePattern.matcher(sql)).find())
+ {
+ tMatcher = dbObjectNamePattern.matcher(sql);
+ if (tMatcher.find())
+ {
+ // got sequence name
+ String sequenceName = sql.substring(tMatcher.start(), tMatcher.end());
+ if (isSequenceExists(conn, sequenceName))
+ {
+ if (log.isDebugEnabled())
+ log.debug("Sequence is already exists " + sequenceName);
+ return true;
+ }
+ }
+ }
+ else if ((tMatcher = creatTriggerPattern.matcher(sql)).find())
+ {
+ tMatcher = dbTriggerNamePattern.matcher(sql);
+ if (tMatcher.find())
+ {
+ // got trigger name
+ String triggerName = sql.substring(tMatcher.start(), tMatcher.end());
+ if (isTriggerExists(conn, triggerName))
+ {
+ if (log.isDebugEnabled())
+ log.debug("Trigger is already exists " + triggerName);
+ return true;
+ }
+ }
+ }
+ else
+ {
+ if (log.isDebugEnabled())
+ log.debug("Command is not detected for check '" + sql +
"'");
+ }
+
+ return false;
+ }
+
+ public void init() throws DBInitializerException
+ {
+ String[] scripts = null;
+ if (script.startsWith(SQL_DELIMITER_COMMENT_PREFIX))
+ {
+ // read custom prefix
+ try
+ {
+ String s = script.substring(SQL_DELIMITER_COMMENT_PREFIX.length());
+ int endOfDelimIndex = s.indexOf("*/");
+ String delim = s.substring(0, endOfDelimIndex).trim();
+ s = s.substring(endOfDelimIndex + 2).trim();
+ scripts = s.split(delim);
+ }
+ catch (IndexOutOfBoundsException e)
+ {
+ log.warn("Error of parse SQL-script file. Invalid DELIMITER
configuration. Valid format is '"
+ + SQL_DELIMITER_COMMENT_PREFIX + "XXX*/' at begin of the
SQL-script file, where XXX - DELIMITER string."
+ + " Spaces will be trimed. ", e);
+ log.info("Using DELIMITER:[" + SQL_DELIMITER + "]");
+ scripts = script.split(SQL_DELIMITER);
+ }
+ }
+ else
+ {
+ scripts = script.split(SQL_DELIMITER);
+ }
+
+ String sql = null;
+ try
+ {
+ connection.setAutoCommit(false);
+
+ for (String scr : scripts)
+ {
+ String s = cleanWhitespaces(scr.trim());
+ if (s.length() > 0)
+ {
+ if (isObjectExists(connection, sql = s))
+ continue;
+
+ if (log.isDebugEnabled())
+ log.debug("Execute script: \n[" + sql + "]");
+
+ connection.createStatement().executeUpdate(sql);
+ }
+ }
+
+ //rootInit(connection);
+
+ connection.commit();
+ log.info("DB schema of DataSource: '" + containerName +
"' initialized succesfully");
+ }
+ catch (SQLException e)
+ {
+ try
+ {
+ connection.rollback();
+ }
+ catch (SQLException re)
+ {
+ log.error("Rollback error " + e, e);
+ }
+
+ SQLException next = e.getNextException();
+ String errorTrace = "";
+ while (next != null)
+ {
+ errorTrace += next.getMessage() + "; ";
+ next = e.getNextException();
+ }
+ Throwable cause = e.getCause();
+ String msg =
+ "Could not create db schema of DataSource: '" + containerName +
"'. Reason: " + e.getMessage() + "; "
+ + errorTrace + (cause != null ? " (Cause: " + cause.getMessage()
+ ")" : "") + ". Last command: " + sql;
+
+ throw new DBInitializerException(msg, e);
+ }
+ finally
+ {
+ try
+ {
+ connection.close();
+ }
+ catch (SQLException e)
+ {
+ log.error("Error of a connection closing. " + e, e);
+ }
+ }
+ }
+}
Copied:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockJDBCConnection.java
(from rev 1693,
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockJDBCConnection.java)
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockJDBCConnection.java
(rev 0)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockJDBCConnection.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * 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,
see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.services.jcr.impl.core.lock.jbosscache.jdbc;
+
+import org.exoplatform.services.jcr.impl.core.lock.jbosscache.LockData;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.lock.LockException;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * <br/>Date:
+ *
+ * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
+ * @version $Id: LockJDBCConnection.java 111 2008-11-11 11:11:11Z serg $
+ */
+public class LockJDBCConnection
+{
+
+ private final Log LOG = ExoLogger.getLogger(LockJDBCContainer.class);
+
+ // queries
+ protected String ADD_LOCK_DATA;
+
+ protected String REMOVE_LOCK_DATA;
+
+ protected String REFRESH_LOCK_DATA;
+
+ protected String GET_LOCKED_NODES;
+
+ protected String GET_LOCK_DATA;
+
+ // column names
+ protected static String COLUMN_WS_NAME = "WS_NAME";
+
+ protected static String COLUMN_NODE_ID = "NODE_ID";
+
+ protected static String COLUMN_TOKEN_HASH = "TOKEN_HASH";
+
+ protected static String COLUMN_OWNER = "OWNER";
+
+ protected static String COLUMN_IS_SESSIONSCOPED = "IS_SESSIONSCOPED";
+
+ protected static String COLUMN_IS_DEEP = "IS_DEEP";
+
+ protected static String COLUMN_BIRTHDAY = "BIRTHDAY";
+
+ protected static String COLUMN_TIMEOUT = "TIMEOUT";
+
+ // prepared statements
+ private PreparedStatement insertLockData;
+
+ private PreparedStatement removeLockData;
+
+ private PreparedStatement refreshLockData;
+
+ private PreparedStatement getLockedNodes;
+
+ private PreparedStatement getLockData;
+
+ private Connection dbConnection;
+
+ private String wsName;
+
+ /**
+ * Creates LockJDBCConnection instance based on given connection to
+ * database with specified workspace name.
+ *
+ * @param dbConnection Connection to database.
+ * @param wsName Current workspace's name.
+ * @throws SQLException if database exception occurs.
+ */
+ public LockJDBCConnection(Connection dbConnection, String wsName) throws SQLException
+ {
+ this.dbConnection = dbConnection;
+
+ if (dbConnection.getAutoCommit())
+ {
+ dbConnection.setAutoCommit(false);
+ }
+ this.wsName = wsName;
+
+ ADD_LOCK_DATA =
+ "insert into JCR_LOCKS(WS_NAME, NODE_ID, TOKEN_HASH, OWNER,
IS_SESSIONSCOPED, IS_DEEP, BIRTHDAY, TIMEOUT) VALUES(?,?,?,?,?,?,?,?)";
+
+ REMOVE_LOCK_DATA = "delete from JCR_LOCKS where NODE_ID=? and
WS_NAME=?";
+
+ REFRESH_LOCK_DATA = "update JCR_LOCKS set BIRTHDAY=? where NODE_ID=? and
WS_NAME=?";
+
+ GET_LOCKED_NODES = "select NODE_ID from JCR_LOCKS where WS_NAME=?";
+
+ GET_LOCK_DATA = "select * from JCR_LOCKS where NODE_ID=? and WS_NAME=?";
+ }
+
+ /**
+ * Inserts new lock data into DB
+ *
+ * @param data
+ * @return
+ * @throws LockException
+ */
+ public int addLockData(LockData data) throws LockException
+ {
+ if (!isOpened())
+ {
+ throw new IllegalStateException("Connection is closed");
+ }
+ try
+ {
+ if (insertLockData == null)
+ {
+ insertLockData = dbConnection.prepareStatement(ADD_LOCK_DATA);
+ }
+ else
+ {
+ insertLockData.clearParameters();
+ }
+ insertLockData.setString(1, wsName);
+ insertLockData.setString(2, data.getNodeIdentifier());
+ insertLockData.setString(3, data.getTokenHash());
+ insertLockData.setString(4, data.getOwner());
+ insertLockData.setBoolean(5, data.isSessionScoped());
+ insertLockData.setBoolean(6, data.isDeep());
+ insertLockData.setLong(7, data.getBirthDay());
+ insertLockData.setLong(8, data.getTimeOut());
+
+ return insertLockData.executeUpdate();
+ }
+ catch (SQLException e)
+ {
+ throw new LockException(e);
+ }
+ }
+
+ /**
+ * Removes LockData for given node identifier from database
+ *
+ * @param nodeID
+ * @return
+ * @throws LockException
+ */
+ public int removeLockData(String nodeID) throws LockException
+ {
+ if (!isOpened())
+ {
+ throw new IllegalStateException("Connection is closed");
+ }
+ try
+ {
+ if (removeLockData == null)
+ {
+ removeLockData = dbConnection.prepareStatement(REMOVE_LOCK_DATA);
+ }
+ else
+ {
+ removeLockData.clearParameters();
+ }
+ // REMOVE_LOCK_DATA = "delete from JCR_LOCKS where NODE_ID=? and
WS_NAME=?";
+ removeLockData.setString(1, nodeID);
+ removeLockData.setString(2, wsName);
+
+ return removeLockData.executeUpdate();
+ }
+ catch (SQLException e)
+ {
+ throw new LockException(e);
+ }
+ }
+
+ /**
+ * Refreshes given LockData (updates birthday column)
+ *
+ * @param data
+ * @return
+ * @throws LockException
+ */
+ public int refreshLockData(LockData data) throws LockException
+ {
+ if (!isOpened())
+ {
+ throw new IllegalStateException("Connection is closed");
+ }
+ try
+ {
+ if (refreshLockData == null)
+ {
+ refreshLockData = dbConnection.prepareStatement(REFRESH_LOCK_DATA);
+ }
+ else
+ {
+ refreshLockData.clearParameters();
+ }
+
+ // REFRESH_LOCK_DATA = "update JCR_LOCKS set BIRTHDAY=? where NODE_ID=? and
WS_NAME=?";
+ refreshLockData.setLong(1, data.getBirthDay());
+ refreshLockData.setString(2, data.getNodeIdentifier());
+ refreshLockData.setString(3, wsName);
+
+ return refreshLockData.executeUpdate();
+ }
+ catch (SQLException e)
+ {
+ throw new LockException(e);
+ }
+ }
+
+ /**
+ * Returns the set of locked nodes identifiers
+ *
+ * @return
+ * @throws LockException
+ */
+ public Set<String> getLockedNodes() throws LockException
+ {
+ if (!isOpened())
+ {
+ throw new IllegalStateException("Connection is closed");
+ }
+ try
+ {
+ if (getLockedNodes == null)
+ {
+ getLockedNodes = dbConnection.prepareStatement(GET_LOCKED_NODES);
+ }
+ else
+ {
+ getLockedNodes.clearParameters();
+ }
+ // GET_LOCKED_NODES = "select NODE_ID from JCR_LOCKS where
WS_NAME=?";
+ getLockedNodes.setString(1, wsName);
+ // get result set
+ ResultSet result = getLockedNodes.executeQuery();
+ Set<String> identifiers = new HashSet<String>();
+ // traverse result set
+ while (result.next())
+ {
+ identifiers.add(new String(result.getString(COLUMN_NODE_ID)));
+ }
+ return identifiers;
+ }
+ catch (SQLException e)
+ {
+ throw new LockException(e);
+ }
+ }
+
+ /**
+ * Returns LockData for given node identifier from database
+ * or null if not exists
+ *
+ * @param identifier
+ * @return
+ * @throws LockException
+ */
+ public LockData getLockData(String identifier) throws LockException
+ {
+ if (!isOpened())
+ {
+ throw new IllegalStateException("Connection is closed");
+ }
+ try
+ {
+ if (getLockData == null)
+ {
+ getLockData = dbConnection.prepareStatement(GET_LOCK_DATA);
+ }
+ else
+ {
+ getLockData.clearParameters();
+ }
+ // GET_LOCK_DATA = "select * from JCR_LOCKS where NODE_ID=? and
WS_NAME=?";
+ getLockData.setString(1, identifier);
+ getLockData.setString(2, wsName);
+ // get result set
+ ResultSet result = getLockData.executeQuery();
+ if (result.next())
+ {
+ return new LockData(result.getString(COLUMN_NODE_ID),
result.getString(COLUMN_TOKEN_HASH), result
+ .getBoolean(COLUMN_IS_DEEP), result.getBoolean(COLUMN_IS_SESSIONSCOPED),
result.getString(COLUMN_OWNER),
+ result.getLong(COLUMN_TIMEOUT), result.getLong(COLUMN_BIRTHDAY));
+ }
+ return null;
+ }
+ catch (SQLException e)
+ {
+ throw new LockException(e);
+ }
+ }
+
+ /**
+ * Check if connection is alive and opened
+ * @return
+ */
+ public boolean isOpened()
+ {
+ try
+ {
+ return !dbConnection.isClosed();
+ }
+ catch (SQLException e)
+ {
+ LOG.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ /**
+ * Closes database connection
+ *
+ * @throws IllegalStateException
+ * @throws RepositoryException
+ */
+ public final void close() throws IllegalStateException, RepositoryException
+ {
+ if (!isOpened())
+ {
+ throw new IllegalStateException("Connection is closed");
+ }
+
+ try
+ {
+ dbConnection.close();
+ }
+ catch (SQLException e)
+ {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * Commits and closes database connection
+ *
+ * @throws IllegalStateException
+ * @throws RepositoryException
+ */
+ public final void commit() throws IllegalStateException, RepositoryException
+ {
+ if (!isOpened())
+ {
+ throw new IllegalStateException("Connection is closed");
+ }
+ try
+ {
+ if (!dbConnection.isReadOnly())
+ {
+ dbConnection.commit();
+ }
+
+ dbConnection.close();
+ }
+ catch (SQLException e)
+ {
+ throw new RepositoryException(e);
+ }
+ }
+
+}
Copied:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockJDBCContainer.java
(from rev 1693,
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/LockPersistentDataManager.java)
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockJDBCContainer.java
(rev 0)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/LockJDBCContainer.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.core.lock.jbosscache.jdbc;
+
+import org.exoplatform.services.jcr.impl.storage.jdbc.DBConstants;
+import org.exoplatform.services.jcr.impl.storage.jdbc.DialectDetecter;
+import org.exoplatform.services.jcr.impl.storage.jdbc.init.DBInitializerException;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.lock.LockException;
+import javax.naming.InitialContext;
+import javax.sql.DataSource;
+
+/**
+ * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay
Zamosenchuk</a>
+ * @version $Id: LockPersistentDataManager.java 34360 2009-07-22 23:58:59Z nzamosenchuk
$
+ *
+ */
+public class LockJDBCContainer
+{
+ private final Log log = ExoLogger.getLogger(LockJDBCContainer.class);
+
+ private DataSource dataSource;
+
+ private String wsName;
+
+ /**
+ * @param dataSourceName DataSource name
+ * @param tableName Name of DB table
+ * @throws RepositoryException
+ */
+ public LockJDBCContainer(String dataSourceName, String wsName) throws
RepositoryException
+ {
+ // TODO : rework exception handling
+ this.wsName = wsName;
+
+ // try to resolve DataSource
+ try
+ {
+ dataSource = (DataSource)new InitialContext().lookup(dataSourceName);
+ if (dataSource != null)
+ {
+ // initialize DB table if needed
+ try
+ {
+ log.info("Creating LockManager DB tables.");
+ Connection jdbcConn = dataSource.getConnection();
+ String dialect = DialectDetecter.detect(jdbcConn.getMetaData());
+ // if table not exists, create it
+ // connection is closed by DB initializer
+ initDatabase(dataSourceName, jdbcConn, dialect);
+ }
+ catch (SQLException e)
+ {
+ throw new RepositoryException(e);
+ }
+ catch (IOException e)
+ {
+ throw new RepositoryException(e);
+ }
+ }
+ else
+ {
+ throw new RepositoryException("Datasource '" + dataSourceName +
"' is not bound in this context.");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new RepositoryException(e);
+ }
+
+ }
+
+ public LockJDBCConnection openConnection() throws LockException
+ {
+ try
+ {
+ return new LockJDBCConnection(getJDBCConnection(), wsName);
+ }
+ catch (SQLException e)
+ {
+ throw new LockException(e);
+ }
+ }
+
+ /**
+ * Returns connection to database
+ * @return
+ *
+ * @return connection to database
+ * @throws RepositoryException
+ * @throws RepositoryException
+ */
+ private Connection getJDBCConnection() throws LockException
+ {
+ try
+ {
+ //TODO make connection as in GenericConnectionFactory
+ return dataSource.getConnection();
+
+ }
+ catch (SQLException e)
+ {
+ String err =
+ "Error of JDBC connection open. SQLException: " + e.getMessage() +
", SQLState: " + e.getSQLState()
+ + ", VendorError: " + e.getErrorCode();
+ throw new LockException(err, e);
+ }
+ }
+
+ /**
+ * Creates table in DB if not present
+ *
+ * @param dialect
+ * @throws IOException
+ * @throws DBInitializerException
+ */
+ protected void initDatabase(String dataSource, Connection jdbcConn, String dialect)
throws IOException,
+ DBInitializerException
+ {
+ LockDBInitializer dbInitializer = null;
+
+ // prepare DB
+ if (DBConstants.DB_DIALECT_ORACLE.equals(dialect))
+ {
+ // oracle preparation script
+ String sqlPath = "/conf/storage/lock-jdbc.ora.sql";
+ dbInitializer = new OracleLockDBInitializer(dataSource, jdbcConn, sqlPath);
+ }
+ else
+ {
+ // generic preparation script
+ String sqlPath = "/conf/storage/lock-jdbc.default.sql";
+ dbInitializer = new LockDBInitializer(dataSource, jdbcConn, sqlPath);
+ }
+
+ // init DB
+ dbInitializer.init();
+ }
+
+}
\ No newline at end of file
Copied:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/OracleLockDBInitializer.java
(from rev 1693,
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/OracleLockDBInitializer.java)
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/OracleLockDBInitializer.java
(rev 0)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/jdbc/OracleLockDBInitializer.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * 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,
see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.services.jcr.impl.core.lock.jbosscache.jdbc;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * <br/>Date:
+ *
+ * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
+ * @version $Id: OracleLockDBInitializer.java 111 2008-11-11 11:11:11Z serg $
+ */
+public class OracleLockDBInitializer extends LockDBInitializer
+{
+
+ public OracleLockDBInitializer(String containerName, Connection connection, String
script) throws IOException
+ {
+ super(containerName, connection, script);
+ }
+
+ @Override
+ protected boolean isSequenceExists(Connection conn, String sequenceName) throws
SQLException
+ {
+ try
+ {
+ ResultSet srs = conn.createStatement().executeQuery("SELECT " +
sequenceName + ".nextval FROM DUAL");
+ if (srs.next())
+ {
+ return true;
+ }
+ srs.close();
+ return false;
+ }
+ catch (SQLException e)
+ {
+ // check: ORA-02289: sequence does not exist
+ if (e.getMessage().indexOf("ORA-02289") >= 0)
+ return false;
+ throw e;
+ }
+ }
+
+ @Override
+ protected boolean isTriggerExists(Connection conn, String triggerName) throws
SQLException
+ {
+ String sql = "SELECT COUNT(trigger_name) FROM all_triggers WHERE trigger_name
= '" + triggerName + "'";
+ ResultSet r = conn.createStatement().executeQuery(sql);
+ if (r.next())
+ return r.getInt(1) > 0;
+ else
+ return false;
+ }
+
+ @Override
+ protected boolean isTableExists(Connection conn, String tableName) throws
SQLException
+ {
+ try
+ {
+ conn.createStatement().executeUpdate("SELECT 1 FROM " + tableName);
+ return true;
+ }
+ catch (SQLException e)
+ {
+ // check: ORA-00942: table or view does not exist
+ if (e.getMessage().indexOf("ORA-00942") >= 0)
+ return false;
+ throw e;
+ }
+ }
+
+ @Override
+ protected boolean isIndexExists(Connection conn, String tableName, String indexName)
throws SQLException
+ {
+ // use of oracle system view
+ String sql = "SELECT COUNT(index_name) FROM all_indexes WHERE
index_name='" + indexName + "'";
+ ResultSet r = conn.createStatement().executeQuery(sql);
+ if (r.next())
+ return r.getInt(1) > 0;
+ else
+ return false;
+ }
+}
Modified:
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/core/lock/TestLockPerstistentDataManager.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/core/lock/TestLockPerstistentDataManager.java 2010-02-05
12:37:39 UTC (rev 1697)
+++
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/core/lock/TestLockPerstistentDataManager.java 2010-02-05
13:29:35 UTC (rev 1698)
@@ -20,8 +20,8 @@
import org.exoplatform.services.jcr.JcrImplBaseTest;
import org.exoplatform.services.jcr.impl.core.lock.jbosscache.LockData;
-import org.exoplatform.services.jcr.impl.core.lock.jbosscache.LockJDBCConnection;
-import org.exoplatform.services.jcr.impl.core.lock.jbosscache.LockPersistentDataManager;
+import org.exoplatform.services.jcr.impl.core.lock.jbosscache.jdbc.LockJDBCConnection;
+import org.exoplatform.services.jcr.impl.core.lock.jbosscache.jdbc.LockJDBCContainer;
import java.util.Set;
@@ -37,18 +37,18 @@
{
public void testAddLockData() throws RepositoryException
{
- LockPersistentDataManager dataManager = new
LockPersistentDataManager("jdbcjcrtest", "ws");
+ LockJDBCContainer dataManager = new LockJDBCContainer("jdbcjcrtest",
"ws");
LockJDBCConnection connection = null;
try
{
// get connection to lock storage
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
// put lock data
connection.addLockData(new LockData("identifier", "hash",
false, false, "owner", 100));
// commit also closes connection
connection.commit();
// acquire new connection
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
// get lock data
LockData lockData = connection.getLockData("identifier");
// asserts
@@ -67,18 +67,18 @@
public void testRemoveLockData() throws RepositoryException
{
- LockPersistentDataManager dataManager = new
LockPersistentDataManager("jdbcjcrtest", "ws");
+ LockJDBCContainer dataManager = new LockJDBCContainer("jdbcjcrtest",
"ws");
LockJDBCConnection connection = null;
try
{
// get connection to lock storage
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
// put lock data
connection.addLockData(new LockData("identifier2", "hash",
false, false, "owner", 100));
// commit also closes connection
connection.commit();
// acquire new connection
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
// get lock data
LockData lockData = connection.getLockData("identifier2");
// asserts
@@ -88,7 +88,7 @@
// commit also closes connection
connection.commit();
// acquire new connection
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
lockData = connection.getLockData("identifier2");
// asserts
assertTrue("Lock data should be null", lockData == null);
@@ -104,12 +104,12 @@
public void testRefreshLockData() throws RepositoryException
{
- LockPersistentDataManager dataManager = new
LockPersistentDataManager("jdbcjcrtest", "ws");
+ LockJDBCContainer dataManager = new LockJDBCContainer("jdbcjcrtest",
"ws");
LockJDBCConnection connection = null;
try
{
// get connection to lock storage
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
// put lock data
connection.addLockData(new LockData("identifier3", "hash",
false, false, "owner", 100));
// commit also closes connection
@@ -123,7 +123,7 @@
{
}
// acquire new connection
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
// get lock Data
LockData lockData = connection.getLockData("identifier3");
Long timeToDeathOriginal = lockData.getTimeToDeath();
@@ -132,7 +132,7 @@
// commit also closes connection
connection.commit();
// acquire new connection
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
lockData = connection.getLockData("identifier3");
Long timeToDeathNew = lockData.getTimeToDeath();
// asserts
@@ -149,13 +149,13 @@
public void testgetLockedNodes() throws RepositoryException
{
- LockPersistentDataManager dataManager = new
LockPersistentDataManager("jdbcjcrtest", "test_workspace");
- LockPersistentDataManager dataManagerAnotherWS = new
LockPersistentDataManager("jdbcjcrtest", "another_workspace");
+ LockJDBCContainer dataManager = new LockJDBCContainer("jdbcjcrtest",
"test_workspace");
+ LockJDBCContainer dataManagerAnotherWS = new
LockJDBCContainer("jdbcjcrtest", "another_workspace");
LockJDBCConnection connection = null;
try
{
// get connection to lock storage
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
// put lock data
connection.addLockData(new LockData("identifier1-listTest",
"hash1", false, false, "owner", 100));
connection.addLockData(new LockData("identifier2-listTest",
"hash2", false, false, "owner", 100));
@@ -165,12 +165,12 @@
connection.commit();
// Adding lock data to another workspace
- connection = dataManagerAnotherWS.openConnection(false);
+ connection = dataManagerAnotherWS.openConnection();
// this lock data is from another workspace and shouldn't be in result set
connection.addLockData(new LockData("identifier1-listTest",
"hash1", false, false, "owner", 100));
connection.commit();
// acquire new connection
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
// get set
Set<String> identifiers = connection.getLockedNodes();
assertEquals("Wrong size of result.", 4, identifiers.size());
@@ -186,18 +186,18 @@
public void testAddLockDataTwice() throws RepositoryException
{
- LockPersistentDataManager dataManager = new
LockPersistentDataManager("jdbcjcrtest", "ws");
+ LockJDBCContainer dataManager = new LockJDBCContainer("jdbcjcrtest",
"ws");
LockJDBCConnection connection = null;
try
{
// get connection to lock storage
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
// put lock data
connection.addLockData(new LockData("identifier", "hash",
false, false, "owner", 100));
// commit also closes connection
connection.commit();
// acquire new connection
- connection = dataManager.openConnection(false);
+ connection = dataManager.openConnection();
// put lock data with same identifier
connection.addLockData(new LockData("identifier", "hash",
false, false, "owner", 100));
fail("exception expected!");