mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Change license to Apache2 and reformat
This commit is contained in:
@@ -1,19 +0,0 @@
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
|
||||
<id>agent</id>
|
||||
<formats>
|
||||
<format>jar</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>target/classes</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<includes>
|
||||
<include>com/avaje/ebean/enhance/**</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -1,254 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.jdbc;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.Savepoint;
|
||||
import java.sql.Statement;
|
||||
import java.util.Map;
|
||||
|
||||
public class ConnectionDelegator implements Connection
|
||||
{
|
||||
private final Connection delegate;
|
||||
|
||||
public ConnectionDelegator(Connection delegate)
|
||||
{
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public Statement createStatement()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement();
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql);
|
||||
}
|
||||
|
||||
public String nativeSQL(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.nativeSQL(sql);
|
||||
}
|
||||
|
||||
public void setAutoCommit(boolean autoCommit)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setAutoCommit(autoCommit);
|
||||
}
|
||||
|
||||
public boolean getAutoCommit()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getAutoCommit();
|
||||
}
|
||||
|
||||
public void commit()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.commit();
|
||||
}
|
||||
|
||||
public void rollback()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.rollback();
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
public boolean isClosed()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isClosed();
|
||||
}
|
||||
|
||||
public DatabaseMetaData getMetaData()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMetaData();
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setReadOnly(readOnly);
|
||||
}
|
||||
|
||||
public boolean isReadOnly()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isReadOnly();
|
||||
}
|
||||
|
||||
public void setCatalog(String catalog)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setCatalog(catalog);
|
||||
}
|
||||
|
||||
public String getCatalog()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getCatalog();
|
||||
}
|
||||
|
||||
public void setTransactionIsolation(int level)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTransactionIsolation(level);
|
||||
}
|
||||
|
||||
public int getTransactionIsolation()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getTransactionIsolation();
|
||||
}
|
||||
|
||||
public SQLWarning getWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getWarnings();
|
||||
}
|
||||
|
||||
public void clearWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.clearWarnings();
|
||||
}
|
||||
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement(resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql, resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public Map<String, Class<?>> getTypeMap()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getTypeMap();
|
||||
}
|
||||
|
||||
public void setTypeMap(Map<String, Class<?>> map)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTypeMap(map);
|
||||
}
|
||||
|
||||
public void setHoldability(int holdability)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setHoldability(holdability);
|
||||
}
|
||||
|
||||
public int getHoldability()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getHoldability();
|
||||
}
|
||||
|
||||
public Savepoint setSavepoint()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.setSavepoint();
|
||||
}
|
||||
|
||||
public Savepoint setSavepoint(String name)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.setSavepoint(name);
|
||||
}
|
||||
|
||||
public void rollback(Savepoint savepoint)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.rollback(savepoint);
|
||||
}
|
||||
|
||||
public void releaseSavepoint(Savepoint savepoint)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.releaseSavepoint(savepoint);
|
||||
}
|
||||
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, autoGeneratedKeys);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, columnIndexes);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, String[] columnNames)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, columnNames);
|
||||
}
|
||||
}
|
||||
@@ -1,492 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.jdbc;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Date;
|
||||
import java.sql.ParameterMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Ref;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class PreparedStatementDelegator implements PreparedStatement
|
||||
{
|
||||
private final PreparedStatement delegate;
|
||||
|
||||
public PreparedStatementDelegator(PreparedStatement delegate)
|
||||
{
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public ResultSet executeQuery()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeQuery();
|
||||
}
|
||||
|
||||
public int executeUpdate()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeUpdate();
|
||||
}
|
||||
|
||||
public void setNull(int parameterIndex, int sqlType)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setNull(parameterIndex, sqlType);
|
||||
}
|
||||
|
||||
public void setBoolean(int parameterIndex, boolean x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBoolean(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setByte(int parameterIndex, byte x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setByte(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setShort(int parameterIndex, short x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setShort(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setInt(int parameterIndex, int x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setInt(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setLong(int parameterIndex, long x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setLong(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setFloat(int parameterIndex, float x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setFloat(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setDouble(int parameterIndex, double x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setDouble(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setBigDecimal(int parameterIndex, BigDecimal x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBigDecimal(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setString(int parameterIndex, String x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setString(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setBytes(int parameterIndex, byte[] x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBytes(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setDate(int parameterIndex, Date x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setDate(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setTime(int parameterIndex, Time x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTime(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setTimestamp(int parameterIndex, Timestamp x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTimestamp(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setAsciiStream(int parameterIndex, InputStream x, int length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setAsciiStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void setUnicodeStream(int parameterIndex, InputStream x, int length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setUnicodeStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
public void setBinaryStream(int parameterIndex, InputStream x, int length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBinaryStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
public void clearParameters()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.clearParameters();
|
||||
}
|
||||
|
||||
public void setObject(int i, Object o, int i1, int i2) throws SQLException
|
||||
{
|
||||
delegate.setObject(i, o, i1, i2);
|
||||
}
|
||||
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setObject(parameterIndex, x, targetSqlType);
|
||||
}
|
||||
|
||||
public void setObject(int parameterIndex, Object x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setObject(parameterIndex, x);
|
||||
}
|
||||
|
||||
public boolean execute()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.execute();
|
||||
}
|
||||
|
||||
public void addBatch()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.addBatch();
|
||||
}
|
||||
|
||||
public void setCharacterStream(int parameterIndex, Reader reader, int length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setCharacterStream(parameterIndex, reader, length);
|
||||
}
|
||||
|
||||
public void setRef(int parameterIndex, Ref x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setRef(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setBlob(int parameterIndex, Blob x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBlob(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setClob(int parameterIndex, Clob x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setClob(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setArray(int parameterIndex, Array x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setArray(parameterIndex, x);
|
||||
}
|
||||
|
||||
public ResultSetMetaData getMetaData()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMetaData();
|
||||
}
|
||||
|
||||
public void setDate(int parameterIndex, Date x, Calendar cal)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setDate(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
public void setTime(int parameterIndex, Time x, Calendar cal)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTime(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTimestamp(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
public void setNull(int parameterIndex, int sqlType, String typeName)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setNull(parameterIndex, sqlType, typeName);
|
||||
}
|
||||
|
||||
public void setURL(int parameterIndex, URL x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setURL(parameterIndex, x);
|
||||
}
|
||||
|
||||
public ParameterMetaData getParameterMetaData()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getParameterMetaData();
|
||||
}
|
||||
|
||||
public ResultSet executeQuery(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeQuery(sql);
|
||||
}
|
||||
|
||||
public int executeUpdate(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeUpdate(sql);
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
public int getMaxFieldSize()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMaxFieldSize();
|
||||
}
|
||||
|
||||
public void setMaxFieldSize(int max)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setMaxFieldSize(max);
|
||||
}
|
||||
|
||||
public int getMaxRows()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMaxRows();
|
||||
}
|
||||
|
||||
public void setMaxRows(int max)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setMaxRows(max);
|
||||
}
|
||||
|
||||
public void setEscapeProcessing(boolean enable)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setEscapeProcessing(enable);
|
||||
}
|
||||
|
||||
public int getQueryTimeout()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getQueryTimeout();
|
||||
}
|
||||
|
||||
public void setQueryTimeout(int seconds)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setQueryTimeout(seconds);
|
||||
}
|
||||
|
||||
public void cancel()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.cancel();
|
||||
}
|
||||
|
||||
public SQLWarning getWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getWarnings();
|
||||
}
|
||||
|
||||
public void clearWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.clearWarnings();
|
||||
}
|
||||
|
||||
public void setCursorName(String name)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setCursorName(name);
|
||||
}
|
||||
|
||||
public boolean execute(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.execute(sql);
|
||||
}
|
||||
|
||||
public ResultSet getResultSet()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getResultSet();
|
||||
}
|
||||
|
||||
public int getUpdateCount()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getUpdateCount();
|
||||
}
|
||||
|
||||
public boolean getMoreResults()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMoreResults();
|
||||
}
|
||||
|
||||
public void setFetchDirection(int direction)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setFetchDirection(direction);
|
||||
}
|
||||
|
||||
public int getFetchDirection()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getFetchDirection();
|
||||
}
|
||||
|
||||
public void setFetchSize(int rows)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setFetchSize(rows);
|
||||
}
|
||||
|
||||
public int getFetchSize()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getFetchSize();
|
||||
}
|
||||
|
||||
public int getResultSetConcurrency()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getResultSetConcurrency();
|
||||
}
|
||||
|
||||
public int getResultSetType()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getResultSetType();
|
||||
}
|
||||
|
||||
public void addBatch(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.addBatch(sql);
|
||||
}
|
||||
|
||||
public void clearBatch()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.clearBatch();
|
||||
}
|
||||
|
||||
public int[] executeBatch()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeBatch();
|
||||
}
|
||||
|
||||
public Connection getConnection()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getConnection();
|
||||
}
|
||||
|
||||
public boolean getMoreResults(int current)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMoreResults(current);
|
||||
}
|
||||
|
||||
public ResultSet getGeneratedKeys()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getGeneratedKeys();
|
||||
}
|
||||
|
||||
public int executeUpdate(String sql, int autoGeneratedKeys)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeUpdate(sql, autoGeneratedKeys);
|
||||
}
|
||||
|
||||
public int executeUpdate(String sql, int[] columnIndexes)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeUpdate(sql, columnIndexes);
|
||||
}
|
||||
|
||||
public int executeUpdate(String sql, String[] columnNames)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeUpdate(sql, columnNames);
|
||||
}
|
||||
|
||||
public boolean execute(String sql, int autoGeneratedKeys)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.execute(sql, autoGeneratedKeys);
|
||||
}
|
||||
|
||||
public boolean execute(String sql, int[] columnIndexes)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.execute(sql, columnIndexes);
|
||||
}
|
||||
|
||||
public boolean execute(String sql, String[] columnNames)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.execute(sql, columnNames);
|
||||
}
|
||||
|
||||
public int getResultSetHoldability()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getResultSetHoldability();
|
||||
}
|
||||
}
|
||||
@@ -1,340 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.jdbc;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.NClob;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLClientInfoException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Savepoint;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Struct;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
public class ConnectionDelegator implements Connection
|
||||
{
|
||||
private final Connection delegate;
|
||||
|
||||
public ConnectionDelegator(Connection delegate)
|
||||
{
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public Statement createStatement()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement();
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql);
|
||||
}
|
||||
|
||||
public String nativeSQL(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.nativeSQL(sql);
|
||||
}
|
||||
|
||||
public void setAutoCommit(boolean autoCommit)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setAutoCommit(autoCommit);
|
||||
}
|
||||
|
||||
public boolean getAutoCommit()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getAutoCommit();
|
||||
}
|
||||
|
||||
public void commit()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.commit();
|
||||
}
|
||||
|
||||
public void rollback()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.rollback();
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
public boolean isClosed()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isClosed();
|
||||
}
|
||||
|
||||
public DatabaseMetaData getMetaData()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMetaData();
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setReadOnly(readOnly);
|
||||
}
|
||||
|
||||
public boolean isReadOnly()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isReadOnly();
|
||||
}
|
||||
|
||||
public void setCatalog(String catalog)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setCatalog(catalog);
|
||||
}
|
||||
|
||||
public String getCatalog()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getCatalog();
|
||||
}
|
||||
|
||||
public void setTransactionIsolation(int level)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTransactionIsolation(level);
|
||||
}
|
||||
|
||||
public int getTransactionIsolation()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getTransactionIsolation();
|
||||
}
|
||||
|
||||
public SQLWarning getWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getWarnings();
|
||||
}
|
||||
|
||||
public void clearWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.clearWarnings();
|
||||
}
|
||||
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement(resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql, resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public Map<String, Class<?>> getTypeMap()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getTypeMap();
|
||||
}
|
||||
|
||||
public void setTypeMap(Map<String, Class<?>> map)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTypeMap(map);
|
||||
}
|
||||
|
||||
public void setHoldability(int holdability)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setHoldability(holdability);
|
||||
}
|
||||
|
||||
public int getHoldability()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getHoldability();
|
||||
}
|
||||
|
||||
public Savepoint setSavepoint()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.setSavepoint();
|
||||
}
|
||||
|
||||
public Savepoint setSavepoint(String name)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.setSavepoint(name);
|
||||
}
|
||||
|
||||
public void rollback(Savepoint savepoint)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.rollback(savepoint);
|
||||
}
|
||||
|
||||
public void releaseSavepoint(Savepoint savepoint)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.releaseSavepoint(savepoint);
|
||||
}
|
||||
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, autoGeneratedKeys);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, columnIndexes);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, String[] columnNames)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, columnNames);
|
||||
}
|
||||
|
||||
public Clob createClob()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createClob();
|
||||
}
|
||||
|
||||
public Blob createBlob()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createBlob();
|
||||
}
|
||||
|
||||
public NClob createNClob()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createNClob();
|
||||
}
|
||||
|
||||
public SQLXML createSQLXML()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createSQLXML();
|
||||
}
|
||||
|
||||
public boolean isValid(int timeout)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isValid(timeout);
|
||||
}
|
||||
|
||||
public void setClientInfo(String name, String value)
|
||||
throws SQLClientInfoException
|
||||
{
|
||||
delegate.setClientInfo(name, value);
|
||||
}
|
||||
|
||||
public void setClientInfo(Properties properties)
|
||||
throws SQLClientInfoException
|
||||
{
|
||||
delegate.setClientInfo(properties);
|
||||
}
|
||||
|
||||
public String getClientInfo(String name)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getClientInfo(name);
|
||||
}
|
||||
|
||||
public Properties getClientInfo()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getClientInfo();
|
||||
}
|
||||
|
||||
public Array createArrayOf(String typeName, Object[] elements)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createArrayOf(typeName, elements);
|
||||
}
|
||||
|
||||
public Struct createStruct(String typeName, Object[] attributes)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStruct(typeName, attributes);
|
||||
}
|
||||
|
||||
public <T> T unwrap(Class<T> iface)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.unwrap(iface);
|
||||
}
|
||||
|
||||
public boolean isWrapperFor(Class<?> iface)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isWrapperFor(iface);
|
||||
}
|
||||
}
|
||||
@@ -1,634 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.jdbc;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Date;
|
||||
import java.sql.NClob;
|
||||
import java.sql.ParameterMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Ref;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.RowId;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class PreparedStatementDelegator implements PreparedStatement
|
||||
{
|
||||
private final PreparedStatement delegate;
|
||||
|
||||
public PreparedStatementDelegator(PreparedStatement delegate)
|
||||
{
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public ResultSet executeQuery()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeQuery();
|
||||
}
|
||||
|
||||
public int executeUpdate()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeUpdate();
|
||||
}
|
||||
|
||||
public void setNull(int parameterIndex, int sqlType)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setNull(parameterIndex, sqlType);
|
||||
}
|
||||
|
||||
public void setBoolean(int parameterIndex, boolean x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBoolean(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setByte(int parameterIndex, byte x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setByte(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setShort(int parameterIndex, short x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setShort(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setInt(int parameterIndex, int x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setInt(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setLong(int parameterIndex, long x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setLong(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setFloat(int parameterIndex, float x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setFloat(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setDouble(int parameterIndex, double x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setDouble(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setBigDecimal(int parameterIndex, BigDecimal x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBigDecimal(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setString(int parameterIndex, String x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setString(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setBytes(int parameterIndex, byte[] x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBytes(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setDate(int parameterIndex, Date x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setDate(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setTime(int parameterIndex, Time x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTime(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setTimestamp(int parameterIndex, Timestamp x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTimestamp(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setAsciiStream(int parameterIndex, InputStream x, int length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setAsciiStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void setUnicodeStream(int parameterIndex, InputStream x, int length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setUnicodeStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
public void setBinaryStream(int parameterIndex, InputStream x, int length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBinaryStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
public void clearParameters()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.clearParameters();
|
||||
}
|
||||
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setObject(parameterIndex, x, targetSqlType);
|
||||
}
|
||||
|
||||
public void setObject(int parameterIndex, Object x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setObject(parameterIndex, x);
|
||||
}
|
||||
|
||||
public boolean execute()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.execute();
|
||||
}
|
||||
|
||||
public void addBatch()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.addBatch();
|
||||
}
|
||||
|
||||
public void setCharacterStream(int parameterIndex, Reader reader, int length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setCharacterStream(parameterIndex, reader, length);
|
||||
}
|
||||
|
||||
public void setRef(int parameterIndex, Ref x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setRef(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setBlob(int parameterIndex, Blob x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBlob(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setClob(int parameterIndex, Clob x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setClob(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setArray(int parameterIndex, Array x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setArray(parameterIndex, x);
|
||||
}
|
||||
|
||||
public ResultSetMetaData getMetaData()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMetaData();
|
||||
}
|
||||
|
||||
public void setDate(int parameterIndex, Date x, Calendar cal)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setDate(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
public void setTime(int parameterIndex, Time x, Calendar cal)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTime(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTimestamp(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
public void setNull(int parameterIndex, int sqlType, String typeName)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setNull(parameterIndex, sqlType, typeName);
|
||||
}
|
||||
|
||||
public void setURL(int parameterIndex, URL x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setURL(parameterIndex, x);
|
||||
}
|
||||
|
||||
public ParameterMetaData getParameterMetaData()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getParameterMetaData();
|
||||
}
|
||||
|
||||
public void setRowId(int parameterIndex, RowId x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setRowId(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setNString(int parameterIndex, String value)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setNString(parameterIndex, value);
|
||||
}
|
||||
|
||||
public void setNCharacterStream(int parameterIndex, Reader value, long length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setNCharacterStream(parameterIndex, value, length);
|
||||
}
|
||||
|
||||
public void setNClob(int parameterIndex, NClob value)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setNClob(parameterIndex, value);
|
||||
}
|
||||
|
||||
public void setClob(int parameterIndex, Reader reader, long length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setClob(parameterIndex, reader, length);
|
||||
}
|
||||
|
||||
public void setBlob(int parameterIndex, InputStream inputStream, long length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBlob(parameterIndex, inputStream, length);
|
||||
}
|
||||
|
||||
public void setNClob(int parameterIndex, Reader reader, long length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setNClob(parameterIndex, reader, length);
|
||||
}
|
||||
|
||||
public void setSQLXML(int parameterIndex, SQLXML xmlObject)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setSQLXML(parameterIndex, xmlObject);
|
||||
}
|
||||
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setObject(parameterIndex, x, targetSqlType, scaleOrLength);
|
||||
}
|
||||
|
||||
public void setAsciiStream(int parameterIndex, InputStream x, long length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setAsciiStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
public void setBinaryStream(int parameterIndex, InputStream x, long length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBinaryStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
public void setCharacterStream(int parameterIndex, Reader reader, long length)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setCharacterStream(parameterIndex, reader, length);
|
||||
}
|
||||
|
||||
public void setAsciiStream(int parameterIndex, InputStream x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setAsciiStream(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setBinaryStream(int parameterIndex, InputStream x)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBinaryStream(parameterIndex, x);
|
||||
}
|
||||
|
||||
public void setCharacterStream(int parameterIndex, Reader reader)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setCharacterStream(parameterIndex, reader);
|
||||
}
|
||||
|
||||
public void setNCharacterStream(int parameterIndex, Reader value)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setNCharacterStream(parameterIndex, value);
|
||||
}
|
||||
|
||||
public void setClob(int parameterIndex, Reader reader)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setClob(parameterIndex, reader);
|
||||
}
|
||||
|
||||
public void setBlob(int parameterIndex, InputStream inputStream)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setBlob(parameterIndex, inputStream);
|
||||
}
|
||||
|
||||
public void setNClob(int parameterIndex, Reader reader)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setNClob(parameterIndex, reader);
|
||||
}
|
||||
|
||||
public ResultSet executeQuery(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeQuery(sql);
|
||||
}
|
||||
|
||||
public int executeUpdate(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeUpdate(sql);
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
public int getMaxFieldSize()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMaxFieldSize();
|
||||
}
|
||||
|
||||
public void setMaxFieldSize(int max)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setMaxFieldSize(max);
|
||||
}
|
||||
|
||||
public int getMaxRows()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMaxRows();
|
||||
}
|
||||
|
||||
public void setMaxRows(int max)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setMaxRows(max);
|
||||
}
|
||||
|
||||
public void setEscapeProcessing(boolean enable)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setEscapeProcessing(enable);
|
||||
}
|
||||
|
||||
public int getQueryTimeout()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getQueryTimeout();
|
||||
}
|
||||
|
||||
public void setQueryTimeout(int seconds)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setQueryTimeout(seconds);
|
||||
}
|
||||
|
||||
public void cancel()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.cancel();
|
||||
}
|
||||
|
||||
public SQLWarning getWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getWarnings();
|
||||
}
|
||||
|
||||
public void clearWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.clearWarnings();
|
||||
}
|
||||
|
||||
public void setCursorName(String name)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setCursorName(name);
|
||||
}
|
||||
|
||||
public boolean execute(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.execute(sql);
|
||||
}
|
||||
|
||||
public ResultSet getResultSet()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getResultSet();
|
||||
}
|
||||
|
||||
public int getUpdateCount()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getUpdateCount();
|
||||
}
|
||||
|
||||
public boolean getMoreResults()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMoreResults();
|
||||
}
|
||||
|
||||
public void setFetchDirection(int direction)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setFetchDirection(direction);
|
||||
}
|
||||
|
||||
public int getFetchDirection()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getFetchDirection();
|
||||
}
|
||||
|
||||
public void setFetchSize(int rows)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setFetchSize(rows);
|
||||
}
|
||||
|
||||
public int getFetchSize()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getFetchSize();
|
||||
}
|
||||
|
||||
public int getResultSetConcurrency()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getResultSetConcurrency();
|
||||
}
|
||||
|
||||
public int getResultSetType()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getResultSetType();
|
||||
}
|
||||
|
||||
public void addBatch(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.addBatch(sql);
|
||||
}
|
||||
|
||||
public void clearBatch()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.clearBatch();
|
||||
}
|
||||
|
||||
public int[] executeBatch()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeBatch();
|
||||
}
|
||||
|
||||
public Connection getConnection()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getConnection();
|
||||
}
|
||||
|
||||
public boolean getMoreResults(int current)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMoreResults(current);
|
||||
}
|
||||
|
||||
public ResultSet getGeneratedKeys()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getGeneratedKeys();
|
||||
}
|
||||
|
||||
public int executeUpdate(String sql, int autoGeneratedKeys)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeUpdate(sql, autoGeneratedKeys);
|
||||
}
|
||||
|
||||
public int executeUpdate(String sql, int[] columnIndexes)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeUpdate(sql, columnIndexes);
|
||||
}
|
||||
|
||||
public int executeUpdate(String sql, String[] columnNames)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.executeUpdate(sql, columnNames);
|
||||
}
|
||||
|
||||
public boolean execute(String sql, int autoGeneratedKeys)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.execute(sql, autoGeneratedKeys);
|
||||
}
|
||||
|
||||
public boolean execute(String sql, int[] columnIndexes)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.execute(sql, columnIndexes);
|
||||
}
|
||||
|
||||
public boolean execute(String sql, String[] columnNames)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.execute(sql, columnNames);
|
||||
}
|
||||
|
||||
public int getResultSetHoldability()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getResultSetHoldability();
|
||||
}
|
||||
|
||||
public boolean isClosed()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isClosed();
|
||||
}
|
||||
|
||||
public void setPoolable(boolean poolable)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setPoolable(poolable);
|
||||
}
|
||||
|
||||
public boolean isPoolable()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isPoolable();
|
||||
}
|
||||
|
||||
public <T> T unwrap(Class<T> iface)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.unwrap(iface);
|
||||
}
|
||||
|
||||
public boolean isWrapperFor(Class<?> iface)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isWrapperFor(iface);
|
||||
}
|
||||
}
|
||||
@@ -1,114 +1,95 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
/**
|
||||
* Wrapper of the list of Id's adding support for background fetching
|
||||
* future object.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class BeanIdList {
|
||||
|
||||
private final List<Object> idList;
|
||||
|
||||
private boolean hasMore = true;
|
||||
|
||||
private FutureTask<Integer> fetchFuture;
|
||||
|
||||
public BeanIdList(List<Object> idList) {
|
||||
this.idList = idList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch is continuing in a background thread.
|
||||
*/
|
||||
public boolean isFetchingInBackground() {
|
||||
return fetchFuture != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the FutureTask that is continuing the fetch in a background thread.
|
||||
*/
|
||||
public void setBackgroundFetch(FutureTask<Integer> fetchFuture) {
|
||||
this.fetchFuture = fetchFuture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the background fetching to complete with a timeout.
|
||||
*/
|
||||
public void backgroundFetchWait(long wait, TimeUnit timeUnit) {
|
||||
if (fetchFuture != null){
|
||||
try {
|
||||
fetchFuture.get(wait, timeUnit);
|
||||
} catch (Exception e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the background fetching to complete.
|
||||
*/
|
||||
public void backgroundFetchWait() {
|
||||
if (fetchFuture != null){
|
||||
try {
|
||||
fetchFuture.get();
|
||||
} catch (Exception e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an Id to the list.
|
||||
*/
|
||||
public void add(Object id){
|
||||
idList.add(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of Id's.
|
||||
*/
|
||||
public List<Object> getIdList() {
|
||||
return idList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if max rows was hit and there is more rows to fetch.
|
||||
*/
|
||||
public boolean isHasMore() {
|
||||
return hasMore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true when max rows is hit and there are more rows to fetch.
|
||||
*/
|
||||
public void setHasMore(boolean hasMore) {
|
||||
this.hasMore = hasMore;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
/**
|
||||
* Wrapper of the list of Id's adding support for background fetching
|
||||
* future object.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class BeanIdList {
|
||||
|
||||
private final List<Object> idList;
|
||||
|
||||
private boolean hasMore = true;
|
||||
|
||||
private FutureTask<Integer> fetchFuture;
|
||||
|
||||
public BeanIdList(List<Object> idList) {
|
||||
this.idList = idList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch is continuing in a background thread.
|
||||
*/
|
||||
public boolean isFetchingInBackground() {
|
||||
return fetchFuture != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the FutureTask that is continuing the fetch in a background thread.
|
||||
*/
|
||||
public void setBackgroundFetch(FutureTask<Integer> fetchFuture) {
|
||||
this.fetchFuture = fetchFuture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the background fetching to complete with a timeout.
|
||||
*/
|
||||
public void backgroundFetchWait(long wait, TimeUnit timeUnit) {
|
||||
if (fetchFuture != null){
|
||||
try {
|
||||
fetchFuture.get(wait, timeUnit);
|
||||
} catch (Exception e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the background fetching to complete.
|
||||
*/
|
||||
public void backgroundFetchWait() {
|
||||
if (fetchFuture != null){
|
||||
try {
|
||||
fetchFuture.get();
|
||||
} catch (Exception e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an Id to the list.
|
||||
*/
|
||||
public void add(Object id){
|
||||
idList.add(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of Id's.
|
||||
*/
|
||||
public List<Object> getIdList() {
|
||||
return idList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if max rows was hit and there is more rows to fetch.
|
||||
*/
|
||||
public boolean isHasMore() {
|
||||
return hasMore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true when max rows is hit and there are more rows to fetch.
|
||||
*/
|
||||
public void setHasMore(boolean hasMore) {
|
||||
this.hasMore = hasMore;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,22 +1,3 @@
|
||||
/**
|
||||
* Copyright (C) 2010 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
@@ -1,111 +1,92 @@
|
||||
/**
|
||||
* Copyright (C) 2010 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* Helper to find classes taking into account the context class loader.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class ClassUtil {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClassUtil.class.getName());
|
||||
|
||||
private static boolean preferContext = true;
|
||||
|
||||
/**
|
||||
* Load a class taking into account a context class loader (if present).
|
||||
*/
|
||||
public static Class<?> forName(String name) throws ClassNotFoundException {
|
||||
return forName(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a class taking into account a context class loader (if present).
|
||||
*/
|
||||
public static Class<?> forName(String name, Class<?> caller) throws ClassNotFoundException {
|
||||
|
||||
if (caller == null){
|
||||
caller = ClassUtil.class;
|
||||
}
|
||||
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
|
||||
|
||||
return ctx.forName(name);
|
||||
}
|
||||
|
||||
|
||||
public static ClassLoader getClassLoader(Class<?> caller, boolean preferContext) {
|
||||
|
||||
if (caller == null){
|
||||
caller = ClassUtil.class;
|
||||
}
|
||||
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
|
||||
ClassLoader classLoader = ctx.getDefault(preferContext);
|
||||
if (ctx.isAmbiguous()){
|
||||
logger.info("Ambigous ClassLoader (Context vs Caller) chosen "+classLoader);
|
||||
}
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
public static boolean isPresent(String className) {
|
||||
return isPresent(className, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
public static boolean isPresent(String className, Class<?> caller) {
|
||||
try {
|
||||
forName(className, caller);
|
||||
return true;
|
||||
} catch (Throwable ex) {
|
||||
// Class or one of its dependencies is not present...
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance of the class using the default constructor.
|
||||
*/
|
||||
public static Object newInstance(String className) {
|
||||
return newInstance(className,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance of the class using the default constructor.
|
||||
*/
|
||||
public static Object newInstance(String className, Class<?> caller) {
|
||||
|
||||
try {
|
||||
Class<?> cls = forName(className, caller);
|
||||
return cls.newInstance();
|
||||
} catch (Exception e){
|
||||
String msg = "Error constructing "+className;
|
||||
throw new IllegalArgumentException(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* Helper to find classes taking into account the context class loader.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class ClassUtil {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClassUtil.class.getName());
|
||||
|
||||
private static boolean preferContext = true;
|
||||
|
||||
/**
|
||||
* Load a class taking into account a context class loader (if present).
|
||||
*/
|
||||
public static Class<?> forName(String name) throws ClassNotFoundException {
|
||||
return forName(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a class taking into account a context class loader (if present).
|
||||
*/
|
||||
public static Class<?> forName(String name, Class<?> caller) throws ClassNotFoundException {
|
||||
|
||||
if (caller == null){
|
||||
caller = ClassUtil.class;
|
||||
}
|
||||
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
|
||||
|
||||
return ctx.forName(name);
|
||||
}
|
||||
|
||||
|
||||
public static ClassLoader getClassLoader(Class<?> caller, boolean preferContext) {
|
||||
|
||||
if (caller == null){
|
||||
caller = ClassUtil.class;
|
||||
}
|
||||
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
|
||||
ClassLoader classLoader = ctx.getDefault(preferContext);
|
||||
if (ctx.isAmbiguous()){
|
||||
logger.info("Ambigous ClassLoader (Context vs Caller) chosen "+classLoader);
|
||||
}
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
public static boolean isPresent(String className) {
|
||||
return isPresent(className, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
public static boolean isPresent(String className, Class<?> caller) {
|
||||
try {
|
||||
forName(className, caller);
|
||||
return true;
|
||||
} catch (Throwable ex) {
|
||||
// Class or one of its dependencies is not present...
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance of the class using the default constructor.
|
||||
*/
|
||||
public static Object newInstance(String className) {
|
||||
return newInstance(className,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance of the class using the default constructor.
|
||||
*/
|
||||
public static Object newInstance(String className, Class<?> caller) {
|
||||
|
||||
try {
|
||||
Class<?> cls = forName(className, caller);
|
||||
return cls.newInstance();
|
||||
} catch (Exception e){
|
||||
String msg = "Error constructing "+className;
|
||||
throw new IllegalArgumentException(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,55 +1,36 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.TxScope;
|
||||
|
||||
/**
|
||||
* Helper object to make AOP generated code simpler.
|
||||
*/
|
||||
public class HelpScopeTrans {
|
||||
|
||||
/**
|
||||
* Create a ScopeTrans for a given methods TxScope.
|
||||
*/
|
||||
public static ScopeTrans createScopeTrans(TxScope txScope) {
|
||||
|
||||
EbeanServer server = Ebean.getServer(txScope.getServerName());
|
||||
SpiEbeanServer iserver = (SpiEbeanServer)server;
|
||||
return iserver.createScopeTrans(txScope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exiting the method in an expected fashion.
|
||||
* <p>
|
||||
* That is returning successfully or via a caught exception.
|
||||
* Unexpected exceptions are caught via the Thread uncaughtExceptionHandler.
|
||||
* </p>
|
||||
* @param returnOrThrowable the return or throwable object
|
||||
* @param opCode the opcode for ATHROW or ARETURN etc
|
||||
* @param scopeTrans the scoped transaction the method was run with.
|
||||
*/
|
||||
public static void onExitScopeTrans(Object returnOrThrowable, int opCode, ScopeTrans scopeTrans){
|
||||
|
||||
scopeTrans.onExit(returnOrThrowable, opCode);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.TxScope;
|
||||
|
||||
/**
|
||||
* Helper object to make AOP generated code simpler.
|
||||
*/
|
||||
public class HelpScopeTrans {
|
||||
|
||||
/**
|
||||
* Create a ScopeTrans for a given methods TxScope.
|
||||
*/
|
||||
public static ScopeTrans createScopeTrans(TxScope txScope) {
|
||||
|
||||
EbeanServer server = Ebean.getServer(txScope.getServerName());
|
||||
SpiEbeanServer iserver = (SpiEbeanServer)server;
|
||||
return iserver.createScopeTrans(txScope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exiting the method in an expected fashion.
|
||||
* <p>
|
||||
* That is returning successfully or via a caught exception.
|
||||
* Unexpected exceptions are caught via the Thread uncaughtExceptionHandler.
|
||||
* </p>
|
||||
* @param returnOrThrowable the return or throwable object
|
||||
* @param opCode the opcode for ATHROW or ARETURN etc
|
||||
* @param scopeTrans the scoped transaction the method was run with.
|
||||
*/
|
||||
public static void onExitScopeTrans(Object returnOrThrowable, int opCode, ScopeTrans scopeTrans){
|
||||
|
||||
scopeTrans.onExit(returnOrThrowable, opCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +1,39 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
/**
|
||||
* Controls the loading of ManyToOne and OneToOne relationships.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface LoadBeanContext extends LoadSecondaryQuery {
|
||||
|
||||
/**
|
||||
* Configure the query to load beans for this node/path.
|
||||
*/
|
||||
public void configureQuery(SpiQuery<?> query, String lazyLoadProperty);
|
||||
|
||||
/**
|
||||
* Return the full path of this node from the root object.
|
||||
*/
|
||||
public String getFullPath();
|
||||
|
||||
/**
|
||||
* Return the persistence context used for all queries
|
||||
* related to this object graph.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for beans for this node.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
/**
|
||||
* Return the batchSize used for lazy loading beans.
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
/**
|
||||
* Controls the loading of ManyToOne and OneToOne relationships.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface LoadBeanContext extends LoadSecondaryQuery {
|
||||
|
||||
/**
|
||||
* Configure the query to load beans for this node/path.
|
||||
*/
|
||||
public void configureQuery(SpiQuery<?> query, String lazyLoadProperty);
|
||||
|
||||
/**
|
||||
* Return the full path of this node from the root object.
|
||||
*/
|
||||
public String getFullPath();
|
||||
|
||||
/**
|
||||
* Return the persistence context used for all queries
|
||||
* related to this object graph.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for beans for this node.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
/**
|
||||
* Return the batchSize used for lazy loading beans.
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,82 +1,63 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
|
||||
/**
|
||||
* Request for loading ManyToOne and OneToOne relationships.
|
||||
*/
|
||||
public class LoadBeanRequest extends LoadRequest {
|
||||
|
||||
private final List<EntityBeanIntercept> batch;
|
||||
|
||||
private final LoadBeanContext loadContext;
|
||||
|
||||
private final String lazyLoadProperty;
|
||||
|
||||
private final boolean loadCache;
|
||||
|
||||
public LoadBeanRequest(LoadBeanContext loadContext, List<EntityBeanIntercept> batch,
|
||||
Transaction transaction, int batchSize, boolean lazy, String lazyLoadProperty, boolean loadCache) {
|
||||
|
||||
super(transaction, batchSize, lazy);
|
||||
this.loadContext = loadContext;
|
||||
this.batch = batch;
|
||||
this.lazyLoadProperty = lazyLoadProperty;
|
||||
this.loadCache = loadCache;
|
||||
}
|
||||
|
||||
public boolean isLoadCache() {
|
||||
return loadCache;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
String fullPath = loadContext.getFullPath();
|
||||
String s = "path:" + fullPath + " batch:" + batchSize + " actual:"
|
||||
+ batch.size();
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch of beans to actually load.
|
||||
*/
|
||||
public List<EntityBeanIntercept> getBatch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the load context.
|
||||
*/
|
||||
public LoadBeanContext getLoadContext() {
|
||||
return loadContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property that invoked the lazy loading.
|
||||
*/
|
||||
public String getLazyLoadProperty() {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
|
||||
/**
|
||||
* Request for loading ManyToOne and OneToOne relationships.
|
||||
*/
|
||||
public class LoadBeanRequest extends LoadRequest {
|
||||
|
||||
private final List<EntityBeanIntercept> batch;
|
||||
|
||||
private final LoadBeanContext loadContext;
|
||||
|
||||
private final String lazyLoadProperty;
|
||||
|
||||
private final boolean loadCache;
|
||||
|
||||
public LoadBeanRequest(LoadBeanContext loadContext, List<EntityBeanIntercept> batch,
|
||||
Transaction transaction, int batchSize, boolean lazy, String lazyLoadProperty, boolean loadCache) {
|
||||
|
||||
super(transaction, batchSize, lazy);
|
||||
this.loadContext = loadContext;
|
||||
this.batch = batch;
|
||||
this.lazyLoadProperty = lazyLoadProperty;
|
||||
this.loadCache = loadCache;
|
||||
}
|
||||
|
||||
public boolean isLoadCache() {
|
||||
return loadCache;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
String fullPath = loadContext.getFullPath();
|
||||
String s = "path:" + fullPath + " batch:" + batchSize + " actual:"
|
||||
+ batch.size();
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch of beans to actually load.
|
||||
*/
|
||||
public List<EntityBeanIntercept> getBatch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the load context.
|
||||
*/
|
||||
public LoadBeanContext getLoadContext() {
|
||||
return loadContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property that invoked the lazy loading.
|
||||
*/
|
||||
public String getLazyLoadProperty() {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,79 +1,60 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
|
||||
/**
|
||||
* Controls the loading of reference objects for a query instance.
|
||||
*/
|
||||
public interface LoadContext {
|
||||
|
||||
/**
|
||||
* Return the minimum batch size when using QueryIterator with query joins.
|
||||
*/
|
||||
public int getSecondaryQueriesMinBatchSize(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
|
||||
|
||||
/**
|
||||
* Execute any secondary (+query) queries if there are any defined.
|
||||
* @param parentRequest the originating query request
|
||||
*/
|
||||
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
|
||||
|
||||
/**
|
||||
* Register any secondary queries (+query or +lazy) with their
|
||||
* appropriate LoadBeanContext or LoadManyContext.
|
||||
* <p>
|
||||
* This is so the LoadBeanContext or LoadManyContext use the
|
||||
* defined query for +query and +lazy execution.
|
||||
* </p>
|
||||
*/
|
||||
public void registerSecondaryQueries(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* Return the node for a given path which is used by autofetch profiling.
|
||||
*/
|
||||
public ObjectGraphNode getObjectGraphNode(String path);
|
||||
|
||||
/**
|
||||
* Return the persistence context used by this query and future lazy loading.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Set the persistence context used by this query and future lazy loading.
|
||||
*/
|
||||
public void setPersistenceContext(PersistenceContext persistenceContext);
|
||||
|
||||
/**
|
||||
* Register a Bean for lazy loading.
|
||||
*/
|
||||
public void register(String path, EntityBeanIntercept ebi);
|
||||
|
||||
/**
|
||||
* Register a collection for lazy loading.
|
||||
*/
|
||||
public void register(String path, BeanCollection<?> bc);
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
|
||||
/**
|
||||
* Controls the loading of reference objects for a query instance.
|
||||
*/
|
||||
public interface LoadContext {
|
||||
|
||||
/**
|
||||
* Return the minimum batch size when using QueryIterator with query joins.
|
||||
*/
|
||||
public int getSecondaryQueriesMinBatchSize(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
|
||||
|
||||
/**
|
||||
* Execute any secondary (+query) queries if there are any defined.
|
||||
* @param parentRequest the originating query request
|
||||
*/
|
||||
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
|
||||
|
||||
/**
|
||||
* Register any secondary queries (+query or +lazy) with their
|
||||
* appropriate LoadBeanContext or LoadManyContext.
|
||||
* <p>
|
||||
* This is so the LoadBeanContext or LoadManyContext use the
|
||||
* defined query for +query and +lazy execution.
|
||||
* </p>
|
||||
*/
|
||||
public void registerSecondaryQueries(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* Return the node for a given path which is used by autofetch profiling.
|
||||
*/
|
||||
public ObjectGraphNode getObjectGraphNode(String path);
|
||||
|
||||
/**
|
||||
* Return the persistence context used by this query and future lazy loading.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Set the persistence context used by this query and future lazy loading.
|
||||
*/
|
||||
public void setPersistenceContext(PersistenceContext persistenceContext);
|
||||
|
||||
/**
|
||||
* Register a Bean for lazy loading.
|
||||
*/
|
||||
public void register(String path, EntityBeanIntercept ebi);
|
||||
|
||||
/**
|
||||
* Register a collection for lazy loading.
|
||||
*/
|
||||
public void register(String path, BeanCollection<?> bc);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,73 +1,54 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
|
||||
/**
|
||||
* Controls the loading of OneToMany and ManyToMany relationships.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface LoadManyContext extends LoadSecondaryQuery {
|
||||
|
||||
/**
|
||||
* Configure the query to load beans for this node/path.
|
||||
*/
|
||||
public void configureQuery(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* Return the full path of this node from the root object.
|
||||
*/
|
||||
public String getFullPath();
|
||||
|
||||
/**
|
||||
* Return the node location for this node/path.
|
||||
*/
|
||||
public ObjectGraphNode getObjectGraphNode();
|
||||
|
||||
|
||||
/**
|
||||
* Return the persistence context used for all queries
|
||||
* related to this object graph.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Return the batchSize used for lazy loading beans.
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for beans for this node.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
/**
|
||||
* Return the associated Many bean property.
|
||||
*/
|
||||
public BeanPropertyAssocMany<?> getBeanProperty();
|
||||
|
||||
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
|
||||
/**
|
||||
* Controls the loading of OneToMany and ManyToMany relationships.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface LoadManyContext extends LoadSecondaryQuery {
|
||||
|
||||
/**
|
||||
* Configure the query to load beans for this node/path.
|
||||
*/
|
||||
public void configureQuery(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* Return the full path of this node from the root object.
|
||||
*/
|
||||
public String getFullPath();
|
||||
|
||||
/**
|
||||
* Return the node location for this node/path.
|
||||
*/
|
||||
public ObjectGraphNode getObjectGraphNode();
|
||||
|
||||
|
||||
/**
|
||||
* Return the persistence context used for all queries
|
||||
* related to this object graph.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Return the batchSize used for lazy loading beans.
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for beans for this node.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
/**
|
||||
* Return the associated Many bean property.
|
||||
*/
|
||||
public BeanPropertyAssocMany<?> getBeanProperty();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,93 +1,74 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Request for loading Associated One Beans.
|
||||
*/
|
||||
public class LoadManyRequest extends LoadRequest {
|
||||
|
||||
|
||||
private final List<BeanCollection<?>> batch;
|
||||
|
||||
private final LoadManyContext loadContext;
|
||||
|
||||
private final boolean onlyIds;
|
||||
|
||||
private final boolean loadCache;
|
||||
|
||||
public LoadManyRequest(LoadManyContext loadContext,
|
||||
List<BeanCollection<?>> batch, Transaction transaction,
|
||||
int batchSize, boolean lazy, boolean onlyIds, boolean loadCache) {
|
||||
|
||||
super(transaction, batchSize, lazy);
|
||||
this.loadContext = loadContext;
|
||||
this.batch = batch;
|
||||
this.onlyIds = onlyIds;
|
||||
this.loadCache = loadCache;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
String fullPath = loadContext.getFullPath();
|
||||
String s = "path:" + fullPath + " batch:" + batchSize + " actual:"
|
||||
+ batch.size();
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch of collections to actually load.
|
||||
*/
|
||||
public List<BeanCollection<?>> getBatch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the load context.
|
||||
*/
|
||||
public LoadManyContext getLoadContext() {
|
||||
return loadContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if lazy loading should only load the id values.
|
||||
* <p>
|
||||
* This for use when lazy loading is invoked on methods such
|
||||
* as clear() and removeAll() where it generally makes sense to
|
||||
* only fetch the Id values as the other property information is
|
||||
* not used.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isOnlyIds() {
|
||||
return onlyIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should load the Collection ids into the cache.
|
||||
*/
|
||||
public boolean isLoadCache() {
|
||||
return loadCache;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Request for loading Associated One Beans.
|
||||
*/
|
||||
public class LoadManyRequest extends LoadRequest {
|
||||
|
||||
|
||||
private final List<BeanCollection<?>> batch;
|
||||
|
||||
private final LoadManyContext loadContext;
|
||||
|
||||
private final boolean onlyIds;
|
||||
|
||||
private final boolean loadCache;
|
||||
|
||||
public LoadManyRequest(LoadManyContext loadContext,
|
||||
List<BeanCollection<?>> batch, Transaction transaction,
|
||||
int batchSize, boolean lazy, boolean onlyIds, boolean loadCache) {
|
||||
|
||||
super(transaction, batchSize, lazy);
|
||||
this.loadContext = loadContext;
|
||||
this.batch = batch;
|
||||
this.onlyIds = onlyIds;
|
||||
this.loadCache = loadCache;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
String fullPath = loadContext.getFullPath();
|
||||
String s = "path:" + fullPath + " batch:" + batchSize + " actual:"
|
||||
+ batch.size();
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch of collections to actually load.
|
||||
*/
|
||||
public List<BeanCollection<?>> getBatch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the load context.
|
||||
*/
|
||||
public LoadManyContext getLoadContext() {
|
||||
return loadContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if lazy loading should only load the id values.
|
||||
* <p>
|
||||
* This for use when lazy loading is invoked on methods such
|
||||
* as clear() and removeAll() where it generally makes sense to
|
||||
* only fetch the Id values as the other property information is
|
||||
* not used.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isOnlyIds() {
|
||||
return onlyIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should load the Collection ids into the cache.
|
||||
*/
|
||||
public boolean isLoadCache() {
|
||||
return loadCache;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,67 +1,48 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
|
||||
/**
|
||||
* Request for loading Associated One Beans.
|
||||
*/
|
||||
public abstract class LoadRequest {
|
||||
|
||||
protected final boolean lazy;
|
||||
|
||||
protected final int batchSize;
|
||||
|
||||
protected final Transaction transaction;
|
||||
|
||||
public LoadRequest(Transaction transaction, int batchSize, boolean lazy) {
|
||||
|
||||
this.transaction = transaction;
|
||||
this.batchSize = batchSize;
|
||||
this.lazy = lazy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if this is a lazy load and false if it is a secondary query.
|
||||
*/
|
||||
public boolean isLazy() {
|
||||
return lazy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the requested batch size.
|
||||
*/
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction to use if this is a secondary query.
|
||||
* <p>
|
||||
* Lazy loading queries run in their own transaction.
|
||||
* </p>
|
||||
*/
|
||||
public Transaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
|
||||
/**
|
||||
* Request for loading Associated One Beans.
|
||||
*/
|
||||
public abstract class LoadRequest {
|
||||
|
||||
protected final boolean lazy;
|
||||
|
||||
protected final int batchSize;
|
||||
|
||||
protected final Transaction transaction;
|
||||
|
||||
public LoadRequest(Transaction transaction, int batchSize, boolean lazy) {
|
||||
|
||||
this.transaction = transaction;
|
||||
this.batchSize = batchSize;
|
||||
this.lazy = lazy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if this is a lazy load and false if it is a secondary query.
|
||||
*/
|
||||
public boolean isLazy() {
|
||||
return lazy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the requested batch size.
|
||||
*/
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction to use if this is a secondary query.
|
||||
* <p>
|
||||
* Lazy loading queries run in their own transaction.
|
||||
* </p>
|
||||
*/
|
||||
public Transaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,40 +1,21 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
|
||||
/**
|
||||
* Defines the method for executing secondary queries.
|
||||
* <p>
|
||||
* That is +query nodes in a orm query get executed after
|
||||
* the initial query as 'secondary' queries.
|
||||
* </p>
|
||||
*/
|
||||
public interface LoadSecondaryQuery {
|
||||
|
||||
/**
|
||||
* Execute the secondary query with a given batch size.
|
||||
*
|
||||
* @param parentRequest
|
||||
* the originating query request
|
||||
*/
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, int requestedBatchSize, boolean all);
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
|
||||
/**
|
||||
* Defines the method for executing secondary queries.
|
||||
* <p>
|
||||
* That is +query nodes in a orm query get executed after
|
||||
* the initial query as 'secondary' queries.
|
||||
* </p>
|
||||
*/
|
||||
public interface LoadSecondaryQuery {
|
||||
|
||||
/**
|
||||
* Execute the secondary query with a given batch size.
|
||||
*
|
||||
* @param parentRequest
|
||||
* the originating query request
|
||||
*/
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, int requestedBatchSize, boolean all);
|
||||
}
|
||||
|
||||
@@ -1,95 +1,76 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
|
||||
/**
|
||||
* Holds the joins needs to support the many where predicates.
|
||||
* These joins are independent of any 'fetch' joins on the many.
|
||||
*/
|
||||
public class ManyWhereJoins implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6490181101871795417L;
|
||||
|
||||
private final TreeSet<String> joins = new TreeSet<String>();
|
||||
|
||||
/**
|
||||
* Add a many where join.
|
||||
*/
|
||||
public void add(ElPropertyDeploy elProp) {
|
||||
|
||||
String join = elProp.getElPrefix();
|
||||
BeanProperty p = elProp.getBeanProperty();
|
||||
if (p instanceof BeanPropertyAssocMany<?>){
|
||||
join = addManyToJoin(join, p.getName());
|
||||
}
|
||||
if (join != null){
|
||||
joins.add(join);
|
||||
String secondaryTableJoinPrefix = p.getSecondaryTableJoinPrefix();
|
||||
if (secondaryTableJoinPrefix != null) {
|
||||
joins.add(join+"."+secondaryTableJoinPrefix);
|
||||
}
|
||||
addParentJoins(join);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For 'many' properties we also need to add the name of the
|
||||
* many property to get the full logical name of the join.
|
||||
*/
|
||||
private String addManyToJoin(String join, String manyPropName){
|
||||
if (join == null){
|
||||
return manyPropName;
|
||||
} else {
|
||||
return join+"."+manyPropName;
|
||||
}
|
||||
}
|
||||
|
||||
private void addParentJoins(String join) {
|
||||
String[] split = SplitName.split(join);
|
||||
if (split[0] != null){
|
||||
joins.add(split[0]);
|
||||
addParentJoins(split[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no extra many where joins.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return joins.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of many where joins.
|
||||
*/
|
||||
public Set<String> getJoins() {
|
||||
return joins;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
|
||||
/**
|
||||
* Holds the joins needs to support the many where predicates.
|
||||
* These joins are independent of any 'fetch' joins on the many.
|
||||
*/
|
||||
public class ManyWhereJoins implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6490181101871795417L;
|
||||
|
||||
private final TreeSet<String> joins = new TreeSet<String>();
|
||||
|
||||
/**
|
||||
* Add a many where join.
|
||||
*/
|
||||
public void add(ElPropertyDeploy elProp) {
|
||||
|
||||
String join = elProp.getElPrefix();
|
||||
BeanProperty p = elProp.getBeanProperty();
|
||||
if (p instanceof BeanPropertyAssocMany<?>){
|
||||
join = addManyToJoin(join, p.getName());
|
||||
}
|
||||
if (join != null){
|
||||
joins.add(join);
|
||||
String secondaryTableJoinPrefix = p.getSecondaryTableJoinPrefix();
|
||||
if (secondaryTableJoinPrefix != null) {
|
||||
joins.add(join+"."+secondaryTableJoinPrefix);
|
||||
}
|
||||
addParentJoins(join);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For 'many' properties we also need to add the name of the
|
||||
* many property to get the full logical name of the join.
|
||||
*/
|
||||
private String addManyToJoin(String join, String manyPropName){
|
||||
if (join == null){
|
||||
return manyPropName;
|
||||
} else {
|
||||
return join+"."+manyPropName;
|
||||
}
|
||||
}
|
||||
|
||||
private void addParentJoins(String join) {
|
||||
String[] split = SplitName.split(join);
|
||||
if (split[0] != null){
|
||||
joins.add(split[0]);
|
||||
addParentJoins(split[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no extra many where joins.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return joins.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of many where joins.
|
||||
*/
|
||||
public Set<String> getJoins() {
|
||||
return joins;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,31 +1,12 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Object used as a synchronization monitor that is serializable.
|
||||
*/
|
||||
public class Monitor implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -2741687226680981940L;
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Object used as a synchronization monitor that is serializable.
|
||||
*/
|
||||
public class Monitor implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -2741687226680981940L;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,221 +1,202 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.avaje.ebean.TxScope;
|
||||
|
||||
/**
|
||||
* Used internally to handle the scoping of transactions for methods.
|
||||
*/
|
||||
public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
private static final int OPCODE_ATHROW = 191;
|
||||
//private static final int OPCODE_ATHROW = com.avaje.ebean.enhance.asm.Opcodes.ATHROW;
|
||||
|
||||
private final SpiTransactionScopeManager scopeMgr;
|
||||
|
||||
/**
|
||||
* The suspended transaction (can be null).
|
||||
*/
|
||||
private final SpiTransaction suspendedTransaction;
|
||||
/**
|
||||
* The transaction in scope (can be null).
|
||||
*/
|
||||
private final SpiTransaction transaction;
|
||||
|
||||
/**
|
||||
* If true by default rollback on Checked exceptions.
|
||||
*/
|
||||
private final boolean rollbackOnChecked;
|
||||
|
||||
/**
|
||||
* True if the transaction was created and hence should be committed
|
||||
* on finally if it hasn't already been rolled back.
|
||||
*/
|
||||
private final boolean created;
|
||||
|
||||
/**
|
||||
* Explicit set of Exceptions that DO NOT cause a rollback to occur.
|
||||
*/
|
||||
private final ArrayList<Class<? extends Throwable>> noRollbackFor;
|
||||
|
||||
/**
|
||||
* Explicit set of Exceptions that DO cause a rollback to occur.
|
||||
*/
|
||||
private final ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
|
||||
|
||||
private final UncaughtExceptionHandler originalUncaughtHandler;
|
||||
|
||||
/**
|
||||
* Flag set when a rollback has occurred.
|
||||
*/
|
||||
private boolean rolledBack;
|
||||
|
||||
|
||||
public ScopeTrans(boolean rollbackOnChecked, boolean created, SpiTransaction transaction, TxScope txScope,
|
||||
SpiTransaction suspendedTransaction, SpiTransactionScopeManager scopeMgr) {
|
||||
|
||||
this.rollbackOnChecked = rollbackOnChecked;
|
||||
this.created = created;
|
||||
this.transaction = transaction;
|
||||
this.suspendedTransaction = suspendedTransaction;
|
||||
this.scopeMgr = scopeMgr;
|
||||
|
||||
this.noRollbackFor = txScope.getNoRollbackFor();
|
||||
this.rollbackFor = txScope.getRollbackFor();
|
||||
|
||||
Thread t = Thread.currentThread();
|
||||
originalUncaughtHandler = t.getUncaughtExceptionHandler();
|
||||
|
||||
t.setUncaughtExceptionHandler(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the Thread catches any uncaught exception.
|
||||
* For example, an unexpected NullPointerException or Error.
|
||||
*/
|
||||
public void uncaughtException(Thread thread, Throwable e) {
|
||||
|
||||
// rollback transaction if required
|
||||
caughtThrowable(e);
|
||||
|
||||
// reinstate suspended transaction and
|
||||
// original uncaughtExceptionHandler if required
|
||||
onFinally();
|
||||
|
||||
if (originalUncaughtHandler != null){
|
||||
originalUncaughtHandler.uncaughtException(thread, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returned via RETURN or expected Exception from the method.
|
||||
* @param returnOrThrowable the return value or Throwable
|
||||
* @param opCode indicates
|
||||
*/
|
||||
public void onExit(Object returnOrThrowable, int opCode) {
|
||||
|
||||
if (opCode == OPCODE_ATHROW){
|
||||
// exited with a Throwable
|
||||
caughtThrowable((Throwable)returnOrThrowable);
|
||||
}
|
||||
onFinally();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Commit if the transaction exists and has not already been rolled back.
|
||||
* Also reinstate the suspended transaction if there was one.
|
||||
*/
|
||||
public void onFinally() {
|
||||
try {
|
||||
if (originalUncaughtHandler != null){
|
||||
Thread.currentThread().setUncaughtExceptionHandler(originalUncaughtHandler);
|
||||
}
|
||||
|
||||
if (!rolledBack && created) {
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (suspendedTransaction != null){
|
||||
// put the previously suspended transaction
|
||||
// back onto the ThreadLocal or equivalent
|
||||
scopeMgr.replace(suspendedTransaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An Error was caught and this ALWAYS causes a rollback to occur.
|
||||
* Returns the error and this should be thrown by the calling code.
|
||||
*/
|
||||
public Error caughtError(Error e) {
|
||||
rollback(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* An Exception was caught and may or may not cause a rollback to occur.
|
||||
* Returns the exception and this should be thrown by the calling code.
|
||||
*/
|
||||
public <T extends Throwable> T caughtThrowable(T e) {
|
||||
|
||||
if (isRollbackThrowable(e)) {
|
||||
rollback(e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
private void rollback(Throwable e) {
|
||||
if (transaction != null && transaction.isActive()) {
|
||||
// transaction is null for NOT_SUPPORTED and sometimes SUPPORTS
|
||||
// and Inactive (already rolled back) if nested REQUIRED
|
||||
transaction.rollback(e);
|
||||
}
|
||||
rolledBack = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this throwable should cause a rollback to occur.
|
||||
*/
|
||||
private boolean isRollbackThrowable(Throwable e) {
|
||||
|
||||
if (e instanceof Error){
|
||||
return true;
|
||||
}
|
||||
|
||||
if (noRollbackFor != null){
|
||||
for (int i = 0; i < noRollbackFor.size(); i++) {
|
||||
if (noRollbackFor.get(i).equals(e.getClass())) {
|
||||
|
||||
// explicit no rollback for this one
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rollbackFor != null){
|
||||
for (int i = 0; i < rollbackFor.size(); i++) {
|
||||
if (rollbackFor.get(i).equals(e.getClass())) {
|
||||
// explicit rollback for this one
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (e instanceof RuntimeException) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// checked exceptions...
|
||||
// EJB defaults this to false which is not intuitive IMO
|
||||
// Ebean makes this configurable (default to true)
|
||||
return rollbackOnChecked;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.avaje.ebean.TxScope;
|
||||
|
||||
/**
|
||||
* Used internally to handle the scoping of transactions for methods.
|
||||
*/
|
||||
public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
private static final int OPCODE_ATHROW = 191;
|
||||
//private static final int OPCODE_ATHROW = com.avaje.ebean.enhance.asm.Opcodes.ATHROW;
|
||||
|
||||
private final SpiTransactionScopeManager scopeMgr;
|
||||
|
||||
/**
|
||||
* The suspended transaction (can be null).
|
||||
*/
|
||||
private final SpiTransaction suspendedTransaction;
|
||||
/**
|
||||
* The transaction in scope (can be null).
|
||||
*/
|
||||
private final SpiTransaction transaction;
|
||||
|
||||
/**
|
||||
* If true by default rollback on Checked exceptions.
|
||||
*/
|
||||
private final boolean rollbackOnChecked;
|
||||
|
||||
/**
|
||||
* True if the transaction was created and hence should be committed
|
||||
* on finally if it hasn't already been rolled back.
|
||||
*/
|
||||
private final boolean created;
|
||||
|
||||
/**
|
||||
* Explicit set of Exceptions that DO NOT cause a rollback to occur.
|
||||
*/
|
||||
private final ArrayList<Class<? extends Throwable>> noRollbackFor;
|
||||
|
||||
/**
|
||||
* Explicit set of Exceptions that DO cause a rollback to occur.
|
||||
*/
|
||||
private final ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
|
||||
|
||||
private final UncaughtExceptionHandler originalUncaughtHandler;
|
||||
|
||||
/**
|
||||
* Flag set when a rollback has occurred.
|
||||
*/
|
||||
private boolean rolledBack;
|
||||
|
||||
|
||||
public ScopeTrans(boolean rollbackOnChecked, boolean created, SpiTransaction transaction, TxScope txScope,
|
||||
SpiTransaction suspendedTransaction, SpiTransactionScopeManager scopeMgr) {
|
||||
|
||||
this.rollbackOnChecked = rollbackOnChecked;
|
||||
this.created = created;
|
||||
this.transaction = transaction;
|
||||
this.suspendedTransaction = suspendedTransaction;
|
||||
this.scopeMgr = scopeMgr;
|
||||
|
||||
this.noRollbackFor = txScope.getNoRollbackFor();
|
||||
this.rollbackFor = txScope.getRollbackFor();
|
||||
|
||||
Thread t = Thread.currentThread();
|
||||
originalUncaughtHandler = t.getUncaughtExceptionHandler();
|
||||
|
||||
t.setUncaughtExceptionHandler(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the Thread catches any uncaught exception.
|
||||
* For example, an unexpected NullPointerException or Error.
|
||||
*/
|
||||
public void uncaughtException(Thread thread, Throwable e) {
|
||||
|
||||
// rollback transaction if required
|
||||
caughtThrowable(e);
|
||||
|
||||
// reinstate suspended transaction and
|
||||
// original uncaughtExceptionHandler if required
|
||||
onFinally();
|
||||
|
||||
if (originalUncaughtHandler != null){
|
||||
originalUncaughtHandler.uncaughtException(thread, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returned via RETURN or expected Exception from the method.
|
||||
* @param returnOrThrowable the return value or Throwable
|
||||
* @param opCode indicates
|
||||
*/
|
||||
public void onExit(Object returnOrThrowable, int opCode) {
|
||||
|
||||
if (opCode == OPCODE_ATHROW){
|
||||
// exited with a Throwable
|
||||
caughtThrowable((Throwable)returnOrThrowable);
|
||||
}
|
||||
onFinally();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Commit if the transaction exists and has not already been rolled back.
|
||||
* Also reinstate the suspended transaction if there was one.
|
||||
*/
|
||||
public void onFinally() {
|
||||
try {
|
||||
if (originalUncaughtHandler != null){
|
||||
Thread.currentThread().setUncaughtExceptionHandler(originalUncaughtHandler);
|
||||
}
|
||||
|
||||
if (!rolledBack && created) {
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (suspendedTransaction != null){
|
||||
// put the previously suspended transaction
|
||||
// back onto the ThreadLocal or equivalent
|
||||
scopeMgr.replace(suspendedTransaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An Error was caught and this ALWAYS causes a rollback to occur.
|
||||
* Returns the error and this should be thrown by the calling code.
|
||||
*/
|
||||
public Error caughtError(Error e) {
|
||||
rollback(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* An Exception was caught and may or may not cause a rollback to occur.
|
||||
* Returns the exception and this should be thrown by the calling code.
|
||||
*/
|
||||
public <T extends Throwable> T caughtThrowable(T e) {
|
||||
|
||||
if (isRollbackThrowable(e)) {
|
||||
rollback(e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
private void rollback(Throwable e) {
|
||||
if (transaction != null && transaction.isActive()) {
|
||||
// transaction is null for NOT_SUPPORTED and sometimes SUPPORTS
|
||||
// and Inactive (already rolled back) if nested REQUIRED
|
||||
transaction.rollback(e);
|
||||
}
|
||||
rolledBack = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this throwable should cause a rollback to occur.
|
||||
*/
|
||||
private boolean isRollbackThrowable(Throwable e) {
|
||||
|
||||
if (e instanceof Error){
|
||||
return true;
|
||||
}
|
||||
|
||||
if (noRollbackFor != null){
|
||||
for (int i = 0; i < noRollbackFor.size(); i++) {
|
||||
if (noRollbackFor.get(i).equals(e.getClass())) {
|
||||
|
||||
// explicit no rollback for this one
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rollbackFor != null){
|
||||
for (int i = 0; i < rollbackFor.size(); i++) {
|
||||
if (rollbackFor.get(i).equals(e.getClass())) {
|
||||
// explicit rollback for this one
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (e instanceof RuntimeException) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// checked exceptions...
|
||||
// EJB defaults this to false which is not intuitive IMO
|
||||
// Ebean makes this configurable (default to true)
|
||||
return rollbackOnChecked;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,210 +1,191 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.TxScope;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.BeanLoader;
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
|
||||
import com.avaje.ebeaninternal.server.core.PstmtBatch;
|
||||
import com.avaje.ebeaninternal.server.core.SpiOrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.ddl.DdlGenerator;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.query.CQuery;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
/**
|
||||
* Service Provider extension to EbeanServer.
|
||||
*/
|
||||
public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionLoader {
|
||||
|
||||
/**
|
||||
* Return true if DeleteMissingChildren defaults to true for stateless updates.
|
||||
*/
|
||||
public boolean isDefaultDeleteMissingChildren();
|
||||
|
||||
/**
|
||||
* Return true if UpdateNullProperties defaults to true for stateless updates.
|
||||
*/
|
||||
public boolean isDefaultUpdateNullProperties();
|
||||
|
||||
/**
|
||||
* Return true if vanilla beans should be returned by queries by default.
|
||||
*/
|
||||
public boolean isVanillaMode();
|
||||
|
||||
/**
|
||||
* Return the DatabasePlatform for this server.
|
||||
*/
|
||||
public DatabasePlatform getDatabasePlatform();
|
||||
|
||||
/**
|
||||
* Return a JDBC driver specific handler for batching.
|
||||
* <p>
|
||||
* Required for Oracle specific batch handling.
|
||||
* </p>
|
||||
*/
|
||||
public PstmtBatch getPstmtBatch();
|
||||
|
||||
/**
|
||||
* Create an object to represent the current CallStack.
|
||||
* <p>
|
||||
* Typically used to identify the origin of queries for Autofetch
|
||||
* and object graph costing.
|
||||
* </p>
|
||||
*/
|
||||
public CallStack createCallStack();
|
||||
|
||||
/**
|
||||
* Return the DDL generator.
|
||||
*/
|
||||
public DdlGenerator getDdlGenerator();
|
||||
|
||||
/**
|
||||
* Return the AutoFetchListener.
|
||||
*/
|
||||
public AutoFetchManager getAutoFetchManager();
|
||||
|
||||
/**
|
||||
* Clear the query execution statistics.
|
||||
*/
|
||||
public void clearQueryStatistics();
|
||||
|
||||
/**
|
||||
* Return all the descriptors.
|
||||
*/
|
||||
public List<BeanDescriptor<?>> getBeanDescriptors();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for a given type of bean.
|
||||
*/
|
||||
public <T> BeanDescriptor<T> getBeanDescriptor(Class<T> type);
|
||||
|
||||
/**
|
||||
* Return BeanDescriptor using it's unique id.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptorById(String descriptorId);
|
||||
|
||||
/**
|
||||
* Return BeanDescriptors mapped to this table.
|
||||
*/
|
||||
public List<BeanDescriptor<?>> getBeanDescriptors(String tableName);
|
||||
|
||||
/**
|
||||
* Process committed changes from another framework.
|
||||
* <p>
|
||||
* This notifies this instance of the framework that beans have been
|
||||
* committed externally to it. Either by another framework or clustered
|
||||
* server. It uses this to maintain its cache and text indexes
|
||||
* appropriately.
|
||||
* </p>
|
||||
*/
|
||||
public void externalModification(TransactionEventTable event);
|
||||
|
||||
/**
|
||||
* Create a ServerTransaction.
|
||||
* <p>
|
||||
* To specify to use the default transaction isolation use a value of -1.
|
||||
* </p>
|
||||
*/
|
||||
public SpiTransaction createServerTransaction(boolean isExplicit, int isolationLevel);
|
||||
|
||||
/**
|
||||
* Return the current transaction or null if there is no current
|
||||
* transaction.
|
||||
*/
|
||||
public SpiTransaction getCurrentServerTransaction();
|
||||
|
||||
/**
|
||||
* Create a ScopeTrans for a method for the given scope definition.
|
||||
*/
|
||||
public ScopeTrans createScopeTrans(TxScope txScope);
|
||||
|
||||
/**
|
||||
* Create a ServerTransaction for query purposes.
|
||||
*/
|
||||
public SpiTransaction createQueryTransaction();
|
||||
|
||||
/**
|
||||
* An event from another server in the cluster used to notify local
|
||||
* BeanListeners of remote inserts updates and deletes.
|
||||
*/
|
||||
public void remoteTransactionEvent(RemoteTransactionEvent event);
|
||||
|
||||
|
||||
/**
|
||||
* Create a query request object.
|
||||
*/
|
||||
public <T> SpiOrmQueryRequest<T> createQueryRequest(BeanDescriptor<T> desc, SpiQuery<T> q, Transaction t);
|
||||
|
||||
/**
|
||||
* Compile a query.
|
||||
*/
|
||||
public <T> CQuery<T> compileQuery(Query<T> query, Transaction t);
|
||||
|
||||
/**
|
||||
* Return the queryEngine for this server.
|
||||
*/
|
||||
public CQueryEngine getQueryEngine();
|
||||
|
||||
/**
|
||||
* Execute the findId's query but without copying the query.
|
||||
* <p>
|
||||
* Used so that the list of Id's can be made accessible to client code
|
||||
* before the query has finished (if executing in a background thread).
|
||||
* </p>
|
||||
*/
|
||||
public <T> List<Object> findIdsWithCopy(Query<T> query, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the findRowCount query but without copying the query.
|
||||
*/
|
||||
public <T> int findRowCountWithCopy(Query<T> query, Transaction t);
|
||||
|
||||
/**
|
||||
* Load a batch of Associated One Beans.
|
||||
*/
|
||||
public void loadBean(LoadBeanRequest loadRequest);
|
||||
|
||||
/**
|
||||
* Lazy load a batch of Many's.
|
||||
*/
|
||||
public void loadMany(LoadManyRequest loadRequest);
|
||||
|
||||
/**
|
||||
* Return the default batch size for lazy loading.
|
||||
*/
|
||||
public int getLazyLoadBatchSize();
|
||||
|
||||
/**
|
||||
* Return true if the type is known as an Entity or Xml type
|
||||
* or a List Set or Map of known bean types.
|
||||
*/
|
||||
public boolean isSupportedType(java.lang.reflect.Type genericType);
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.TxScope;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.BeanLoader;
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
|
||||
import com.avaje.ebeaninternal.server.core.PstmtBatch;
|
||||
import com.avaje.ebeaninternal.server.core.SpiOrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.ddl.DdlGenerator;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.query.CQuery;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
/**
|
||||
* Service Provider extension to EbeanServer.
|
||||
*/
|
||||
public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionLoader {
|
||||
|
||||
/**
|
||||
* Return true if DeleteMissingChildren defaults to true for stateless updates.
|
||||
*/
|
||||
public boolean isDefaultDeleteMissingChildren();
|
||||
|
||||
/**
|
||||
* Return true if UpdateNullProperties defaults to true for stateless updates.
|
||||
*/
|
||||
public boolean isDefaultUpdateNullProperties();
|
||||
|
||||
/**
|
||||
* Return true if vanilla beans should be returned by queries by default.
|
||||
*/
|
||||
public boolean isVanillaMode();
|
||||
|
||||
/**
|
||||
* Return the DatabasePlatform for this server.
|
||||
*/
|
||||
public DatabasePlatform getDatabasePlatform();
|
||||
|
||||
/**
|
||||
* Return a JDBC driver specific handler for batching.
|
||||
* <p>
|
||||
* Required for Oracle specific batch handling.
|
||||
* </p>
|
||||
*/
|
||||
public PstmtBatch getPstmtBatch();
|
||||
|
||||
/**
|
||||
* Create an object to represent the current CallStack.
|
||||
* <p>
|
||||
* Typically used to identify the origin of queries for Autofetch
|
||||
* and object graph costing.
|
||||
* </p>
|
||||
*/
|
||||
public CallStack createCallStack();
|
||||
|
||||
/**
|
||||
* Return the DDL generator.
|
||||
*/
|
||||
public DdlGenerator getDdlGenerator();
|
||||
|
||||
/**
|
||||
* Return the AutoFetchListener.
|
||||
*/
|
||||
public AutoFetchManager getAutoFetchManager();
|
||||
|
||||
/**
|
||||
* Clear the query execution statistics.
|
||||
*/
|
||||
public void clearQueryStatistics();
|
||||
|
||||
/**
|
||||
* Return all the descriptors.
|
||||
*/
|
||||
public List<BeanDescriptor<?>> getBeanDescriptors();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for a given type of bean.
|
||||
*/
|
||||
public <T> BeanDescriptor<T> getBeanDescriptor(Class<T> type);
|
||||
|
||||
/**
|
||||
* Return BeanDescriptor using it's unique id.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptorById(String descriptorId);
|
||||
|
||||
/**
|
||||
* Return BeanDescriptors mapped to this table.
|
||||
*/
|
||||
public List<BeanDescriptor<?>> getBeanDescriptors(String tableName);
|
||||
|
||||
/**
|
||||
* Process committed changes from another framework.
|
||||
* <p>
|
||||
* This notifies this instance of the framework that beans have been
|
||||
* committed externally to it. Either by another framework or clustered
|
||||
* server. It uses this to maintain its cache and text indexes
|
||||
* appropriately.
|
||||
* </p>
|
||||
*/
|
||||
public void externalModification(TransactionEventTable event);
|
||||
|
||||
/**
|
||||
* Create a ServerTransaction.
|
||||
* <p>
|
||||
* To specify to use the default transaction isolation use a value of -1.
|
||||
* </p>
|
||||
*/
|
||||
public SpiTransaction createServerTransaction(boolean isExplicit, int isolationLevel);
|
||||
|
||||
/**
|
||||
* Return the current transaction or null if there is no current
|
||||
* transaction.
|
||||
*/
|
||||
public SpiTransaction getCurrentServerTransaction();
|
||||
|
||||
/**
|
||||
* Create a ScopeTrans for a method for the given scope definition.
|
||||
*/
|
||||
public ScopeTrans createScopeTrans(TxScope txScope);
|
||||
|
||||
/**
|
||||
* Create a ServerTransaction for query purposes.
|
||||
*/
|
||||
public SpiTransaction createQueryTransaction();
|
||||
|
||||
/**
|
||||
* An event from another server in the cluster used to notify local
|
||||
* BeanListeners of remote inserts updates and deletes.
|
||||
*/
|
||||
public void remoteTransactionEvent(RemoteTransactionEvent event);
|
||||
|
||||
|
||||
/**
|
||||
* Create a query request object.
|
||||
*/
|
||||
public <T> SpiOrmQueryRequest<T> createQueryRequest(BeanDescriptor<T> desc, SpiQuery<T> q, Transaction t);
|
||||
|
||||
/**
|
||||
* Compile a query.
|
||||
*/
|
||||
public <T> CQuery<T> compileQuery(Query<T> query, Transaction t);
|
||||
|
||||
/**
|
||||
* Return the queryEngine for this server.
|
||||
*/
|
||||
public CQueryEngine getQueryEngine();
|
||||
|
||||
/**
|
||||
* Execute the findId's query but without copying the query.
|
||||
* <p>
|
||||
* Used so that the list of Id's can be made accessible to client code
|
||||
* before the query has finished (if executing in a background thread).
|
||||
* </p>
|
||||
*/
|
||||
public <T> List<Object> findIdsWithCopy(Query<T> query, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the findRowCount query but without copying the query.
|
||||
*/
|
||||
public <T> int findRowCountWithCopy(Query<T> query, Transaction t);
|
||||
|
||||
/**
|
||||
* Load a batch of Associated One Beans.
|
||||
*/
|
||||
public void loadBean(LoadBeanRequest loadRequest);
|
||||
|
||||
/**
|
||||
* Lazy load a batch of Many's.
|
||||
*/
|
||||
public void loadMany(LoadManyRequest loadRequest);
|
||||
|
||||
/**
|
||||
* Return the default batch size for lazy loading.
|
||||
*/
|
||||
public int getLazyLoadBatchSize();
|
||||
|
||||
/**
|
||||
* Return true if the type is known as an Entity or Xml type
|
||||
* or a List Set or Map of known bean types.
|
||||
*/
|
||||
public boolean isSupportedType(java.lang.reflect.Type genericType);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,32 +1,13 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebeaninternal.server.expression.FilterExprPath;
|
||||
|
||||
public interface SpiExpressionFactory extends ExpressionFactory {
|
||||
|
||||
/**
|
||||
* Create another expression factory with a given sub path.
|
||||
*/
|
||||
public ExpressionFactory createExpressionFactory(FilterExprPath prefix);
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebeaninternal.server.expression.FilterExprPath;
|
||||
|
||||
public interface SpiExpressionFactory extends ExpressionFactory {
|
||||
|
||||
/**
|
||||
* Create another expression factory with a given sub path.
|
||||
*/
|
||||
public ExpressionFactory createExpressionFactory(FilterExprPath prefix);
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,203 +1,184 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionLogBuffer;
|
||||
|
||||
/**
|
||||
* Extends Transaction with additional API required on server.
|
||||
* <p>
|
||||
* Provides support for batching and TransactionContext.
|
||||
* </p>
|
||||
*/
|
||||
public interface SpiTransaction extends Transaction {
|
||||
|
||||
/**
|
||||
* Return true if generated SQL and Bind values should be logged to the
|
||||
* transaction log.
|
||||
*/
|
||||
public boolean isLogSql();
|
||||
|
||||
/**
|
||||
* Return true if summary level events should be logged to the transaction
|
||||
* log.
|
||||
*/
|
||||
public boolean isLogSummary();
|
||||
|
||||
/**
|
||||
* Log a comment to the transaction log for Ebean INTERNAL use. There should
|
||||
* always be an external LogLevel check prior to calling this method.
|
||||
*/
|
||||
public void logInternal(String msg);
|
||||
|
||||
/**
|
||||
* Return the buffer containing transaction log messages.
|
||||
*/
|
||||
public TransactionLogBuffer getLogBuffer();
|
||||
|
||||
/**
|
||||
* Register a "Derived Relationship" (that requires an additional update).
|
||||
*/
|
||||
public void registerDerivedRelationship(DerivedRelationshipData assocBean);
|
||||
|
||||
/**
|
||||
* Return the list of "Derived Relationships" that must be maintained after
|
||||
* insert.
|
||||
*/
|
||||
public List<DerivedRelationshipData> getDerivedRelationship(Object bean);
|
||||
|
||||
/**
|
||||
* Add a deleting bean to the registered list.
|
||||
* <p>
|
||||
* This is to handle bi-directional relationships where both sides Cascade.
|
||||
* </p>
|
||||
*/
|
||||
public void registerDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Unregister the hash of the bean.
|
||||
*/
|
||||
public void unregisterDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been saved/deleted.
|
||||
*/
|
||||
public boolean isRegisteredDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Unregister the persisted bean.
|
||||
*/
|
||||
public void unregisterBean(Object bean);
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been persisted in the
|
||||
* current recursive save request. The goal is to stop recursively saving
|
||||
* the bean when cascade persist is on both sides of a relationship).
|
||||
* <p>
|
||||
* This will register the bean if it is not already.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isRegisteredBean(Object bean);
|
||||
|
||||
/**
|
||||
* Returns a String used to identify the transaction. This id is used for
|
||||
* Transaction logging.
|
||||
*/
|
||||
public String getId();
|
||||
|
||||
/**
|
||||
* Return the batchSize specifically set for this transaction or 0.
|
||||
* <p>
|
||||
* Returning 0 implies to use the system wide default batch size.
|
||||
* </p>
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
/**
|
||||
* Modify and return the current 'depth' of the transaction.
|
||||
* <p>
|
||||
* As we cascade save or delete we traverse the object graph tree. Going up
|
||||
* to Assoc Ones the depth decreases and going down to Assoc Manys the depth
|
||||
* increases.
|
||||
* </p>
|
||||
* <p>
|
||||
* The depth is used for ordering batching statements. The lowest depth get
|
||||
* executed first during save.
|
||||
* </p>
|
||||
*/
|
||||
public int depth(int diff);
|
||||
|
||||
/**
|
||||
* Return true if this transaction was created explicitly via
|
||||
* <code>Ebean.beginTransaction()</code>.
|
||||
*/
|
||||
public boolean isExplicit();
|
||||
|
||||
/**
|
||||
* Get the object that holds the event details.
|
||||
* <p>
|
||||
* This information is used maintain the table state, cache and text
|
||||
* indexes. On commit the Table modifications this generates is broadcast
|
||||
* around the cluster (if you have a cluster).
|
||||
* </p>
|
||||
*/
|
||||
public TransactionEvent getEvent();
|
||||
|
||||
/**
|
||||
* Whether persistCascade is on for save and delete.
|
||||
*/
|
||||
public boolean isPersistCascade();
|
||||
|
||||
/**
|
||||
* Return true if this request should be batched. Conversely returns false
|
||||
* if this request should be executed immediately.
|
||||
*/
|
||||
public boolean isBatchThisRequest();
|
||||
|
||||
/**
|
||||
* Return the queue used to batch up persist requests.
|
||||
*/
|
||||
public BatchControl getBatchControl();
|
||||
|
||||
/**
|
||||
* Set the queue used to batch up persist requests. There should only be one
|
||||
* PersistQueue set per transaction.
|
||||
*/
|
||||
public void setBatchControl(BatchControl control);
|
||||
|
||||
/**
|
||||
* Return the persistence context associated with this transaction.
|
||||
* <p>
|
||||
* You may wish to hold onto this and set it against another transaction
|
||||
* later. This is along the lines of 'extended persistence context'
|
||||
* behaviour.
|
||||
* </p>
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Set the persistence context to this transaction.
|
||||
* <p>
|
||||
* This could be considered similar to 'EJB3 Extended Persistence Context'.
|
||||
* In that you can get the PersistenceContext from a transaction, hold onto
|
||||
* it, and then set it back later to a second transaction. In general there
|
||||
* is one PersistenceContext per Transaction. The getPersistenceContext()
|
||||
* and setPersistenceContext() enable a developer to reuse a single
|
||||
* PersistenceContext with multiple transactions.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersistenceContext(PersistenceContext context);
|
||||
|
||||
/**
|
||||
* Return the underlying Connection for internal use.
|
||||
* <p>
|
||||
* If the connection is made public from Transaction and the user code calls
|
||||
* that method we can no longer trust the query only status of a
|
||||
* Transaction.
|
||||
* </p>
|
||||
*/
|
||||
public Connection getInternalConnection();
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionLogBuffer;
|
||||
|
||||
/**
|
||||
* Extends Transaction with additional API required on server.
|
||||
* <p>
|
||||
* Provides support for batching and TransactionContext.
|
||||
* </p>
|
||||
*/
|
||||
public interface SpiTransaction extends Transaction {
|
||||
|
||||
/**
|
||||
* Return true if generated SQL and Bind values should be logged to the
|
||||
* transaction log.
|
||||
*/
|
||||
public boolean isLogSql();
|
||||
|
||||
/**
|
||||
* Return true if summary level events should be logged to the transaction
|
||||
* log.
|
||||
*/
|
||||
public boolean isLogSummary();
|
||||
|
||||
/**
|
||||
* Log a comment to the transaction log for Ebean INTERNAL use. There should
|
||||
* always be an external LogLevel check prior to calling this method.
|
||||
*/
|
||||
public void logInternal(String msg);
|
||||
|
||||
/**
|
||||
* Return the buffer containing transaction log messages.
|
||||
*/
|
||||
public TransactionLogBuffer getLogBuffer();
|
||||
|
||||
/**
|
||||
* Register a "Derived Relationship" (that requires an additional update).
|
||||
*/
|
||||
public void registerDerivedRelationship(DerivedRelationshipData assocBean);
|
||||
|
||||
/**
|
||||
* Return the list of "Derived Relationships" that must be maintained after
|
||||
* insert.
|
||||
*/
|
||||
public List<DerivedRelationshipData> getDerivedRelationship(Object bean);
|
||||
|
||||
/**
|
||||
* Add a deleting bean to the registered list.
|
||||
* <p>
|
||||
* This is to handle bi-directional relationships where both sides Cascade.
|
||||
* </p>
|
||||
*/
|
||||
public void registerDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Unregister the hash of the bean.
|
||||
*/
|
||||
public void unregisterDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been saved/deleted.
|
||||
*/
|
||||
public boolean isRegisteredDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Unregister the persisted bean.
|
||||
*/
|
||||
public void unregisterBean(Object bean);
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been persisted in the
|
||||
* current recursive save request. The goal is to stop recursively saving
|
||||
* the bean when cascade persist is on both sides of a relationship).
|
||||
* <p>
|
||||
* This will register the bean if it is not already.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isRegisteredBean(Object bean);
|
||||
|
||||
/**
|
||||
* Returns a String used to identify the transaction. This id is used for
|
||||
* Transaction logging.
|
||||
*/
|
||||
public String getId();
|
||||
|
||||
/**
|
||||
* Return the batchSize specifically set for this transaction or 0.
|
||||
* <p>
|
||||
* Returning 0 implies to use the system wide default batch size.
|
||||
* </p>
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
/**
|
||||
* Modify and return the current 'depth' of the transaction.
|
||||
* <p>
|
||||
* As we cascade save or delete we traverse the object graph tree. Going up
|
||||
* to Assoc Ones the depth decreases and going down to Assoc Manys the depth
|
||||
* increases.
|
||||
* </p>
|
||||
* <p>
|
||||
* The depth is used for ordering batching statements. The lowest depth get
|
||||
* executed first during save.
|
||||
* </p>
|
||||
*/
|
||||
public int depth(int diff);
|
||||
|
||||
/**
|
||||
* Return true if this transaction was created explicitly via
|
||||
* <code>Ebean.beginTransaction()</code>.
|
||||
*/
|
||||
public boolean isExplicit();
|
||||
|
||||
/**
|
||||
* Get the object that holds the event details.
|
||||
* <p>
|
||||
* This information is used maintain the table state, cache and text
|
||||
* indexes. On commit the Table modifications this generates is broadcast
|
||||
* around the cluster (if you have a cluster).
|
||||
* </p>
|
||||
*/
|
||||
public TransactionEvent getEvent();
|
||||
|
||||
/**
|
||||
* Whether persistCascade is on for save and delete.
|
||||
*/
|
||||
public boolean isPersistCascade();
|
||||
|
||||
/**
|
||||
* Return true if this request should be batched. Conversely returns false
|
||||
* if this request should be executed immediately.
|
||||
*/
|
||||
public boolean isBatchThisRequest();
|
||||
|
||||
/**
|
||||
* Return the queue used to batch up persist requests.
|
||||
*/
|
||||
public BatchControl getBatchControl();
|
||||
|
||||
/**
|
||||
* Set the queue used to batch up persist requests. There should only be one
|
||||
* PersistQueue set per transaction.
|
||||
*/
|
||||
public void setBatchControl(BatchControl control);
|
||||
|
||||
/**
|
||||
* Return the persistence context associated with this transaction.
|
||||
* <p>
|
||||
* You may wish to hold onto this and set it against another transaction
|
||||
* later. This is along the lines of 'extended persistence context'
|
||||
* behaviour.
|
||||
* </p>
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Set the persistence context to this transaction.
|
||||
* <p>
|
||||
* This could be considered similar to 'EJB3 Extended Persistence Context'.
|
||||
* In that you can get the PersistenceContext from a transaction, hold onto
|
||||
* it, and then set it back later to a second transaction. In general there
|
||||
* is one PersistenceContext per Transaction. The getPersistenceContext()
|
||||
* and setPersistenceContext() enable a developer to reuse a single
|
||||
* PersistenceContext with multiple transactions.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersistenceContext(PersistenceContext context);
|
||||
|
||||
/**
|
||||
* Return the underlying Connection for internal use.
|
||||
* <p>
|
||||
* If the connection is made public from Transaction and the user code calls
|
||||
* that method we can no longer trust the query only status of a
|
||||
* Transaction.
|
||||
* </p>
|
||||
*/
|
||||
public Connection getInternalConnection();
|
||||
}
|
||||
|
||||
@@ -1,94 +1,75 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.ConcurrencyMode;
|
||||
import com.avaje.ebeaninternal.server.persist.dml.DmlHandler;
|
||||
import com.avaje.ebeaninternal.server.persist.dmlbind.Bindable;
|
||||
|
||||
/**
|
||||
* A plan for executing bean updates for a given set of changed properties.
|
||||
* <p>
|
||||
* This is a cachable plan with the purpose of being being able to skip some
|
||||
* phases of the update bean processing.
|
||||
* </p>
|
||||
* <p>
|
||||
* The plans are cached by the BeanDescriptors.
|
||||
* </>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface SpiUpdatePlan {
|
||||
|
||||
/**
|
||||
* Return true if the set clause has no columns.
|
||||
* <p>
|
||||
* Can occur when the only columns updated have a updatable=false in their
|
||||
* deployment.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isEmptySetClause();
|
||||
|
||||
/**
|
||||
* Bind given the request and bean. The bean could be the oldValues bean
|
||||
* when binding a update or delete where clause with ALL concurrency mode.
|
||||
*/
|
||||
public void bindSet(DmlHandler bind, Object bean) throws SQLException;
|
||||
|
||||
/**
|
||||
* Return the time this plan was created.
|
||||
*/
|
||||
public long getTimeCreated();
|
||||
|
||||
/**
|
||||
* Return the time this plan was last used.
|
||||
*/
|
||||
public Long getTimeLastUsed();
|
||||
|
||||
/**
|
||||
* Return the hash key for this plan.
|
||||
*/
|
||||
public Integer getKey();
|
||||
|
||||
/**
|
||||
* Return the concurrency mode for this plan.
|
||||
*/
|
||||
public ConcurrencyMode getMode();
|
||||
|
||||
/**
|
||||
* Return the update SQL statement.
|
||||
*/
|
||||
public String getSql();
|
||||
|
||||
/**
|
||||
* Return the set of bindable update properties.
|
||||
*/
|
||||
public Bindable getSet();
|
||||
|
||||
/**
|
||||
* Return the properties that where changed and should be included in the
|
||||
* update statement.
|
||||
*/
|
||||
public Set<String> getProperties();
|
||||
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.ConcurrencyMode;
|
||||
import com.avaje.ebeaninternal.server.persist.dml.DmlHandler;
|
||||
import com.avaje.ebeaninternal.server.persist.dmlbind.Bindable;
|
||||
|
||||
/**
|
||||
* A plan for executing bean updates for a given set of changed properties.
|
||||
* <p>
|
||||
* This is a cachable plan with the purpose of being being able to skip some
|
||||
* phases of the update bean processing.
|
||||
* </p>
|
||||
* <p>
|
||||
* The plans are cached by the BeanDescriptors.
|
||||
* </>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface SpiUpdatePlan {
|
||||
|
||||
/**
|
||||
* Return true if the set clause has no columns.
|
||||
* <p>
|
||||
* Can occur when the only columns updated have a updatable=false in their
|
||||
* deployment.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isEmptySetClause();
|
||||
|
||||
/**
|
||||
* Bind given the request and bean. The bean could be the oldValues bean
|
||||
* when binding a update or delete where clause with ALL concurrency mode.
|
||||
*/
|
||||
public void bindSet(DmlHandler bind, Object bean) throws SQLException;
|
||||
|
||||
/**
|
||||
* Return the time this plan was created.
|
||||
*/
|
||||
public long getTimeCreated();
|
||||
|
||||
/**
|
||||
* Return the time this plan was last used.
|
||||
*/
|
||||
public Long getTimeLastUsed();
|
||||
|
||||
/**
|
||||
* Return the hash key for this plan.
|
||||
*/
|
||||
public Integer getKey();
|
||||
|
||||
/**
|
||||
* Return the concurrency mode for this plan.
|
||||
*/
|
||||
public ConcurrencyMode getMode();
|
||||
|
||||
/**
|
||||
* Return the update SQL statement.
|
||||
*/
|
||||
public String getSql();
|
||||
|
||||
/**
|
||||
* Return the set of bindable update properties.
|
||||
*/
|
||||
public Bindable getSet();
|
||||
|
||||
/**
|
||||
* Return the properties that where changed and should be included in the
|
||||
* update statement.
|
||||
*/
|
||||
public Set<String> getProperties();
|
||||
|
||||
}
|
||||
@@ -1,221 +1,202 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanDelta;
|
||||
import com.avaje.ebeaninternal.server.transaction.DeleteByIdMap;
|
||||
import com.avaje.ebeaninternal.server.transaction.IndexInvalidate;
|
||||
|
||||
/**
|
||||
* Holds information for a transaction. There is one TransactionEvent instance
|
||||
* per Transaction instance.
|
||||
* <p>
|
||||
* When the associated Transaction commits or rollback this information is sent
|
||||
* to the TransactionEventManager.
|
||||
* </p>
|
||||
*/
|
||||
public class TransactionEvent implements Serializable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TransactionEvent.class.getName());
|
||||
|
||||
private static final long serialVersionUID = 7230903304106097120L;
|
||||
|
||||
/**
|
||||
* Flag indicating this is a local transaction (not from another server in
|
||||
* the cluster).
|
||||
*/
|
||||
private transient boolean local;
|
||||
|
||||
private boolean invalidateAll;
|
||||
|
||||
private TransactionEventTable eventTables;
|
||||
|
||||
private transient TransactionEventBeans eventBeans;
|
||||
|
||||
private transient List<BeanDelta> beanDeltas;
|
||||
|
||||
private transient DeleteByIdMap deleteByIdMap;
|
||||
|
||||
private transient Set<IndexInvalidate> indexInvalidations;
|
||||
|
||||
private transient Set<String> pauseIndexInvalidate;
|
||||
|
||||
/**
|
||||
* Create the TransactionEvent, one per Transaction.
|
||||
*/
|
||||
public TransactionEvent() {
|
||||
this.local = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to true to invalidate all table dependent cached objects.
|
||||
*/
|
||||
public void setInvalidateAll(boolean isInvalidateAll) {
|
||||
this.invalidateAll = isInvalidateAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if all table states should be invalidated. This will cause
|
||||
* all cached objects to be invalidated.
|
||||
*/
|
||||
public boolean isInvalidateAll() {
|
||||
return invalidateAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily pause/ignore any index invalidation for this bean type.
|
||||
*/
|
||||
public void pauseIndexInvalidate(Class<?> beanType) {
|
||||
if (pauseIndexInvalidate == null){
|
||||
pauseIndexInvalidate = new HashSet<String>();
|
||||
}
|
||||
pauseIndexInvalidate.add(beanType.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume listening for index invalidation for this bean type.
|
||||
*/
|
||||
public void resumeIndexInvalidate(Class<?> beanType) {
|
||||
if (pauseIndexInvalidate != null){
|
||||
pauseIndexInvalidate.remove(beanType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an IndexInvalidation notices to the transaction.
|
||||
*/
|
||||
public void addIndexInvalidate(IndexInvalidate indexEvent){
|
||||
if (pauseIndexInvalidate != null && pauseIndexInvalidate.contains(indexEvent.getIndexName())){
|
||||
logger.fine("--- IGNORE Invalidate on "+indexEvent.getIndexName());
|
||||
return;
|
||||
}
|
||||
if (indexInvalidations == null){
|
||||
indexInvalidations = new HashSet<IndexInvalidate>();
|
||||
}
|
||||
indexInvalidations.add(indexEvent);
|
||||
}
|
||||
|
||||
public void addDeleteById(BeanDescriptor<?> desc, Object id){
|
||||
if (deleteByIdMap == null){
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
deleteByIdMap.add(desc, id);
|
||||
}
|
||||
|
||||
public void addDeleteByIdList(BeanDescriptor<?> desc, List<Object> idList) {
|
||||
if (deleteByIdMap == null) {
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
deleteByIdMap.addList(desc, idList);
|
||||
}
|
||||
|
||||
public DeleteByIdMap getDeleteByIdMap() {
|
||||
return deleteByIdMap;
|
||||
}
|
||||
|
||||
public void addBeanDelta(BeanDelta delta) {
|
||||
if (beanDeltas == null) {
|
||||
beanDeltas = new ArrayList<BeanDelta>();
|
||||
}
|
||||
beanDeltas.add(delta);
|
||||
}
|
||||
|
||||
public List<BeanDelta> getBeanDeltas() {
|
||||
return beanDeltas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this was a local transaction. Returns false if this
|
||||
* transaction originated on another server in the cluster.
|
||||
*/
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
/**
|
||||
* For BeanListeners the requests they are interested in.
|
||||
*/
|
||||
public TransactionEventBeans getEventBeans() {
|
||||
return eventBeans;
|
||||
}
|
||||
|
||||
public TransactionEventTable getEventTables() {
|
||||
return eventTables;
|
||||
}
|
||||
|
||||
public Set<IndexInvalidate> getIndexInvalidations() {
|
||||
return indexInvalidations;
|
||||
}
|
||||
|
||||
public void add(String tableName, boolean inserts, boolean updates, boolean deletes){
|
||||
if (eventTables == null){
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(tableName, inserts, updates, deletes);
|
||||
}
|
||||
|
||||
public void add(TransactionEventTable table){
|
||||
if (eventTables == null){
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a inserted updated or deleted bean to the event.
|
||||
*/
|
||||
public void add(PersistRequestBean<?> request) {
|
||||
|
||||
if (request.isNotify(this)){
|
||||
// either a BeanListener or Cache is interested
|
||||
if (eventBeans == null) {
|
||||
eventBeans = new TransactionEventBeans();
|
||||
}
|
||||
eventBeans.add(request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the cache of bean changes.
|
||||
* <p>
|
||||
* This returns the TransactionEventTable so that if any
|
||||
* general table changes can also be used to invalidate
|
||||
* parts of the cache.
|
||||
* </p>
|
||||
*/
|
||||
public void notifyCache(){
|
||||
if (eventBeans != null){
|
||||
eventBeans.notifyCache();
|
||||
}
|
||||
if (deleteByIdMap != null) {
|
||||
deleteByIdMap.notifyCache();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanDelta;
|
||||
import com.avaje.ebeaninternal.server.transaction.DeleteByIdMap;
|
||||
import com.avaje.ebeaninternal.server.transaction.IndexInvalidate;
|
||||
|
||||
/**
|
||||
* Holds information for a transaction. There is one TransactionEvent instance
|
||||
* per Transaction instance.
|
||||
* <p>
|
||||
* When the associated Transaction commits or rollback this information is sent
|
||||
* to the TransactionEventManager.
|
||||
* </p>
|
||||
*/
|
||||
public class TransactionEvent implements Serializable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TransactionEvent.class.getName());
|
||||
|
||||
private static final long serialVersionUID = 7230903304106097120L;
|
||||
|
||||
/**
|
||||
* Flag indicating this is a local transaction (not from another server in
|
||||
* the cluster).
|
||||
*/
|
||||
private transient boolean local;
|
||||
|
||||
private boolean invalidateAll;
|
||||
|
||||
private TransactionEventTable eventTables;
|
||||
|
||||
private transient TransactionEventBeans eventBeans;
|
||||
|
||||
private transient List<BeanDelta> beanDeltas;
|
||||
|
||||
private transient DeleteByIdMap deleteByIdMap;
|
||||
|
||||
private transient Set<IndexInvalidate> indexInvalidations;
|
||||
|
||||
private transient Set<String> pauseIndexInvalidate;
|
||||
|
||||
/**
|
||||
* Create the TransactionEvent, one per Transaction.
|
||||
*/
|
||||
public TransactionEvent() {
|
||||
this.local = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to true to invalidate all table dependent cached objects.
|
||||
*/
|
||||
public void setInvalidateAll(boolean isInvalidateAll) {
|
||||
this.invalidateAll = isInvalidateAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if all table states should be invalidated. This will cause
|
||||
* all cached objects to be invalidated.
|
||||
*/
|
||||
public boolean isInvalidateAll() {
|
||||
return invalidateAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily pause/ignore any index invalidation for this bean type.
|
||||
*/
|
||||
public void pauseIndexInvalidate(Class<?> beanType) {
|
||||
if (pauseIndexInvalidate == null){
|
||||
pauseIndexInvalidate = new HashSet<String>();
|
||||
}
|
||||
pauseIndexInvalidate.add(beanType.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume listening for index invalidation for this bean type.
|
||||
*/
|
||||
public void resumeIndexInvalidate(Class<?> beanType) {
|
||||
if (pauseIndexInvalidate != null){
|
||||
pauseIndexInvalidate.remove(beanType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an IndexInvalidation notices to the transaction.
|
||||
*/
|
||||
public void addIndexInvalidate(IndexInvalidate indexEvent){
|
||||
if (pauseIndexInvalidate != null && pauseIndexInvalidate.contains(indexEvent.getIndexName())){
|
||||
logger.fine("--- IGNORE Invalidate on "+indexEvent.getIndexName());
|
||||
return;
|
||||
}
|
||||
if (indexInvalidations == null){
|
||||
indexInvalidations = new HashSet<IndexInvalidate>();
|
||||
}
|
||||
indexInvalidations.add(indexEvent);
|
||||
}
|
||||
|
||||
public void addDeleteById(BeanDescriptor<?> desc, Object id){
|
||||
if (deleteByIdMap == null){
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
deleteByIdMap.add(desc, id);
|
||||
}
|
||||
|
||||
public void addDeleteByIdList(BeanDescriptor<?> desc, List<Object> idList) {
|
||||
if (deleteByIdMap == null) {
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
deleteByIdMap.addList(desc, idList);
|
||||
}
|
||||
|
||||
public DeleteByIdMap getDeleteByIdMap() {
|
||||
return deleteByIdMap;
|
||||
}
|
||||
|
||||
public void addBeanDelta(BeanDelta delta) {
|
||||
if (beanDeltas == null) {
|
||||
beanDeltas = new ArrayList<BeanDelta>();
|
||||
}
|
||||
beanDeltas.add(delta);
|
||||
}
|
||||
|
||||
public List<BeanDelta> getBeanDeltas() {
|
||||
return beanDeltas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this was a local transaction. Returns false if this
|
||||
* transaction originated on another server in the cluster.
|
||||
*/
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
/**
|
||||
* For BeanListeners the requests they are interested in.
|
||||
*/
|
||||
public TransactionEventBeans getEventBeans() {
|
||||
return eventBeans;
|
||||
}
|
||||
|
||||
public TransactionEventTable getEventTables() {
|
||||
return eventTables;
|
||||
}
|
||||
|
||||
public Set<IndexInvalidate> getIndexInvalidations() {
|
||||
return indexInvalidations;
|
||||
}
|
||||
|
||||
public void add(String tableName, boolean inserts, boolean updates, boolean deletes){
|
||||
if (eventTables == null){
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(tableName, inserts, updates, deletes);
|
||||
}
|
||||
|
||||
public void add(TransactionEventTable table){
|
||||
if (eventTables == null){
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a inserted updated or deleted bean to the event.
|
||||
*/
|
||||
public void add(PersistRequestBean<?> request) {
|
||||
|
||||
if (request.isNotify(this)){
|
||||
// either a BeanListener or Cache is interested
|
||||
if (eventBeans == null) {
|
||||
eventBeans = new TransactionEventBeans();
|
||||
}
|
||||
eventBeans.add(request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the cache of bean changes.
|
||||
* <p>
|
||||
* This returns the TransactionEventTable so that if any
|
||||
* general table changes can also be used to invalidate
|
||||
* parts of the cache.
|
||||
* </p>
|
||||
*/
|
||||
public void notifyCache(){
|
||||
if (eventBeans != null){
|
||||
eventBeans.notifyCache();
|
||||
}
|
||||
if (deleteByIdMap != null) {
|
||||
deleteByIdMap.notifyCache();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,59 +1,40 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
|
||||
/**
|
||||
* Lists of inserted updated and deleted beans that have a BeanPersistListener.
|
||||
* <p>
|
||||
* These beans will be sent to the appropriate BeanListeners after a successful
|
||||
* commit of the transaction.
|
||||
* </p>
|
||||
*/
|
||||
public class TransactionEventBeans {
|
||||
|
||||
ArrayList<PersistRequestBean<?>> requests = new ArrayList<PersistRequestBean<?>>();
|
||||
|
||||
/**
|
||||
* Return the list of PersistRequests that BeanListeners are interested in.
|
||||
*/
|
||||
public List<PersistRequestBean<?>> getRequests() {
|
||||
return requests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a bean for BeanListener notification.
|
||||
*/
|
||||
public void add(PersistRequestBean<?> request) {
|
||||
|
||||
requests.add(request);
|
||||
}
|
||||
|
||||
public void notifyCache() {
|
||||
for (int i = 0; i < requests.size(); i++) {
|
||||
requests.get(i).notifyCache();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
|
||||
/**
|
||||
* Lists of inserted updated and deleted beans that have a BeanPersistListener.
|
||||
* <p>
|
||||
* These beans will be sent to the appropriate BeanListeners after a successful
|
||||
* commit of the transaction.
|
||||
* </p>
|
||||
*/
|
||||
public class TransactionEventBeans {
|
||||
|
||||
ArrayList<PersistRequestBean<?>> requests = new ArrayList<PersistRequestBean<?>>();
|
||||
|
||||
/**
|
||||
* Return the list of PersistRequests that BeanListeners are interested in.
|
||||
*/
|
||||
public List<PersistRequestBean<?>> getRequests() {
|
||||
return requests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a bean for BeanListener notification.
|
||||
*/
|
||||
public void add(PersistRequestBean<?> request) {
|
||||
|
||||
requests.add(request);
|
||||
}
|
||||
|
||||
public void notifyCache() {
|
||||
for (int i = 0; i < requests.size(); i++) {
|
||||
requests.get(i).notifyCache();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
/**
|
||||
* Internal service API.
|
||||
*/
|
||||
package com.avaje.ebeaninternal.api;
|
||||
@@ -1,340 +1,323 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.jdbc;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.NClob;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLClientInfoException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Savepoint;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Struct;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
public class ConnectionDelegator implements Connection
|
||||
{
|
||||
private final Connection delegate;
|
||||
|
||||
public ConnectionDelegator(Connection delegate)
|
||||
{
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public Statement createStatement()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement();
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql);
|
||||
}
|
||||
|
||||
public String nativeSQL(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.nativeSQL(sql);
|
||||
}
|
||||
|
||||
public void setAutoCommit(boolean autoCommit)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setAutoCommit(autoCommit);
|
||||
}
|
||||
|
||||
public boolean getAutoCommit()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getAutoCommit();
|
||||
}
|
||||
|
||||
public void commit()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.commit();
|
||||
}
|
||||
|
||||
public void rollback()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.rollback();
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
public boolean isClosed()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isClosed();
|
||||
}
|
||||
|
||||
public DatabaseMetaData getMetaData()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMetaData();
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setReadOnly(readOnly);
|
||||
}
|
||||
|
||||
public boolean isReadOnly()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isReadOnly();
|
||||
}
|
||||
|
||||
public void setCatalog(String catalog)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setCatalog(catalog);
|
||||
}
|
||||
|
||||
public String getCatalog()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getCatalog();
|
||||
}
|
||||
|
||||
public void setTransactionIsolation(int level)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTransactionIsolation(level);
|
||||
}
|
||||
|
||||
public int getTransactionIsolation()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getTransactionIsolation();
|
||||
}
|
||||
|
||||
public SQLWarning getWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getWarnings();
|
||||
}
|
||||
|
||||
public void clearWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.clearWarnings();
|
||||
}
|
||||
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement(resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql, resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public Map<String, Class<?>> getTypeMap()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getTypeMap();
|
||||
}
|
||||
|
||||
public void setTypeMap(Map<String, Class<?>> map)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTypeMap(map);
|
||||
}
|
||||
|
||||
public void setHoldability(int holdability)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setHoldability(holdability);
|
||||
}
|
||||
|
||||
public int getHoldability()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getHoldability();
|
||||
}
|
||||
|
||||
public Savepoint setSavepoint()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.setSavepoint();
|
||||
}
|
||||
|
||||
public Savepoint setSavepoint(String name)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.setSavepoint(name);
|
||||
}
|
||||
|
||||
public void rollback(Savepoint savepoint)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.rollback(savepoint);
|
||||
}
|
||||
|
||||
public void releaseSavepoint(Savepoint savepoint)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.releaseSavepoint(savepoint);
|
||||
}
|
||||
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, autoGeneratedKeys);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, columnIndexes);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, String[] columnNames)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, columnNames);
|
||||
}
|
||||
|
||||
public Clob createClob()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createClob();
|
||||
}
|
||||
|
||||
public Blob createBlob()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createBlob();
|
||||
}
|
||||
|
||||
public NClob createNClob()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createNClob();
|
||||
}
|
||||
|
||||
public SQLXML createSQLXML()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createSQLXML();
|
||||
}
|
||||
|
||||
public boolean isValid(int timeout)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isValid(timeout);
|
||||
}
|
||||
|
||||
public void setClientInfo(String name, String value)
|
||||
throws SQLClientInfoException
|
||||
{
|
||||
delegate.setClientInfo(name, value);
|
||||
}
|
||||
|
||||
public void setClientInfo(Properties properties)
|
||||
throws SQLClientInfoException
|
||||
{
|
||||
delegate.setClientInfo(properties);
|
||||
}
|
||||
|
||||
public String getClientInfo(String name)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getClientInfo(name);
|
||||
}
|
||||
|
||||
public Properties getClientInfo()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getClientInfo();
|
||||
}
|
||||
|
||||
public Array createArrayOf(String typeName, Object[] elements)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createArrayOf(typeName, elements);
|
||||
}
|
||||
|
||||
public Struct createStruct(String typeName, Object[] attributes)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStruct(typeName, attributes);
|
||||
}
|
||||
|
||||
public <T> T unwrap(Class<T> iface)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.unwrap(iface);
|
||||
}
|
||||
|
||||
public boolean isWrapperFor(Class<?> iface)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isWrapperFor(iface);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.jdbc;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.NClob;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLClientInfoException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Savepoint;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Struct;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
public class ConnectionDelegator implements Connection
|
||||
{
|
||||
private final Connection delegate;
|
||||
|
||||
public ConnectionDelegator(Connection delegate)
|
||||
{
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public Statement createStatement()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement();
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql);
|
||||
}
|
||||
|
||||
public String nativeSQL(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.nativeSQL(sql);
|
||||
}
|
||||
|
||||
public void setAutoCommit(boolean autoCommit)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setAutoCommit(autoCommit);
|
||||
}
|
||||
|
||||
public boolean getAutoCommit()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getAutoCommit();
|
||||
}
|
||||
|
||||
public void commit()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.commit();
|
||||
}
|
||||
|
||||
public void rollback()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.rollback();
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
public boolean isClosed()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isClosed();
|
||||
}
|
||||
|
||||
public DatabaseMetaData getMetaData()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getMetaData();
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setReadOnly(readOnly);
|
||||
}
|
||||
|
||||
public boolean isReadOnly()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isReadOnly();
|
||||
}
|
||||
|
||||
public void setCatalog(String catalog)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setCatalog(catalog);
|
||||
}
|
||||
|
||||
public String getCatalog()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getCatalog();
|
||||
}
|
||||
|
||||
public void setTransactionIsolation(int level)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTransactionIsolation(level);
|
||||
}
|
||||
|
||||
public int getTransactionIsolation()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getTransactionIsolation();
|
||||
}
|
||||
|
||||
public SQLWarning getWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getWarnings();
|
||||
}
|
||||
|
||||
public void clearWarnings()
|
||||
throws SQLException
|
||||
{
|
||||
delegate.clearWarnings();
|
||||
}
|
||||
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement(resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql, resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
public Map<String, Class<?>> getTypeMap()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getTypeMap();
|
||||
}
|
||||
|
||||
public void setTypeMap(Map<String, Class<?>> map)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setTypeMap(map);
|
||||
}
|
||||
|
||||
public void setHoldability(int holdability)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.setHoldability(holdability);
|
||||
}
|
||||
|
||||
public int getHoldability()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getHoldability();
|
||||
}
|
||||
|
||||
public Savepoint setSavepoint()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.setSavepoint();
|
||||
}
|
||||
|
||||
public Savepoint setSavepoint(String name)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.setSavepoint(name);
|
||||
}
|
||||
|
||||
public void rollback(Savepoint savepoint)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.rollback(savepoint);
|
||||
}
|
||||
|
||||
public void releaseSavepoint(Savepoint savepoint)
|
||||
throws SQLException
|
||||
{
|
||||
delegate.releaseSavepoint(savepoint);
|
||||
}
|
||||
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, autoGeneratedKeys);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, columnIndexes);
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql, String[] columnNames)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.prepareStatement(sql, columnNames);
|
||||
}
|
||||
|
||||
public Clob createClob()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createClob();
|
||||
}
|
||||
|
||||
public Blob createBlob()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createBlob();
|
||||
}
|
||||
|
||||
public NClob createNClob()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createNClob();
|
||||
}
|
||||
|
||||
public SQLXML createSQLXML()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createSQLXML();
|
||||
}
|
||||
|
||||
public boolean isValid(int timeout)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isValid(timeout);
|
||||
}
|
||||
|
||||
public void setClientInfo(String name, String value)
|
||||
throws SQLClientInfoException
|
||||
{
|
||||
delegate.setClientInfo(name, value);
|
||||
}
|
||||
|
||||
public void setClientInfo(Properties properties)
|
||||
throws SQLClientInfoException
|
||||
{
|
||||
delegate.setClientInfo(properties);
|
||||
}
|
||||
|
||||
public String getClientInfo(String name)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getClientInfo(name);
|
||||
}
|
||||
|
||||
public Properties getClientInfo()
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.getClientInfo();
|
||||
}
|
||||
|
||||
public Array createArrayOf(String typeName, Object[] elements)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createArrayOf(typeName, elements);
|
||||
}
|
||||
|
||||
public Struct createStruct(String typeName, Object[] attributes)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.createStruct(typeName, attributes);
|
||||
}
|
||||
|
||||
public <T> T unwrap(Class<T> iface)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.unwrap(iface);
|
||||
}
|
||||
|
||||
public boolean isWrapperFor(Class<?> iface)
|
||||
throws SQLException
|
||||
{
|
||||
return delegate.isWrapperFor(iface);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,263 +1,244 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.autofetch;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.bean.NodeUsageListener;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.config.AutofetchMode;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
|
||||
/**
|
||||
* Collects and manages the the profile information.
|
||||
* <p>
|
||||
* The profile information is periodically converted into "tuned query details" -
|
||||
* which is used to automatically tune the queries that use autoFetch.
|
||||
* </p>
|
||||
* <p>
|
||||
* The "tuned query details" effectively are part of the query that has the
|
||||
* select() and join() information (but not the where clause, order by, limits
|
||||
* etc). These are applied to the query when tuneQuery() is called.
|
||||
* </p>
|
||||
*/
|
||||
public interface AutoFetchManager extends NodeUsageListener {
|
||||
|
||||
/**
|
||||
* Set the owning ebean server.
|
||||
*/
|
||||
public void setOwner(SpiEbeanServer server, ServerConfig serverConfig);
|
||||
|
||||
/**
|
||||
* Clear the query execution statistics.
|
||||
*/
|
||||
public void clearQueryStatistics();
|
||||
|
||||
/**
|
||||
* Clear all the tuned query info.
|
||||
* <p>
|
||||
* Should only need do this for testing and playing around.
|
||||
* </p>
|
||||
*/
|
||||
public int clearTunedQueryInfo();
|
||||
|
||||
/**
|
||||
* Clear all the profiling information.
|
||||
* <p>
|
||||
* This means the profiling information will need to be re-gathered.
|
||||
* </p>
|
||||
* <p>
|
||||
* Should only need do this for testing and playing around.
|
||||
* </p>
|
||||
*/
|
||||
public int clearProfilingInfo();
|
||||
|
||||
/**
|
||||
* On shutdown fire garbage collection and collect statistics. Note that
|
||||
* usually we add a little delay (100 milliseconds) to give the garbage
|
||||
* collector plenty of time to do its thing and collect the profile
|
||||
* information.
|
||||
*/
|
||||
public void shutdown();
|
||||
|
||||
/**
|
||||
* Return the current tuned fetch information for a given queryPoint key.
|
||||
*/
|
||||
public TunedQueryInfo getTunedQueryInfo(String queryPointKey);
|
||||
|
||||
/**
|
||||
* Return the current Statistics for a given queryPoint key.
|
||||
*/
|
||||
public Statistics getStatistics(String queryPointKey);
|
||||
|
||||
/**
|
||||
* Iterate the tuned fetch info.
|
||||
* <p>
|
||||
* This should be a read only iteration.
|
||||
* </p>
|
||||
*/
|
||||
public Iterator<TunedQueryInfo> iterateTunedQueryInfo();
|
||||
|
||||
/**
|
||||
* Iterate the node usage statistics.
|
||||
* <p>
|
||||
* This should be a read only iteration.
|
||||
* </p>
|
||||
*/
|
||||
public Iterator<Statistics> iterateStatistics();
|
||||
|
||||
/**
|
||||
* Return true if profiling is enabled.
|
||||
*/
|
||||
public boolean isProfiling();
|
||||
|
||||
/**
|
||||
* Set to true to enable profiling.
|
||||
* <p>
|
||||
* We rely on garbage collection to collect the profiling information. This
|
||||
* means there is a unknown delay between when a query is executed and when
|
||||
* we actually collect the usage profile information.
|
||||
* </p>
|
||||
* <p>
|
||||
* Due to this garbage collection delay, when turning off profiling while
|
||||
* the application is running you should consider calling
|
||||
* collectUsageViaGC() <em>BEFORE</em> setProfiling(false). This hints to
|
||||
* the JVM to perform garbage collection, and hopefully collects the
|
||||
* profiling information.
|
||||
* </p>
|
||||
*/
|
||||
public void setProfiling(boolean enable);
|
||||
|
||||
/**
|
||||
* Return true if automatic query tuning is enabled.
|
||||
*/
|
||||
public boolean isQueryTuning();
|
||||
|
||||
/**
|
||||
* Set to true to enable automatic query tuning.
|
||||
*/
|
||||
public void setQueryTuning(boolean enable);
|
||||
|
||||
/**
|
||||
* This controls whether autoFetch is used when it has not been explicitly
|
||||
* set on a query via {@link Query#setAutoFetch(boolean)}.
|
||||
*/
|
||||
public AutofetchMode getMode();
|
||||
|
||||
/**
|
||||
* Set the auto fetch mode used when a query has not had
|
||||
* {@link Query#setAutoFetch(boolean)}.
|
||||
*/
|
||||
public void setMode(AutofetchMode Mode);
|
||||
|
||||
/**
|
||||
* Return the profiling rate (int between 0 and 100).
|
||||
*/
|
||||
public double getProfilingRate();
|
||||
|
||||
/**
|
||||
* Set the profiling rate (int between 0 and 100).
|
||||
*/
|
||||
public void setProfilingRate(double rate);
|
||||
|
||||
/**
|
||||
* Return the max number of queries profiled (per query point).
|
||||
* <p>
|
||||
* The number of queries profiled is collected per query point. Once a query
|
||||
* point has profiled this number of queries it does not profile any more.
|
||||
* </p>
|
||||
*/
|
||||
public int getProfilingBase();
|
||||
|
||||
/**
|
||||
* Set a max number of queries to profile per query point.
|
||||
* <p>
|
||||
* This number should provide a level of confidence that no more profiling
|
||||
* is required for this query point.
|
||||
* </p>
|
||||
*/
|
||||
public void setProfilingBase(int profilingMax);
|
||||
|
||||
/**
|
||||
* Return the minimum number of queries profiled before autoFetch will start
|
||||
* automatically tuning the queries.
|
||||
* <p>
|
||||
* This could be one which means start autoFetch tuning after the first
|
||||
* profiling information is collected.
|
||||
* </p>
|
||||
*/
|
||||
public int getProfilingMin();
|
||||
|
||||
/**
|
||||
* Set the minimum number of queries profiled per query point before
|
||||
* autoFetch will automatically tune the queries.
|
||||
* <p>
|
||||
* Increasing this number will mean more profiling is collected before
|
||||
* autoFetch starts tuning the query.
|
||||
* </p>
|
||||
*/
|
||||
public void setProfilingMin(int autoFetchMinThreshold);
|
||||
|
||||
/**
|
||||
* Fire a garbage collection (hint to the JVM). Assuming garbage collection
|
||||
* fires this will gather the usage profiling information.
|
||||
*/
|
||||
public String collectUsageViaGC(long waitMillis);
|
||||
|
||||
/**
|
||||
* This will take the current profiling information and update the "tuned
|
||||
* query detail".
|
||||
* <p>
|
||||
* This is done periodically and can also be manually invoked.
|
||||
* </p>
|
||||
* <p>
|
||||
* This returns a string summary of the updates that occurred.
|
||||
* </p>
|
||||
*/
|
||||
public String updateTunedQueryInfo();
|
||||
|
||||
/**
|
||||
* Called when a query thinks it should be automatically tuned by autoFetch.
|
||||
* <p>
|
||||
* This internally checks that autoFetch is enabled, there is a "tuned query
|
||||
* detail" to tune the query with and that the autoFetchMinThreshold has
|
||||
* been reached.
|
||||
* </p>
|
||||
* <p>
|
||||
* This will also determine if the query should be profiled.
|
||||
* </p>
|
||||
*/
|
||||
public boolean tuneQuery(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* Collect query profiling information.
|
||||
* <p>
|
||||
* This is for the original query as well as any subsequent lazy loading
|
||||
* queries that are required as the object graph is traversed.
|
||||
* </p>
|
||||
*
|
||||
* @param node
|
||||
* the node path in the object graph.
|
||||
* @param beans
|
||||
* the number of beans loaded by the query.
|
||||
* @param micros
|
||||
* the query executing time in microseconds
|
||||
*/
|
||||
public void collectQueryInfo(ObjectGraphNode node, int beans, int micros);
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of queries tuned by AutoFetch.
|
||||
*/
|
||||
public int getTotalTunedQueryCount();
|
||||
|
||||
/**
|
||||
* Return the size of the TuneQuery map.
|
||||
*/
|
||||
public int getTotalTunedQuerySize();
|
||||
|
||||
/**
|
||||
* Return the size of the profile map.
|
||||
*/
|
||||
public int getTotalProfileSize();
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.autofetch;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.bean.NodeUsageListener;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.config.AutofetchMode;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
|
||||
/**
|
||||
* Collects and manages the the profile information.
|
||||
* <p>
|
||||
* The profile information is periodically converted into "tuned query details" -
|
||||
* which is used to automatically tune the queries that use autoFetch.
|
||||
* </p>
|
||||
* <p>
|
||||
* The "tuned query details" effectively are part of the query that has the
|
||||
* select() and join() information (but not the where clause, order by, limits
|
||||
* etc). These are applied to the query when tuneQuery() is called.
|
||||
* </p>
|
||||
*/
|
||||
public interface AutoFetchManager extends NodeUsageListener {
|
||||
|
||||
/**
|
||||
* Set the owning ebean server.
|
||||
*/
|
||||
public void setOwner(SpiEbeanServer server, ServerConfig serverConfig);
|
||||
|
||||
/**
|
||||
* Clear the query execution statistics.
|
||||
*/
|
||||
public void clearQueryStatistics();
|
||||
|
||||
/**
|
||||
* Clear all the tuned query info.
|
||||
* <p>
|
||||
* Should only need do this for testing and playing around.
|
||||
* </p>
|
||||
*/
|
||||
public int clearTunedQueryInfo();
|
||||
|
||||
/**
|
||||
* Clear all the profiling information.
|
||||
* <p>
|
||||
* This means the profiling information will need to be re-gathered.
|
||||
* </p>
|
||||
* <p>
|
||||
* Should only need do this for testing and playing around.
|
||||
* </p>
|
||||
*/
|
||||
public int clearProfilingInfo();
|
||||
|
||||
/**
|
||||
* On shutdown fire garbage collection and collect statistics. Note that
|
||||
* usually we add a little delay (100 milliseconds) to give the garbage
|
||||
* collector plenty of time to do its thing and collect the profile
|
||||
* information.
|
||||
*/
|
||||
public void shutdown();
|
||||
|
||||
/**
|
||||
* Return the current tuned fetch information for a given queryPoint key.
|
||||
*/
|
||||
public TunedQueryInfo getTunedQueryInfo(String queryPointKey);
|
||||
|
||||
/**
|
||||
* Return the current Statistics for a given queryPoint key.
|
||||
*/
|
||||
public Statistics getStatistics(String queryPointKey);
|
||||
|
||||
/**
|
||||
* Iterate the tuned fetch info.
|
||||
* <p>
|
||||
* This should be a read only iteration.
|
||||
* </p>
|
||||
*/
|
||||
public Iterator<TunedQueryInfo> iterateTunedQueryInfo();
|
||||
|
||||
/**
|
||||
* Iterate the node usage statistics.
|
||||
* <p>
|
||||
* This should be a read only iteration.
|
||||
* </p>
|
||||
*/
|
||||
public Iterator<Statistics> iterateStatistics();
|
||||
|
||||
/**
|
||||
* Return true if profiling is enabled.
|
||||
*/
|
||||
public boolean isProfiling();
|
||||
|
||||
/**
|
||||
* Set to true to enable profiling.
|
||||
* <p>
|
||||
* We rely on garbage collection to collect the profiling information. This
|
||||
* means there is a unknown delay between when a query is executed and when
|
||||
* we actually collect the usage profile information.
|
||||
* </p>
|
||||
* <p>
|
||||
* Due to this garbage collection delay, when turning off profiling while
|
||||
* the application is running you should consider calling
|
||||
* collectUsageViaGC() <em>BEFORE</em> setProfiling(false). This hints to
|
||||
* the JVM to perform garbage collection, and hopefully collects the
|
||||
* profiling information.
|
||||
* </p>
|
||||
*/
|
||||
public void setProfiling(boolean enable);
|
||||
|
||||
/**
|
||||
* Return true if automatic query tuning is enabled.
|
||||
*/
|
||||
public boolean isQueryTuning();
|
||||
|
||||
/**
|
||||
* Set to true to enable automatic query tuning.
|
||||
*/
|
||||
public void setQueryTuning(boolean enable);
|
||||
|
||||
/**
|
||||
* This controls whether autoFetch is used when it has not been explicitly
|
||||
* set on a query via {@link Query#setAutoFetch(boolean)}.
|
||||
*/
|
||||
public AutofetchMode getMode();
|
||||
|
||||
/**
|
||||
* Set the auto fetch mode used when a query has not had
|
||||
* {@link Query#setAutoFetch(boolean)}.
|
||||
*/
|
||||
public void setMode(AutofetchMode Mode);
|
||||
|
||||
/**
|
||||
* Return the profiling rate (int between 0 and 100).
|
||||
*/
|
||||
public double getProfilingRate();
|
||||
|
||||
/**
|
||||
* Set the profiling rate (int between 0 and 100).
|
||||
*/
|
||||
public void setProfilingRate(double rate);
|
||||
|
||||
/**
|
||||
* Return the max number of queries profiled (per query point).
|
||||
* <p>
|
||||
* The number of queries profiled is collected per query point. Once a query
|
||||
* point has profiled this number of queries it does not profile any more.
|
||||
* </p>
|
||||
*/
|
||||
public int getProfilingBase();
|
||||
|
||||
/**
|
||||
* Set a max number of queries to profile per query point.
|
||||
* <p>
|
||||
* This number should provide a level of confidence that no more profiling
|
||||
* is required for this query point.
|
||||
* </p>
|
||||
*/
|
||||
public void setProfilingBase(int profilingMax);
|
||||
|
||||
/**
|
||||
* Return the minimum number of queries profiled before autoFetch will start
|
||||
* automatically tuning the queries.
|
||||
* <p>
|
||||
* This could be one which means start autoFetch tuning after the first
|
||||
* profiling information is collected.
|
||||
* </p>
|
||||
*/
|
||||
public int getProfilingMin();
|
||||
|
||||
/**
|
||||
* Set the minimum number of queries profiled per query point before
|
||||
* autoFetch will automatically tune the queries.
|
||||
* <p>
|
||||
* Increasing this number will mean more profiling is collected before
|
||||
* autoFetch starts tuning the query.
|
||||
* </p>
|
||||
*/
|
||||
public void setProfilingMin(int autoFetchMinThreshold);
|
||||
|
||||
/**
|
||||
* Fire a garbage collection (hint to the JVM). Assuming garbage collection
|
||||
* fires this will gather the usage profiling information.
|
||||
*/
|
||||
public String collectUsageViaGC(long waitMillis);
|
||||
|
||||
/**
|
||||
* This will take the current profiling information and update the "tuned
|
||||
* query detail".
|
||||
* <p>
|
||||
* This is done periodically and can also be manually invoked.
|
||||
* </p>
|
||||
* <p>
|
||||
* This returns a string summary of the updates that occurred.
|
||||
* </p>
|
||||
*/
|
||||
public String updateTunedQueryInfo();
|
||||
|
||||
/**
|
||||
* Called when a query thinks it should be automatically tuned by autoFetch.
|
||||
* <p>
|
||||
* This internally checks that autoFetch is enabled, there is a "tuned query
|
||||
* detail" to tune the query with and that the autoFetchMinThreshold has
|
||||
* been reached.
|
||||
* </p>
|
||||
* <p>
|
||||
* This will also determine if the query should be profiled.
|
||||
* </p>
|
||||
*/
|
||||
public boolean tuneQuery(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* Collect query profiling information.
|
||||
* <p>
|
||||
* This is for the original query as well as any subsequent lazy loading
|
||||
* queries that are required as the object graph is traversed.
|
||||
* </p>
|
||||
*
|
||||
* @param node
|
||||
* the node path in the object graph.
|
||||
* @param beans
|
||||
* the number of beans loaded by the query.
|
||||
* @param micros
|
||||
* the query executing time in microseconds
|
||||
*/
|
||||
public void collectQueryInfo(ObjectGraphNode node, int beans, int micros);
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of queries tuned by AutoFetch.
|
||||
*/
|
||||
public int getTotalTunedQueryCount();
|
||||
|
||||
/**
|
||||
* Return the size of the TuneQuery map.
|
||||
*/
|
||||
public int getTotalTunedQuerySize();
|
||||
|
||||
/**
|
||||
* Return the size of the profile map.
|
||||
*/
|
||||
public int getTotalProfileSize();
|
||||
}
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
/**
|
||||
* Default L2 server cache implementation.
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cache;
|
||||
@@ -1,83 +1,64 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
/**
|
||||
* Represents a relatively small independent message.
|
||||
* <p>
|
||||
* In general terms we break up a potentially large object like
|
||||
* RemoteTransactionEvent into many smaller BinaryMessages. This is so that if
|
||||
* they don't all fit on a single Packet we can easily break them up and put
|
||||
* them on multiple packets.
|
||||
* </p>
|
||||
* <p>
|
||||
* Also note that for the Multicast approach a Packet will generally contain
|
||||
* many messages each directed to different members of the cluster. So it would
|
||||
* be common for many Ack, Resend and Control messages to all be contained in a
|
||||
* single packet.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class BinaryMessage {
|
||||
|
||||
public static final int TYPE_MSGCONTROL = 0;
|
||||
public static final int TYPE_BEANIUD = 1;
|
||||
public static final int TYPE_TABLEIUD = 2;
|
||||
public static final int TYPE_BEANDELTA = 3;
|
||||
public static final int TYPE_BEANPATHUPDATE = 4;
|
||||
public static final int TYPE_INDEX_INVALIDATE = 6;
|
||||
public static final int TYPE_INDEX = 7;
|
||||
public static final int TYPE_MSGACK = 8;
|
||||
public static final int TYPE_MSGRESEND = 9;
|
||||
|
||||
private final ByteArrayOutputStream buffer;
|
||||
private final DataOutputStream os;
|
||||
private byte[] bytes;
|
||||
|
||||
/**
|
||||
* Create with an estimated buffer size.
|
||||
*/
|
||||
public BinaryMessage(int bufSize) {
|
||||
this.buffer = new ByteArrayOutputStream(bufSize);
|
||||
this.os = new DataOutputStream(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataOutputStream to write content to.
|
||||
*/
|
||||
public DataOutputStream getOs() {
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the content as a byte array.
|
||||
*/
|
||||
public byte[] getByteArray() {
|
||||
if (bytes == null) {
|
||||
bytes = buffer.toByteArray();
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
/**
|
||||
* Represents a relatively small independent message.
|
||||
* <p>
|
||||
* In general terms we break up a potentially large object like
|
||||
* RemoteTransactionEvent into many smaller BinaryMessages. This is so that if
|
||||
* they don't all fit on a single Packet we can easily break them up and put
|
||||
* them on multiple packets.
|
||||
* </p>
|
||||
* <p>
|
||||
* Also note that for the Multicast approach a Packet will generally contain
|
||||
* many messages each directed to different members of the cluster. So it would
|
||||
* be common for many Ack, Resend and Control messages to all be contained in a
|
||||
* single packet.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class BinaryMessage {
|
||||
|
||||
public static final int TYPE_MSGCONTROL = 0;
|
||||
public static final int TYPE_BEANIUD = 1;
|
||||
public static final int TYPE_TABLEIUD = 2;
|
||||
public static final int TYPE_BEANDELTA = 3;
|
||||
public static final int TYPE_BEANPATHUPDATE = 4;
|
||||
public static final int TYPE_INDEX_INVALIDATE = 6;
|
||||
public static final int TYPE_INDEX = 7;
|
||||
public static final int TYPE_MSGACK = 8;
|
||||
public static final int TYPE_MSGRESEND = 9;
|
||||
|
||||
private final ByteArrayOutputStream buffer;
|
||||
private final DataOutputStream os;
|
||||
private byte[] bytes;
|
||||
|
||||
/**
|
||||
* Create with an estimated buffer size.
|
||||
*/
|
||||
public BinaryMessage(int bufSize) {
|
||||
this.buffer = new ByteArrayOutputStream(bufSize);
|
||||
this.os = new DataOutputStream(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataOutputStream to write content to.
|
||||
*/
|
||||
public DataOutputStream getOs() {
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the content as a byte array.
|
||||
*/
|
||||
public byte[] getByteArray() {
|
||||
if (bytes == null) {
|
||||
bytes = buffer.toByteArray();
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,23 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds a List of BinaryMessage's.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class BinaryMessageList {
|
||||
|
||||
ArrayList<BinaryMessage> list = new ArrayList<BinaryMessage>();
|
||||
|
||||
public void add(BinaryMessage msg) {
|
||||
list.add(msg);
|
||||
}
|
||||
|
||||
public List<BinaryMessage> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds a List of BinaryMessage's.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class BinaryMessageList {
|
||||
|
||||
ArrayList<BinaryMessage> list = new ArrayList<BinaryMessage>();
|
||||
|
||||
public void add(BinaryMessage msg) {
|
||||
list.add(msg);
|
||||
}
|
||||
|
||||
public List<BinaryMessage> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,45 +1,28 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Sends messages to the cluster members.
|
||||
*/
|
||||
public interface ClusterBroadcast {
|
||||
|
||||
/**
|
||||
* Inform the other cluster members that this instance has come online and
|
||||
* start any listeners etc.
|
||||
*/
|
||||
public void startup(ClusterManager clusterManager);
|
||||
|
||||
/**
|
||||
* Inform the other cluster members that this instance is leaving and
|
||||
* shutdown any listeners.
|
||||
*/
|
||||
public void shutdown();
|
||||
|
||||
/**
|
||||
* Send a transaction event to all the members of the cluster.
|
||||
*/
|
||||
public void broadcast(RemoteTransactionEvent remoteTransEvent);
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Sends messages to the cluster members.
|
||||
*/
|
||||
public interface ClusterBroadcast {
|
||||
|
||||
/**
|
||||
* Inform the other cluster members that this instance has come online and
|
||||
* start any listeners etc.
|
||||
*/
|
||||
public void startup(ClusterManager clusterManager);
|
||||
|
||||
/**
|
||||
* Inform the other cluster members that this instance is leaving and
|
||||
* shutdown any listeners.
|
||||
*/
|
||||
public void shutdown();
|
||||
|
||||
/**
|
||||
* Send a transaction event to all the members of the cluster.
|
||||
*/
|
||||
public void broadcast(RemoteTransactionEvent remoteTransEvent);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,122 +1,105 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.McastClusterManager;
|
||||
import com.avaje.ebeaninternal.server.cluster.socket.SocketClusterBroadcast;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
/**
|
||||
* Manages the cluster service.
|
||||
*/
|
||||
public class ClusterManager {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClusterManager.class.getName());
|
||||
|
||||
private final ConcurrentHashMap<String, EbeanServer> serverMap = new ConcurrentHashMap<String, EbeanServer>();
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final ClusterBroadcast broadcast;
|
||||
|
||||
private boolean started;
|
||||
|
||||
public ClusterManager() {
|
||||
|
||||
String clusterType = GlobalProperties.get("ebean.cluster.type", null);
|
||||
if (clusterType == null || clusterType.trim().length() == 0) {
|
||||
// not clustering this instance
|
||||
this.broadcast = null;
|
||||
|
||||
} else {
|
||||
|
||||
try {
|
||||
if ("mcast".equalsIgnoreCase(clusterType)) {
|
||||
this.broadcast = new McastClusterManager();
|
||||
|
||||
} else if ("socket".equalsIgnoreCase(clusterType)) {
|
||||
this.broadcast = new SocketClusterBroadcast();
|
||||
|
||||
} else {
|
||||
logger.info("Clustering using [" + clusterType + "]");
|
||||
this.broadcast = (ClusterBroadcast) ClassUtil.newInstance(clusterType);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error initialising ClusterManager type [" + clusterType + "]";
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerServer(EbeanServer server) {
|
||||
synchronized (monitor) {
|
||||
if (!started) {
|
||||
startup();
|
||||
}
|
||||
serverMap.put(server.getName(), server);
|
||||
}
|
||||
}
|
||||
|
||||
public EbeanServer getServer(String name) {
|
||||
synchronized (monitor) {
|
||||
return serverMap.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
private void startup() {
|
||||
started = true;
|
||||
if (broadcast != null) {
|
||||
broadcast.startup(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if clustering is on.
|
||||
*/
|
||||
public boolean isClustering() {
|
||||
return broadcast != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message headers and payload to every server in the cluster.
|
||||
*/
|
||||
public void broadcast(RemoteTransactionEvent remoteTransEvent) {
|
||||
if (broadcast != null) {
|
||||
broadcast.broadcast(remoteTransEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the service and Deregister from the cluster.
|
||||
*/
|
||||
public void shutdown() {
|
||||
if (broadcast != null) {
|
||||
logger.info("ClusterManager shutdown ");
|
||||
broadcast.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.McastClusterManager;
|
||||
import com.avaje.ebeaninternal.server.cluster.socket.SocketClusterBroadcast;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
/**
|
||||
* Manages the cluster service.
|
||||
*/
|
||||
public class ClusterManager {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClusterManager.class.getName());
|
||||
|
||||
private final ConcurrentHashMap<String, EbeanServer> serverMap = new ConcurrentHashMap<String, EbeanServer>();
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final ClusterBroadcast broadcast;
|
||||
|
||||
private boolean started;
|
||||
|
||||
public ClusterManager() {
|
||||
|
||||
String clusterType = GlobalProperties.get("ebean.cluster.type", null);
|
||||
if (clusterType == null || clusterType.trim().length() == 0) {
|
||||
// not clustering this instance
|
||||
this.broadcast = null;
|
||||
|
||||
} else {
|
||||
|
||||
try {
|
||||
if ("mcast".equalsIgnoreCase(clusterType)) {
|
||||
this.broadcast = new McastClusterManager();
|
||||
|
||||
} else if ("socket".equalsIgnoreCase(clusterType)) {
|
||||
this.broadcast = new SocketClusterBroadcast();
|
||||
|
||||
} else {
|
||||
logger.info("Clustering using [" + clusterType + "]");
|
||||
this.broadcast = (ClusterBroadcast) ClassUtil.newInstance(clusterType);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error initialising ClusterManager type [" + clusterType + "]";
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerServer(EbeanServer server) {
|
||||
synchronized (monitor) {
|
||||
if (!started) {
|
||||
startup();
|
||||
}
|
||||
serverMap.put(server.getName(), server);
|
||||
}
|
||||
}
|
||||
|
||||
public EbeanServer getServer(String name) {
|
||||
synchronized (monitor) {
|
||||
return serverMap.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
private void startup() {
|
||||
started = true;
|
||||
if (broadcast != null) {
|
||||
broadcast.startup(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if clustering is on.
|
||||
*/
|
||||
public boolean isClustering() {
|
||||
return broadcast != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message headers and payload to every server in the cluster.
|
||||
*/
|
||||
public void broadcast(RemoteTransactionEvent remoteTransEvent) {
|
||||
if (broadcast != null) {
|
||||
broadcast.broadcast(remoteTransEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the service and Deregister from the cluster.
|
||||
*/
|
||||
public void shutdown() {
|
||||
if (broadcast != null) {
|
||||
logger.info("ClusterManager shutdown ");
|
||||
broadcast.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,24 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Simple holder of binary data.
|
||||
* Used to use Packet based serialisation of RemoteTransactionEvent
|
||||
* with simple Java Serialisation of the DataHolder.
|
||||
*/
|
||||
public class DataHolder implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 9090748723571322192L;
|
||||
|
||||
private final byte[] data;
|
||||
|
||||
public DataHolder(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Simple holder of binary data.
|
||||
* Used to use Packet based serialisation of RemoteTransactionEvent
|
||||
* with simple Java Serialisation of the DataHolder.
|
||||
*/
|
||||
public class DataHolder implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 9090748723571322192L;
|
||||
|
||||
private final byte[] data;
|
||||
|
||||
public DataHolder(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,212 +1,193 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Represents the contents sent as a single DatagramPacket.
|
||||
* <p>
|
||||
* The contents is typically multiple messages (ACK,PING etc) or all or part of
|
||||
* a RemoteTransactionEvent.
|
||||
* </p>
|
||||
* <p>
|
||||
* Due to the hard limit on the size of UDP packets a RemoteTransactionEvent
|
||||
* with lots of information could be broken up into multiple packets.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class Packet {
|
||||
|
||||
/**
|
||||
* A Packet that holds protocol messages like ACK, PING etc.
|
||||
*/
|
||||
public static final short TYPE_MESSAGES = 1;
|
||||
|
||||
/**
|
||||
* A Packet that holds TransactionEvent information such as Bean
|
||||
* and or Table IUD information.
|
||||
*/
|
||||
public static final short TYPE_TRANSEVENT = 2;
|
||||
|
||||
/**
|
||||
* The type of Packet.
|
||||
*/
|
||||
protected short packetType;
|
||||
|
||||
/**
|
||||
* The PacketId.
|
||||
*/
|
||||
protected long packetId;
|
||||
|
||||
/**
|
||||
* The timestamp the Packet was created.
|
||||
*/
|
||||
protected long timestamp;
|
||||
|
||||
/**
|
||||
* The EbeanServer name this relates to if relevant.
|
||||
*/
|
||||
protected String serverName;
|
||||
|
||||
protected ByteArrayOutputStream buffer;
|
||||
protected DataOutputStream dataOut;
|
||||
protected byte[] bytes;
|
||||
|
||||
/**
|
||||
* The number of messages in this Packet.
|
||||
*/
|
||||
private int messageCount;
|
||||
|
||||
/**
|
||||
* The number of times this Packet was resent.
|
||||
*/
|
||||
private int resendCount;
|
||||
|
||||
/**
|
||||
* Create a Packet for writing messages to.
|
||||
*/
|
||||
public static Packet forWrite(short packetType, long packetId, long timestamp, String serverName) throws IOException {
|
||||
return new Packet(true, packetType, packetId, timestamp, serverName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Packet just reading the Header information.
|
||||
*/
|
||||
public static Packet readHeader(DataInput dataInput) throws IOException {
|
||||
|
||||
short packetType = dataInput.readShort();
|
||||
long packetId = dataInput.readLong();
|
||||
long timestamp = dataInput.readLong();
|
||||
String serverName = dataInput.readUTF();
|
||||
|
||||
return new Packet(false, packetType, packetId, timestamp, serverName);
|
||||
}
|
||||
|
||||
protected Packet(boolean write, short packetType, long packetId, long timestamp, String serverName) throws IOException{
|
||||
this.packetType = packetType;
|
||||
this.packetId = packetId;
|
||||
this.timestamp = timestamp;
|
||||
this.serverName = serverName;
|
||||
if (write){
|
||||
this.buffer = new ByteArrayOutputStream();
|
||||
this.dataOut = new DataOutputStream(buffer);
|
||||
writeHeader();
|
||||
} else {
|
||||
this.buffer = null;
|
||||
this.dataOut = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeHeader() throws IOException {
|
||||
dataOut.writeShort(packetType);
|
||||
dataOut.writeLong(packetId);
|
||||
dataOut.writeLong(timestamp);
|
||||
dataOut.writeUTF(serverName);
|
||||
}
|
||||
|
||||
public int incrementResendCount() {
|
||||
return resendCount++;
|
||||
}
|
||||
|
||||
public short getPacketType() {
|
||||
return packetType;
|
||||
}
|
||||
|
||||
public long getPacketId() {
|
||||
return packetId;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
public void writeEof() throws IOException {
|
||||
dataOut.writeBoolean(false);
|
||||
}
|
||||
|
||||
public void read(DataInput dataInput) throws IOException {
|
||||
boolean more = dataInput.readBoolean();
|
||||
while (more){
|
||||
int msgType = dataInput.readInt();
|
||||
readMessage(dataInput, msgType);
|
||||
// see if there is more information
|
||||
more = dataInput.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden by more specific Packet implementations to read the messages.
|
||||
*/
|
||||
protected void readMessage(DataInput dataInput, int msgType) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a binary message to this packet returning true if there was
|
||||
* enough room to do so. Return false if the message was too large for
|
||||
* the remaining space left - in this case another Packet should be
|
||||
* created to put that message into.
|
||||
*/
|
||||
public boolean writeBinaryMessage(BinaryMessage msg, int maxPacketSize) throws IOException {
|
||||
|
||||
byte[] bytes = msg.getByteArray();
|
||||
|
||||
if (messageCount > 0 && (bytes.length + buffer.size() > maxPacketSize)){
|
||||
// we are actually going to ignore the maxPacketSize iff we have one
|
||||
// large message.
|
||||
|
||||
// false = no more messages
|
||||
dataOut.writeBoolean(false);
|
||||
return false;
|
||||
}
|
||||
++messageCount;
|
||||
// true = another message follows
|
||||
dataOut.writeBoolean(true);
|
||||
dataOut.write(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return getBytes().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Packet as raw bytes.
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
if (bytes == null){
|
||||
bytes = buffer.toByteArray();
|
||||
buffer = null;
|
||||
dataOut = null;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Represents the contents sent as a single DatagramPacket.
|
||||
* <p>
|
||||
* The contents is typically multiple messages (ACK,PING etc) or all or part of
|
||||
* a RemoteTransactionEvent.
|
||||
* </p>
|
||||
* <p>
|
||||
* Due to the hard limit on the size of UDP packets a RemoteTransactionEvent
|
||||
* with lots of information could be broken up into multiple packets.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class Packet {
|
||||
|
||||
/**
|
||||
* A Packet that holds protocol messages like ACK, PING etc.
|
||||
*/
|
||||
public static final short TYPE_MESSAGES = 1;
|
||||
|
||||
/**
|
||||
* A Packet that holds TransactionEvent information such as Bean
|
||||
* and or Table IUD information.
|
||||
*/
|
||||
public static final short TYPE_TRANSEVENT = 2;
|
||||
|
||||
/**
|
||||
* The type of Packet.
|
||||
*/
|
||||
protected short packetType;
|
||||
|
||||
/**
|
||||
* The PacketId.
|
||||
*/
|
||||
protected long packetId;
|
||||
|
||||
/**
|
||||
* The timestamp the Packet was created.
|
||||
*/
|
||||
protected long timestamp;
|
||||
|
||||
/**
|
||||
* The EbeanServer name this relates to if relevant.
|
||||
*/
|
||||
protected String serverName;
|
||||
|
||||
protected ByteArrayOutputStream buffer;
|
||||
protected DataOutputStream dataOut;
|
||||
protected byte[] bytes;
|
||||
|
||||
/**
|
||||
* The number of messages in this Packet.
|
||||
*/
|
||||
private int messageCount;
|
||||
|
||||
/**
|
||||
* The number of times this Packet was resent.
|
||||
*/
|
||||
private int resendCount;
|
||||
|
||||
/**
|
||||
* Create a Packet for writing messages to.
|
||||
*/
|
||||
public static Packet forWrite(short packetType, long packetId, long timestamp, String serverName) throws IOException {
|
||||
return new Packet(true, packetType, packetId, timestamp, serverName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Packet just reading the Header information.
|
||||
*/
|
||||
public static Packet readHeader(DataInput dataInput) throws IOException {
|
||||
|
||||
short packetType = dataInput.readShort();
|
||||
long packetId = dataInput.readLong();
|
||||
long timestamp = dataInput.readLong();
|
||||
String serverName = dataInput.readUTF();
|
||||
|
||||
return new Packet(false, packetType, packetId, timestamp, serverName);
|
||||
}
|
||||
|
||||
protected Packet(boolean write, short packetType, long packetId, long timestamp, String serverName) throws IOException{
|
||||
this.packetType = packetType;
|
||||
this.packetId = packetId;
|
||||
this.timestamp = timestamp;
|
||||
this.serverName = serverName;
|
||||
if (write){
|
||||
this.buffer = new ByteArrayOutputStream();
|
||||
this.dataOut = new DataOutputStream(buffer);
|
||||
writeHeader();
|
||||
} else {
|
||||
this.buffer = null;
|
||||
this.dataOut = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeHeader() throws IOException {
|
||||
dataOut.writeShort(packetType);
|
||||
dataOut.writeLong(packetId);
|
||||
dataOut.writeLong(timestamp);
|
||||
dataOut.writeUTF(serverName);
|
||||
}
|
||||
|
||||
public int incrementResendCount() {
|
||||
return resendCount++;
|
||||
}
|
||||
|
||||
public short getPacketType() {
|
||||
return packetType;
|
||||
}
|
||||
|
||||
public long getPacketId() {
|
||||
return packetId;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
public void writeEof() throws IOException {
|
||||
dataOut.writeBoolean(false);
|
||||
}
|
||||
|
||||
public void read(DataInput dataInput) throws IOException {
|
||||
boolean more = dataInput.readBoolean();
|
||||
while (more){
|
||||
int msgType = dataInput.readInt();
|
||||
readMessage(dataInput, msgType);
|
||||
// see if there is more information
|
||||
more = dataInput.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden by more specific Packet implementations to read the messages.
|
||||
*/
|
||||
protected void readMessage(DataInput dataInput, int msgType) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a binary message to this packet returning true if there was
|
||||
* enough room to do so. Return false if the message was too large for
|
||||
* the remaining space left - in this case another Packet should be
|
||||
* created to put that message into.
|
||||
*/
|
||||
public boolean writeBinaryMessage(BinaryMessage msg, int maxPacketSize) throws IOException {
|
||||
|
||||
byte[] bytes = msg.getByteArray();
|
||||
|
||||
if (messageCount > 0 && (bytes.length + buffer.size() > maxPacketSize)){
|
||||
// we are actually going to ignore the maxPacketSize iff we have one
|
||||
// large message.
|
||||
|
||||
// false = no more messages
|
||||
dataOut.writeBoolean(false);
|
||||
return false;
|
||||
}
|
||||
++messageCount;
|
||||
// true = another message follows
|
||||
dataOut.writeBoolean(true);
|
||||
dataOut.write(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return getBytes().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Packet as raw bytes.
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
if (bytes == null){
|
||||
bytes = buffer.toByteArray();
|
||||
buffer = null;
|
||||
dataOut = null;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,88 +1,69 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.Message;
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.MessageAck;
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.MessageControl;
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.MessageResend;
|
||||
|
||||
/**
|
||||
* A Packet that contains Ack, Resend and Control messages.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class PacketMessages extends Packet {
|
||||
|
||||
private final ArrayList<Message> messages;
|
||||
|
||||
public static PacketMessages forWrite(long packetId, long timestamp, String serverName) throws IOException {
|
||||
return new PacketMessages(true, packetId, timestamp, serverName);
|
||||
}
|
||||
|
||||
public static PacketMessages forRead(Packet header) throws IOException {
|
||||
return new PacketMessages(header);
|
||||
}
|
||||
|
||||
private PacketMessages(boolean write, long packetId, long timestamp, String serverName) throws IOException {
|
||||
super(write, TYPE_MESSAGES, packetId, timestamp, serverName);
|
||||
this.messages = null;
|
||||
}
|
||||
|
||||
private PacketMessages(Packet header) throws IOException {
|
||||
super(false, TYPE_MESSAGES, header.packetId, header.timestamp, header.serverName);
|
||||
this.messages = new ArrayList<Message>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the messages contained in this Packet.
|
||||
*/
|
||||
public List<Message> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the messages (Ack, Resend or Control) contained in this packet.
|
||||
*/
|
||||
protected void readMessage(DataInput dataInput, int msgType) throws IOException {
|
||||
|
||||
switch (msgType) {
|
||||
case BinaryMessage.TYPE_MSGCONTROL:
|
||||
messages.add(MessageControl.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_MSGACK:
|
||||
messages.add(MessageAck.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_MSGRESEND:
|
||||
messages.add(MessageResend.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid Transaction msgType "+msgType);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.Message;
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.MessageAck;
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.MessageControl;
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.MessageResend;
|
||||
|
||||
/**
|
||||
* A Packet that contains Ack, Resend and Control messages.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class PacketMessages extends Packet {
|
||||
|
||||
private final ArrayList<Message> messages;
|
||||
|
||||
public static PacketMessages forWrite(long packetId, long timestamp, String serverName) throws IOException {
|
||||
return new PacketMessages(true, packetId, timestamp, serverName);
|
||||
}
|
||||
|
||||
public static PacketMessages forRead(Packet header) throws IOException {
|
||||
return new PacketMessages(header);
|
||||
}
|
||||
|
||||
private PacketMessages(boolean write, long packetId, long timestamp, String serverName) throws IOException {
|
||||
super(write, TYPE_MESSAGES, packetId, timestamp, serverName);
|
||||
this.messages = null;
|
||||
}
|
||||
|
||||
private PacketMessages(Packet header) throws IOException {
|
||||
super(false, TYPE_MESSAGES, header.packetId, header.timestamp, header.serverName);
|
||||
this.messages = new ArrayList<Message>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the messages contained in this Packet.
|
||||
*/
|
||||
public List<Message> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the messages (Ack, Resend or Control) contained in this packet.
|
||||
*/
|
||||
protected void readMessage(DataInput dataInput, int msgType) throws IOException {
|
||||
|
||||
switch (msgType) {
|
||||
case BinaryMessage.TYPE_MSGCONTROL:
|
||||
messages.add(MessageControl.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_MSGACK:
|
||||
messages.add(MessageAck.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_MSGRESEND:
|
||||
messages.add(MessageResend.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid Transaction msgType "+msgType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,94 +1,75 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanDelta;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanPersistIds;
|
||||
import com.avaje.ebeaninternal.server.transaction.IndexEvent;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
/**
|
||||
* A Packet holding TransactionEvent data.
|
||||
* <p>
|
||||
* Due to the hard limit for UDP packet sizes a RemoteTransactionEvent
|
||||
* is actually broken up into smaller messages.
|
||||
* </p>
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class PacketTransactionEvent extends Packet {
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
|
||||
private final RemoteTransactionEvent event;
|
||||
|
||||
public static PacketTransactionEvent forWrite(long packetId, long timestamp, String serverName) throws IOException {
|
||||
return new PacketTransactionEvent(true, packetId, timestamp, serverName);
|
||||
}
|
||||
|
||||
private PacketTransactionEvent(boolean write, long packetId, long timestamp, String serverName) throws IOException {
|
||||
super(write, TYPE_TRANSEVENT, packetId, timestamp, serverName);
|
||||
this.server = null;
|
||||
this.event = null;
|
||||
}
|
||||
|
||||
private PacketTransactionEvent(Packet header, SpiEbeanServer server) throws IOException {
|
||||
super(false, TYPE_TRANSEVENT, header.packetId, header.timestamp, header.serverName);
|
||||
this.server = server;
|
||||
this.event = new RemoteTransactionEvent(server);
|
||||
}
|
||||
|
||||
public static PacketTransactionEvent forRead(Packet header, SpiEbeanServer server) throws IOException {
|
||||
return new PacketTransactionEvent(header, server);
|
||||
}
|
||||
|
||||
public RemoteTransactionEvent getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
protected void readMessage(DataInput dataInput, int msgType) throws IOException {
|
||||
|
||||
switch (msgType) {
|
||||
case BinaryMessage.TYPE_BEANIUD:
|
||||
event.addBeanPersistIds(BeanPersistIds.readBinaryMessage(server, dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_TABLEIUD:
|
||||
event.addTableIUD(TableIUD.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_BEANDELTA:
|
||||
event.addBeanDelta(BeanDelta.readBinaryMessage(server, dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_INDEX:
|
||||
event.addIndexEvent(IndexEvent.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid Transaction msgType "+msgType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanDelta;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanPersistIds;
|
||||
import com.avaje.ebeaninternal.server.transaction.IndexEvent;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
/**
|
||||
* A Packet holding TransactionEvent data.
|
||||
* <p>
|
||||
* Due to the hard limit for UDP packet sizes a RemoteTransactionEvent
|
||||
* is actually broken up into smaller messages.
|
||||
* </p>
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class PacketTransactionEvent extends Packet {
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
|
||||
private final RemoteTransactionEvent event;
|
||||
|
||||
public static PacketTransactionEvent forWrite(long packetId, long timestamp, String serverName) throws IOException {
|
||||
return new PacketTransactionEvent(true, packetId, timestamp, serverName);
|
||||
}
|
||||
|
||||
private PacketTransactionEvent(boolean write, long packetId, long timestamp, String serverName) throws IOException {
|
||||
super(write, TYPE_TRANSEVENT, packetId, timestamp, serverName);
|
||||
this.server = null;
|
||||
this.event = null;
|
||||
}
|
||||
|
||||
private PacketTransactionEvent(Packet header, SpiEbeanServer server) throws IOException {
|
||||
super(false, TYPE_TRANSEVENT, header.packetId, header.timestamp, header.serverName);
|
||||
this.server = server;
|
||||
this.event = new RemoteTransactionEvent(server);
|
||||
}
|
||||
|
||||
public static PacketTransactionEvent forRead(Packet header, SpiEbeanServer server) throws IOException {
|
||||
return new PacketTransactionEvent(header, server);
|
||||
}
|
||||
|
||||
public RemoteTransactionEvent getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
protected void readMessage(DataInput dataInput, int msgType) throws IOException {
|
||||
|
||||
switch (msgType) {
|
||||
case BinaryMessage.TYPE_BEANIUD:
|
||||
event.addBeanPersistIds(BeanPersistIds.readBinaryMessage(server, dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_TABLEIUD:
|
||||
event.addTableIUD(TableIUD.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_BEANDELTA:
|
||||
event.addBeanDelta(BeanDelta.readBinaryMessage(server, dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_INDEX:
|
||||
event.addIndexEvent(IndexEvent.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid Transaction msgType "+msgType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
@@ -1,62 +1,43 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds a list of ACK and RESEND messages that should be sent out.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class AckResendMessages {
|
||||
|
||||
ArrayList<Message> messages = new ArrayList<Message>();
|
||||
|
||||
public String toString() {
|
||||
return messages.toString();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return messages.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a ACK message to send.
|
||||
*/
|
||||
public void add(MessageAck ack){
|
||||
messages.add(ack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a RESEND message to send.
|
||||
*/
|
||||
public void add(MessageResend resend){
|
||||
messages.add(resend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the messages to be sent out.
|
||||
*/
|
||||
public List<Message> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds a list of ACK and RESEND messages that should be sent out.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class AckResendMessages {
|
||||
|
||||
ArrayList<Message> messages = new ArrayList<Message>();
|
||||
|
||||
public String toString() {
|
||||
return messages.toString();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return messages.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a ACK message to send.
|
||||
*/
|
||||
public void add(MessageAck ack){
|
||||
messages.add(ack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a RESEND message to send.
|
||||
*/
|
||||
public void add(MessageResend resend){
|
||||
messages.add(resend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the messages to be sent out.
|
||||
*/
|
||||
public List<Message> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
|
||||
+53
-72
@@ -1,72 +1,53 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* For this node this holds the ACK gotAllPoint for each member in the cluster.
|
||||
* <p>
|
||||
* As we receive messages from other members of the cluster periodically we need
|
||||
* to send them ACK messages to say we got all the packets up to the gotAllPoint.
|
||||
* </p>
|
||||
* Thread Safety note: Object only used by McastClusterBroadcast Manager thread.
|
||||
* So Single Threaded access.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class IncomingPacketsLastAck {
|
||||
|
||||
private HashMap<String,MessageAck> lastAckMap = new HashMap<String, MessageAck>();
|
||||
|
||||
public String toString() {
|
||||
return lastAckMap.values().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a member of the cluster who has left.
|
||||
*/
|
||||
public void remove(String memberHostPort) {
|
||||
lastAckMap.remove(memberHostPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last Ack point for a given member of the cluster.
|
||||
*/
|
||||
public MessageAck getLastAck(String memberHostPort) {
|
||||
return lastAckMap.get(memberHostPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the ACK messages in AckResendMessages update the
|
||||
* last Ack packetId.
|
||||
*/
|
||||
public void updateLastAck(AckResendMessages ackResendMessages) {
|
||||
List<Message> messages = ackResendMessages.getMessages();
|
||||
for (int i = 0; i < messages.size(); i++) {
|
||||
Message msg = messages.get(i);
|
||||
if (msg instanceof MessageAck){
|
||||
MessageAck lastAck = (MessageAck)msg;
|
||||
lastAckMap.put(lastAck.getToHostPort(), lastAck);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* For this node this holds the ACK gotAllPoint for each member in the cluster.
|
||||
* <p>
|
||||
* As we receive messages from other members of the cluster periodically we need
|
||||
* to send them ACK messages to say we got all the packets up to the gotAllPoint.
|
||||
* </p>
|
||||
* Thread Safety note: Object only used by McastClusterBroadcast Manager thread.
|
||||
* So Single Threaded access.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class IncomingPacketsLastAck {
|
||||
|
||||
private HashMap<String,MessageAck> lastAckMap = new HashMap<String, MessageAck>();
|
||||
|
||||
public String toString() {
|
||||
return lastAckMap.values().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a member of the cluster who has left.
|
||||
*/
|
||||
public void remove(String memberHostPort) {
|
||||
lastAckMap.remove(memberHostPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last Ack point for a given member of the cluster.
|
||||
*/
|
||||
public MessageAck getLastAck(String memberHostPort) {
|
||||
return lastAckMap.get(memberHostPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the ACK messages in AckResendMessages update the
|
||||
* last Ack packetId.
|
||||
*/
|
||||
public void updateLastAck(AckResendMessages ackResendMessages) {
|
||||
List<Message> messages = ackResendMessages.getMessages();
|
||||
for (int i = 0; i < messages.size(); i++) {
|
||||
Message msg = messages.get(i);
|
||||
if (msg instanceof MessageAck){
|
||||
MessageAck lastAck = (MessageAck)msg;
|
||||
lastAckMap.put(lastAck.getToHostPort(), lastAck);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+273
-292
@@ -1,292 +1,273 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* For Incoming Packets remembers the packets we have received and processed.
|
||||
* <p>
|
||||
* This determines the gotAllPoint per cluster member and identifies missing
|
||||
* packets (gap between gotAllPoint and gotMaxPoint).
|
||||
* </p>
|
||||
* <p>
|
||||
* This information is used by the managerThread so send ACK's for messages we
|
||||
* have received and RESEND messages to fill the missing packets we have
|
||||
* detected.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class IncomingPacketsProcessed {
|
||||
|
||||
private final ConcurrentHashMap<String, GotAllPoint> mapByMember = new ConcurrentHashMap<String, GotAllPoint>();
|
||||
|
||||
private final int maxResendIncoming;
|
||||
|
||||
public IncomingPacketsProcessed(int maxResendIncoming) {
|
||||
this.maxResendIncoming = maxResendIncoming;
|
||||
}
|
||||
|
||||
public void removeMember(String memberKey) {
|
||||
mapByMember.remove(memberKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should process this packet. Return false if we have
|
||||
* already processed the packet.
|
||||
*/
|
||||
public boolean isProcessPacket(String memberKey, long packetId) {
|
||||
|
||||
GotAllPoint memberPackets = getMemberPackets(memberKey);
|
||||
return memberPackets.processPacket(packetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the list of ACK and RESEND messages that we should send out
|
||||
* to the other members of the cluster.
|
||||
*/
|
||||
public AckResendMessages getAckResendMessages(IncomingPacketsLastAck lastAck) {
|
||||
|
||||
// Called by the McastClusterBroadcast manager thread
|
||||
|
||||
AckResendMessages response = new AckResendMessages();
|
||||
|
||||
for (GotAllPoint member : mapByMember.values()) {
|
||||
|
||||
MessageAck lastAckMessage = lastAck.getLastAck(member.getMemberKey());
|
||||
|
||||
member.addAckResendMessages(response, lastAckMessage);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private GotAllPoint getMemberPackets(String memberKey) {
|
||||
|
||||
// This method is only called single threaded
|
||||
// by the listener thread so I'm happy that this
|
||||
// put into mapByMember is ok.
|
||||
GotAllPoint memberGotAllPoint = mapByMember.get(memberKey);
|
||||
if (memberGotAllPoint == null) {
|
||||
memberGotAllPoint = new GotAllPoint(memberKey, maxResendIncoming);
|
||||
mapByMember.put(memberKey, memberGotAllPoint);
|
||||
}
|
||||
return memberGotAllPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps track of packets received from a particular member of the cluster.
|
||||
* <p>
|
||||
* It notes the packetIds of the packets received and uses those to maintain
|
||||
* the 'gotAllPoint'. The 'gotAllPoint' is the packetId which we know we
|
||||
* received all the previous packets.
|
||||
* </p>
|
||||
*/
|
||||
public static class GotAllPoint {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GotAllPoint.class.getName());
|
||||
|
||||
private final String memberKey;
|
||||
private final int maxResendIncoming;
|
||||
|
||||
private long gotAllPoint;
|
||||
|
||||
private long gotMaxPoint;
|
||||
|
||||
/**
|
||||
* Packets received out of order.
|
||||
*/
|
||||
private ArrayList<Long> outOfOrderList = new ArrayList<Long>();
|
||||
|
||||
private HashMap<Long,Integer> resendCountMap = new HashMap<Long,Integer>();
|
||||
|
||||
public GotAllPoint(String memberKey, int maxResendIncoming) {
|
||||
this.memberKey = memberKey;
|
||||
this.maxResendIncoming = maxResendIncoming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ACK and RESEND messages if required.
|
||||
*/
|
||||
public void addAckResendMessages(AckResendMessages response, MessageAck lastAckMessage) {
|
||||
|
||||
synchronized (this) {
|
||||
if (lastAckMessage != null && lastAckMessage.getGotAllPacketId() >= gotAllPoint) {
|
||||
// nothing has changed
|
||||
} else {
|
||||
// ACK that we have got every packet up to gotAllPoint
|
||||
response.add(new MessageAck(memberKey, gotAllPoint));
|
||||
}
|
||||
|
||||
if (getMissingPacketCount() > 0) {
|
||||
// Ask for these Packets to be RESENT
|
||||
List<Long> missingPackets = getMissingPackets();
|
||||
response.add(new MessageResend(memberKey, missingPackets));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getMemberKey() {
|
||||
return memberKey;
|
||||
}
|
||||
|
||||
public long getGotAllPoint() {
|
||||
synchronized (this) {
|
||||
return gotAllPoint;
|
||||
}
|
||||
}
|
||||
|
||||
public long getGotMaxPoint() {
|
||||
synchronized (this) {
|
||||
return gotMaxPoint;
|
||||
}
|
||||
}
|
||||
|
||||
private int getMissingPacketCount() {
|
||||
if (gotMaxPoint <= gotAllPoint) {
|
||||
if (!resendCountMap.isEmpty()) {
|
||||
resendCountMap.clear();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return (int) (gotMaxPoint - gotAllPoint) - outOfOrderList.size();
|
||||
}
|
||||
|
||||
public List<Long> getMissingPackets() {
|
||||
|
||||
synchronized (this) {
|
||||
ArrayList<Long> missingList = new ArrayList<Long>();
|
||||
|
||||
// this is not particularly efficient but expecting
|
||||
// the outOfOrderList to be relatively small
|
||||
|
||||
boolean lostPacket = false;
|
||||
|
||||
for (long i = gotAllPoint + 1; i < gotMaxPoint; i++) {
|
||||
Long packetId = Long.valueOf(i);
|
||||
if (!outOfOrderList.contains(packetId)) {
|
||||
if (incrementResendCount(packetId)) {
|
||||
// request this packet be resent
|
||||
missingList.add(packetId);
|
||||
} else {
|
||||
lostPacket = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lostPacket){
|
||||
checkOutOfOrderList();
|
||||
}
|
||||
|
||||
return missingList;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this packet has not yet exceeded the maxResendCount.
|
||||
*/
|
||||
private boolean incrementResendCount(Long packetId){
|
||||
Integer resendCount = resendCountMap.get(packetId);
|
||||
if (resendCount != null){
|
||||
int i = resendCount.intValue() + 1;
|
||||
if (i > maxResendIncoming){
|
||||
// we are going to give up trying to get this packet now
|
||||
logger.warning("Exceeded maxResendIncoming["+maxResendIncoming+"] for packet["+packetId+"]. Giving up on requesting it.");
|
||||
resendCountMap.remove(packetId);
|
||||
outOfOrderList.add(packetId);
|
||||
return false;
|
||||
}
|
||||
resendCount = Integer.valueOf(i);
|
||||
resendCountMap.put(packetId, resendCount);
|
||||
} else {
|
||||
resendCountMap.put(packetId, ONE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final Integer ONE = Integer.valueOf(1);
|
||||
|
||||
public boolean processPacket(long packetId) {
|
||||
synchronized (this) {
|
||||
|
||||
if (gotAllPoint == 0) {
|
||||
gotAllPoint = packetId;
|
||||
return true;
|
||||
}
|
||||
if (packetId <= gotAllPoint) {
|
||||
// already processed this packet
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!resendCountMap.isEmpty()){
|
||||
resendCountMap.remove(Long.valueOf(packetId));
|
||||
}
|
||||
|
||||
if (packetId == gotAllPoint + 1) {
|
||||
gotAllPoint = packetId;
|
||||
} else {
|
||||
if (packetId > gotMaxPoint) {
|
||||
gotMaxPoint = packetId;
|
||||
}
|
||||
outOfOrderList.add(Long.valueOf(packetId));
|
||||
}
|
||||
checkOutOfOrderList();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkOutOfOrderList() {
|
||||
|
||||
if (outOfOrderList.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean continueCheck;
|
||||
do {
|
||||
continueCheck = false;
|
||||
long nextPoint = gotAllPoint + 1;
|
||||
|
||||
Iterator<Long> it = outOfOrderList.iterator();
|
||||
while (it.hasNext()) {
|
||||
Long id = it.next();
|
||||
if (id.longValue() == nextPoint) {
|
||||
// we found the next one in the outOfOrderList
|
||||
it.remove();
|
||||
gotAllPoint = nextPoint;
|
||||
continueCheck = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (continueCheck);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* For Incoming Packets remembers the packets we have received and processed.
|
||||
* <p>
|
||||
* This determines the gotAllPoint per cluster member and identifies missing
|
||||
* packets (gap between gotAllPoint and gotMaxPoint).
|
||||
* </p>
|
||||
* <p>
|
||||
* This information is used by the managerThread so send ACK's for messages we
|
||||
* have received and RESEND messages to fill the missing packets we have
|
||||
* detected.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class IncomingPacketsProcessed {
|
||||
|
||||
private final ConcurrentHashMap<String, GotAllPoint> mapByMember = new ConcurrentHashMap<String, GotAllPoint>();
|
||||
|
||||
private final int maxResendIncoming;
|
||||
|
||||
public IncomingPacketsProcessed(int maxResendIncoming) {
|
||||
this.maxResendIncoming = maxResendIncoming;
|
||||
}
|
||||
|
||||
public void removeMember(String memberKey) {
|
||||
mapByMember.remove(memberKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should process this packet. Return false if we have
|
||||
* already processed the packet.
|
||||
*/
|
||||
public boolean isProcessPacket(String memberKey, long packetId) {
|
||||
|
||||
GotAllPoint memberPackets = getMemberPackets(memberKey);
|
||||
return memberPackets.processPacket(packetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the list of ACK and RESEND messages that we should send out
|
||||
* to the other members of the cluster.
|
||||
*/
|
||||
public AckResendMessages getAckResendMessages(IncomingPacketsLastAck lastAck) {
|
||||
|
||||
// Called by the McastClusterBroadcast manager thread
|
||||
|
||||
AckResendMessages response = new AckResendMessages();
|
||||
|
||||
for (GotAllPoint member : mapByMember.values()) {
|
||||
|
||||
MessageAck lastAckMessage = lastAck.getLastAck(member.getMemberKey());
|
||||
|
||||
member.addAckResendMessages(response, lastAckMessage);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private GotAllPoint getMemberPackets(String memberKey) {
|
||||
|
||||
// This method is only called single threaded
|
||||
// by the listener thread so I'm happy that this
|
||||
// put into mapByMember is ok.
|
||||
GotAllPoint memberGotAllPoint = mapByMember.get(memberKey);
|
||||
if (memberGotAllPoint == null) {
|
||||
memberGotAllPoint = new GotAllPoint(memberKey, maxResendIncoming);
|
||||
mapByMember.put(memberKey, memberGotAllPoint);
|
||||
}
|
||||
return memberGotAllPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps track of packets received from a particular member of the cluster.
|
||||
* <p>
|
||||
* It notes the packetIds of the packets received and uses those to maintain
|
||||
* the 'gotAllPoint'. The 'gotAllPoint' is the packetId which we know we
|
||||
* received all the previous packets.
|
||||
* </p>
|
||||
*/
|
||||
public static class GotAllPoint {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GotAllPoint.class.getName());
|
||||
|
||||
private final String memberKey;
|
||||
private final int maxResendIncoming;
|
||||
|
||||
private long gotAllPoint;
|
||||
|
||||
private long gotMaxPoint;
|
||||
|
||||
/**
|
||||
* Packets received out of order.
|
||||
*/
|
||||
private ArrayList<Long> outOfOrderList = new ArrayList<Long>();
|
||||
|
||||
private HashMap<Long,Integer> resendCountMap = new HashMap<Long,Integer>();
|
||||
|
||||
public GotAllPoint(String memberKey, int maxResendIncoming) {
|
||||
this.memberKey = memberKey;
|
||||
this.maxResendIncoming = maxResendIncoming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ACK and RESEND messages if required.
|
||||
*/
|
||||
public void addAckResendMessages(AckResendMessages response, MessageAck lastAckMessage) {
|
||||
|
||||
synchronized (this) {
|
||||
if (lastAckMessage != null && lastAckMessage.getGotAllPacketId() >= gotAllPoint) {
|
||||
// nothing has changed
|
||||
} else {
|
||||
// ACK that we have got every packet up to gotAllPoint
|
||||
response.add(new MessageAck(memberKey, gotAllPoint));
|
||||
}
|
||||
|
||||
if (getMissingPacketCount() > 0) {
|
||||
// Ask for these Packets to be RESENT
|
||||
List<Long> missingPackets = getMissingPackets();
|
||||
response.add(new MessageResend(memberKey, missingPackets));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getMemberKey() {
|
||||
return memberKey;
|
||||
}
|
||||
|
||||
public long getGotAllPoint() {
|
||||
synchronized (this) {
|
||||
return gotAllPoint;
|
||||
}
|
||||
}
|
||||
|
||||
public long getGotMaxPoint() {
|
||||
synchronized (this) {
|
||||
return gotMaxPoint;
|
||||
}
|
||||
}
|
||||
|
||||
private int getMissingPacketCount() {
|
||||
if (gotMaxPoint <= gotAllPoint) {
|
||||
if (!resendCountMap.isEmpty()) {
|
||||
resendCountMap.clear();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return (int) (gotMaxPoint - gotAllPoint) - outOfOrderList.size();
|
||||
}
|
||||
|
||||
public List<Long> getMissingPackets() {
|
||||
|
||||
synchronized (this) {
|
||||
ArrayList<Long> missingList = new ArrayList<Long>();
|
||||
|
||||
// this is not particularly efficient but expecting
|
||||
// the outOfOrderList to be relatively small
|
||||
|
||||
boolean lostPacket = false;
|
||||
|
||||
for (long i = gotAllPoint + 1; i < gotMaxPoint; i++) {
|
||||
Long packetId = Long.valueOf(i);
|
||||
if (!outOfOrderList.contains(packetId)) {
|
||||
if (incrementResendCount(packetId)) {
|
||||
// request this packet be resent
|
||||
missingList.add(packetId);
|
||||
} else {
|
||||
lostPacket = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lostPacket){
|
||||
checkOutOfOrderList();
|
||||
}
|
||||
|
||||
return missingList;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this packet has not yet exceeded the maxResendCount.
|
||||
*/
|
||||
private boolean incrementResendCount(Long packetId){
|
||||
Integer resendCount = resendCountMap.get(packetId);
|
||||
if (resendCount != null){
|
||||
int i = resendCount.intValue() + 1;
|
||||
if (i > maxResendIncoming){
|
||||
// we are going to give up trying to get this packet now
|
||||
logger.warning("Exceeded maxResendIncoming["+maxResendIncoming+"] for packet["+packetId+"]. Giving up on requesting it.");
|
||||
resendCountMap.remove(packetId);
|
||||
outOfOrderList.add(packetId);
|
||||
return false;
|
||||
}
|
||||
resendCount = Integer.valueOf(i);
|
||||
resendCountMap.put(packetId, resendCount);
|
||||
} else {
|
||||
resendCountMap.put(packetId, ONE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final Integer ONE = Integer.valueOf(1);
|
||||
|
||||
public boolean processPacket(long packetId) {
|
||||
synchronized (this) {
|
||||
|
||||
if (gotAllPoint == 0) {
|
||||
gotAllPoint = packetId;
|
||||
return true;
|
||||
}
|
||||
if (packetId <= gotAllPoint) {
|
||||
// already processed this packet
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!resendCountMap.isEmpty()){
|
||||
resendCountMap.remove(Long.valueOf(packetId));
|
||||
}
|
||||
|
||||
if (packetId == gotAllPoint + 1) {
|
||||
gotAllPoint = packetId;
|
||||
} else {
|
||||
if (packetId > gotMaxPoint) {
|
||||
gotMaxPoint = packetId;
|
||||
}
|
||||
outOfOrderList.add(Long.valueOf(packetId));
|
||||
}
|
||||
checkOutOfOrderList();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkOutOfOrderList() {
|
||||
|
||||
if (outOfOrderList.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean continueCheck;
|
||||
do {
|
||||
continueCheck = false;
|
||||
long nextPoint = gotAllPoint + 1;
|
||||
|
||||
Iterator<Long> it = outOfOrderList.iterator();
|
||||
while (it.hasNext()) {
|
||||
Long id = it.next();
|
||||
if (id.longValue() == nextPoint) {
|
||||
// we found the next one in the outOfOrderList
|
||||
it.remove();
|
||||
gotAllPoint = nextPoint;
|
||||
continueCheck = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (continueCheck);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.DataInput;
|
||||
|
||||
@@ -1,135 +1,116 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.Packet;
|
||||
|
||||
/**
|
||||
* Handles the sending of Packets via DatagramPacket.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class McastSender {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(McastSender.class.getName());
|
||||
|
||||
private final int port;
|
||||
|
||||
private final InetAddress inetAddress;
|
||||
|
||||
private final DatagramSocket sock;
|
||||
|
||||
private final InetSocketAddress sendAddr;
|
||||
|
||||
private final String senderHostPort;
|
||||
|
||||
|
||||
public McastSender(int port, String address, int sendPort, String sendAddress) {
|
||||
|
||||
try {
|
||||
this.port = port;
|
||||
this.inetAddress = InetAddress.getByName(address);
|
||||
|
||||
InetAddress sendInetAddress = null;
|
||||
if (sendAddress != null) {
|
||||
sendInetAddress = InetAddress.getByName(sendAddress);
|
||||
} else {
|
||||
sendInetAddress = InetAddress.getLocalHost();
|
||||
}
|
||||
|
||||
if (sendPort > 0) {
|
||||
this.sock = new DatagramSocket(sendPort, sendInetAddress);
|
||||
} else {
|
||||
this.sock = new DatagramSocket(new InetSocketAddress(sendInetAddress, 0));
|
||||
}
|
||||
|
||||
String msg = "Cluster Multicast Sender on["+sendInetAddress.getHostAddress()+":"+sock.getLocalPort()+"]";
|
||||
logger.info(msg);
|
||||
|
||||
this.sendAddr = new InetSocketAddress(sendInetAddress, sock.getLocalPort());
|
||||
this.senderHostPort = sendInetAddress.getHostAddress()+":"+sock.getLocalPort();
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "McastSender port:" + port + " sendPort:" + sendPort + " " + address;
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the send Address so that if we have loopback messages we can
|
||||
* detect if they where sent by this local sender and hence should be
|
||||
* ignored.
|
||||
*/
|
||||
public InetSocketAddress getAddress() {
|
||||
return sendAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Host and Port of the sender. This is used to uniquely identify
|
||||
* this instance in the cluster.
|
||||
*/
|
||||
public String getSenderHostPort() {
|
||||
return senderHostPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the packet.
|
||||
*/
|
||||
public int sendPacket(Packet packet) throws IOException {
|
||||
|
||||
byte[] pktBytes = packet.getBytes();
|
||||
|
||||
if (logger.isLoggable(Level.FINE)){
|
||||
logger.fine("OUTGOING packet: " + packet.getPacketId() + " size:" + pktBytes.length);
|
||||
}
|
||||
|
||||
if (pktBytes.length > 65507){
|
||||
logger.warning("OUTGOING packet: " + packet.getPacketId() + " size:" + pktBytes.length
|
||||
+" likely to be truncated using UDP with a MAXIMUM length of 65507");
|
||||
}
|
||||
|
||||
DatagramPacket pack = new DatagramPacket(pktBytes, pktBytes.length, inetAddress, port);
|
||||
sock.send(pack);
|
||||
|
||||
return pktBytes.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the list of Packets.
|
||||
*/
|
||||
public int sendPackets(List<Packet> packets) throws IOException {
|
||||
|
||||
int totalBytes = 0;
|
||||
for (int i = 0; i < packets.size(); i++) {
|
||||
totalBytes += sendPacket(packets.get(i));
|
||||
}
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.Packet;
|
||||
|
||||
/**
|
||||
* Handles the sending of Packets via DatagramPacket.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class McastSender {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(McastSender.class.getName());
|
||||
|
||||
private final int port;
|
||||
|
||||
private final InetAddress inetAddress;
|
||||
|
||||
private final DatagramSocket sock;
|
||||
|
||||
private final InetSocketAddress sendAddr;
|
||||
|
||||
private final String senderHostPort;
|
||||
|
||||
|
||||
public McastSender(int port, String address, int sendPort, String sendAddress) {
|
||||
|
||||
try {
|
||||
this.port = port;
|
||||
this.inetAddress = InetAddress.getByName(address);
|
||||
|
||||
InetAddress sendInetAddress = null;
|
||||
if (sendAddress != null) {
|
||||
sendInetAddress = InetAddress.getByName(sendAddress);
|
||||
} else {
|
||||
sendInetAddress = InetAddress.getLocalHost();
|
||||
}
|
||||
|
||||
if (sendPort > 0) {
|
||||
this.sock = new DatagramSocket(sendPort, sendInetAddress);
|
||||
} else {
|
||||
this.sock = new DatagramSocket(new InetSocketAddress(sendInetAddress, 0));
|
||||
}
|
||||
|
||||
String msg = "Cluster Multicast Sender on["+sendInetAddress.getHostAddress()+":"+sock.getLocalPort()+"]";
|
||||
logger.info(msg);
|
||||
|
||||
this.sendAddr = new InetSocketAddress(sendInetAddress, sock.getLocalPort());
|
||||
this.senderHostPort = sendInetAddress.getHostAddress()+":"+sock.getLocalPort();
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "McastSender port:" + port + " sendPort:" + sendPort + " " + address;
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the send Address so that if we have loopback messages we can
|
||||
* detect if they where sent by this local sender and hence should be
|
||||
* ignored.
|
||||
*/
|
||||
public InetSocketAddress getAddress() {
|
||||
return sendAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Host and Port of the sender. This is used to uniquely identify
|
||||
* this instance in the cluster.
|
||||
*/
|
||||
public String getSenderHostPort() {
|
||||
return senderHostPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the packet.
|
||||
*/
|
||||
public int sendPacket(Packet packet) throws IOException {
|
||||
|
||||
byte[] pktBytes = packet.getBytes();
|
||||
|
||||
if (logger.isLoggable(Level.FINE)){
|
||||
logger.fine("OUTGOING packet: " + packet.getPacketId() + " size:" + pktBytes.length);
|
||||
}
|
||||
|
||||
if (pktBytes.length > 65507){
|
||||
logger.warning("OUTGOING packet: " + packet.getPacketId() + " size:" + pktBytes.length
|
||||
+" likely to be truncated using UDP with a MAXIMUM length of 65507");
|
||||
}
|
||||
|
||||
DatagramPacket pack = new DatagramPacket(pktBytes, pktBytes.length, inetAddress, port);
|
||||
sock.send(pack);
|
||||
|
||||
return pktBytes.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the list of Packets.
|
||||
*/
|
||||
public int sendPackets(List<Packet> packets) throws IOException {
|
||||
|
||||
int totalBytes = 0;
|
||||
for (int i = 0; i < packets.size(); i++) {
|
||||
totalBytes += sendPacket(packets.get(i));
|
||||
}
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,155 +1,136 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
/**
|
||||
* Gives an overall status of this Cluster instance.
|
||||
* <p>
|
||||
* Ideally you want to see relatively low Re-send statistics.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class McastStatus {
|
||||
|
||||
private final long totalTxnEventsSent;
|
||||
private final long totalTxnEventsReceived;
|
||||
|
||||
private final long totalPacketsSent;
|
||||
private final long totalPacketsResent;
|
||||
private final long totalPacketsReceived;
|
||||
|
||||
private final long totalBytesSent;
|
||||
private final long totalBytesResent;
|
||||
private final long totalBytesReceived;
|
||||
|
||||
private final int currentGroupSize;
|
||||
private final int outgoingPacketsCacheSize;
|
||||
|
||||
private final long currentPacketId;
|
||||
private final long minAckedPacketId;
|
||||
private final String lastOutgoingAcks;
|
||||
|
||||
public String getSummary() {
|
||||
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
sb.append("txnOut:").append(totalTxnEventsSent).append("; ");
|
||||
sb.append("txnIn:").append(totalTxnEventsReceived).append("; ");
|
||||
sb.append("outPackets:").append(totalPacketsSent).append("; ");
|
||||
sb.append("outBytes:").append(totalBytesSent).append("; ");
|
||||
sb.append("inPackets:").append(totalPacketsReceived).append("; ");
|
||||
sb.append("inBytes:").append(totalBytesReceived).append("; ");
|
||||
sb.append("resentPackets:").append(totalPacketsResent).append("; ");
|
||||
sb.append("resentBytes:").append(totalBytesResent).append("; ");
|
||||
sb.append("groupSize:").append(currentGroupSize).append("; ");
|
||||
sb.append("cache:").append(outgoingPacketsCacheSize).append("; ");
|
||||
sb.append("currentPacket:").append(currentPacketId).append("; ");
|
||||
sb.append("minAckedPacket:").append(minAckedPacketId).append("; ");
|
||||
sb.append("lastAck:").append(lastOutgoingAcks).append("; ");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public McastStatus(int currentGroupSize,
|
||||
int outgoingPacketsCacheSize,
|
||||
long currentPacketId,
|
||||
long minAckedPacketId,
|
||||
String lastOutgoingAcks,
|
||||
long totalTransEventsSent,
|
||||
long totalTransEventsReceived,
|
||||
long totalPacketsSent,
|
||||
long totalPacketsResent,
|
||||
long totalPacketsReceived,
|
||||
long totalBytesSent,
|
||||
long totalBytesResent,
|
||||
long totalBytesReceived) {
|
||||
|
||||
this.currentGroupSize = currentGroupSize;
|
||||
this.outgoingPacketsCacheSize = outgoingPacketsCacheSize;
|
||||
this.currentPacketId = currentPacketId;
|
||||
this.minAckedPacketId = minAckedPacketId;
|
||||
this.lastOutgoingAcks = lastOutgoingAcks;
|
||||
this.totalTxnEventsSent = totalTransEventsSent;
|
||||
this.totalTxnEventsReceived = totalTransEventsReceived;
|
||||
this.totalPacketsSent = totalPacketsSent;
|
||||
this.totalPacketsResent = totalPacketsResent;
|
||||
this.totalPacketsReceived = totalPacketsReceived;
|
||||
|
||||
this.totalBytesSent = totalBytesSent;
|
||||
this.totalBytesResent = totalBytesResent;
|
||||
this.totalBytesReceived = totalBytesReceived;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public long getTotalTxnEventsReceived() {
|
||||
return totalTxnEventsReceived;
|
||||
}
|
||||
|
||||
public long getTotalPacketsReceived() {
|
||||
return totalPacketsReceived;
|
||||
}
|
||||
|
||||
public long getTotalBytesSent() {
|
||||
return totalBytesSent;
|
||||
}
|
||||
|
||||
public long getTotalBytesResent() {
|
||||
return totalBytesResent;
|
||||
}
|
||||
|
||||
public long getTotalBytesReceived() {
|
||||
return totalBytesReceived;
|
||||
}
|
||||
|
||||
public String getLastOutgoingAcks() {
|
||||
return lastOutgoingAcks;
|
||||
}
|
||||
|
||||
public int getOutgoingPacketsCacheSize() {
|
||||
return outgoingPacketsCacheSize;
|
||||
}
|
||||
|
||||
public long getCurrentPacketId() {
|
||||
return currentPacketId;
|
||||
}
|
||||
|
||||
public long getMinAckedPacketId() {
|
||||
return minAckedPacketId;
|
||||
}
|
||||
|
||||
public long getTotalTxnEventsSent() {
|
||||
return totalTxnEventsSent;
|
||||
}
|
||||
|
||||
public long getTotalPacketsSent() {
|
||||
return totalPacketsSent;
|
||||
}
|
||||
|
||||
public long getTotalPacketsResent() {
|
||||
return totalPacketsResent;
|
||||
}
|
||||
|
||||
public long getCurrentGroupSize() {
|
||||
return currentGroupSize;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
/**
|
||||
* Gives an overall status of this Cluster instance.
|
||||
* <p>
|
||||
* Ideally you want to see relatively low Re-send statistics.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class McastStatus {
|
||||
|
||||
private final long totalTxnEventsSent;
|
||||
private final long totalTxnEventsReceived;
|
||||
|
||||
private final long totalPacketsSent;
|
||||
private final long totalPacketsResent;
|
||||
private final long totalPacketsReceived;
|
||||
|
||||
private final long totalBytesSent;
|
||||
private final long totalBytesResent;
|
||||
private final long totalBytesReceived;
|
||||
|
||||
private final int currentGroupSize;
|
||||
private final int outgoingPacketsCacheSize;
|
||||
|
||||
private final long currentPacketId;
|
||||
private final long minAckedPacketId;
|
||||
private final String lastOutgoingAcks;
|
||||
|
||||
public String getSummary() {
|
||||
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
sb.append("txnOut:").append(totalTxnEventsSent).append("; ");
|
||||
sb.append("txnIn:").append(totalTxnEventsReceived).append("; ");
|
||||
sb.append("outPackets:").append(totalPacketsSent).append("; ");
|
||||
sb.append("outBytes:").append(totalBytesSent).append("; ");
|
||||
sb.append("inPackets:").append(totalPacketsReceived).append("; ");
|
||||
sb.append("inBytes:").append(totalBytesReceived).append("; ");
|
||||
sb.append("resentPackets:").append(totalPacketsResent).append("; ");
|
||||
sb.append("resentBytes:").append(totalBytesResent).append("; ");
|
||||
sb.append("groupSize:").append(currentGroupSize).append("; ");
|
||||
sb.append("cache:").append(outgoingPacketsCacheSize).append("; ");
|
||||
sb.append("currentPacket:").append(currentPacketId).append("; ");
|
||||
sb.append("minAckedPacket:").append(minAckedPacketId).append("; ");
|
||||
sb.append("lastAck:").append(lastOutgoingAcks).append("; ");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public McastStatus(int currentGroupSize,
|
||||
int outgoingPacketsCacheSize,
|
||||
long currentPacketId,
|
||||
long minAckedPacketId,
|
||||
String lastOutgoingAcks,
|
||||
long totalTransEventsSent,
|
||||
long totalTransEventsReceived,
|
||||
long totalPacketsSent,
|
||||
long totalPacketsResent,
|
||||
long totalPacketsReceived,
|
||||
long totalBytesSent,
|
||||
long totalBytesResent,
|
||||
long totalBytesReceived) {
|
||||
|
||||
this.currentGroupSize = currentGroupSize;
|
||||
this.outgoingPacketsCacheSize = outgoingPacketsCacheSize;
|
||||
this.currentPacketId = currentPacketId;
|
||||
this.minAckedPacketId = minAckedPacketId;
|
||||
this.lastOutgoingAcks = lastOutgoingAcks;
|
||||
this.totalTxnEventsSent = totalTransEventsSent;
|
||||
this.totalTxnEventsReceived = totalTransEventsReceived;
|
||||
this.totalPacketsSent = totalPacketsSent;
|
||||
this.totalPacketsResent = totalPacketsResent;
|
||||
this.totalPacketsReceived = totalPacketsReceived;
|
||||
|
||||
this.totalBytesSent = totalBytesSent;
|
||||
this.totalBytesResent = totalBytesResent;
|
||||
this.totalBytesReceived = totalBytesReceived;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public long getTotalTxnEventsReceived() {
|
||||
return totalTxnEventsReceived;
|
||||
}
|
||||
|
||||
public long getTotalPacketsReceived() {
|
||||
return totalPacketsReceived;
|
||||
}
|
||||
|
||||
public long getTotalBytesSent() {
|
||||
return totalBytesSent;
|
||||
}
|
||||
|
||||
public long getTotalBytesResent() {
|
||||
return totalBytesResent;
|
||||
}
|
||||
|
||||
public long getTotalBytesReceived() {
|
||||
return totalBytesReceived;
|
||||
}
|
||||
|
||||
public String getLastOutgoingAcks() {
|
||||
return lastOutgoingAcks;
|
||||
}
|
||||
|
||||
public int getOutgoingPacketsCacheSize() {
|
||||
return outgoingPacketsCacheSize;
|
||||
}
|
||||
|
||||
public long getCurrentPacketId() {
|
||||
return currentPacketId;
|
||||
}
|
||||
|
||||
public long getMinAckedPacketId() {
|
||||
return minAckedPacketId;
|
||||
}
|
||||
|
||||
public long getTotalTxnEventsSent() {
|
||||
return totalTxnEventsSent;
|
||||
}
|
||||
|
||||
public long getTotalPacketsSent() {
|
||||
return totalPacketsSent;
|
||||
}
|
||||
|
||||
public long getTotalPacketsResent() {
|
||||
return totalPacketsResent;
|
||||
}
|
||||
|
||||
public long getCurrentGroupSize() {
|
||||
return currentGroupSize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,33 +1,14 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
|
||||
|
||||
public interface Message {
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException;
|
||||
|
||||
public boolean isControlMessage();
|
||||
|
||||
public String getToHostPort();
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
|
||||
|
||||
public interface Message {
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException;
|
||||
|
||||
public boolean isControlMessage();
|
||||
|
||||
public String getToHostPort();
|
||||
}
|
||||
|
||||
@@ -1,76 +1,57 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
|
||||
|
||||
public class MessageAck implements Message {
|
||||
|
||||
private final String toHostPort;
|
||||
|
||||
private final long gotAllPacketId;
|
||||
|
||||
public MessageAck(String toHostPort, long gotAllPacketId) {
|
||||
this.toHostPort = toHostPort;
|
||||
this.gotAllPacketId = gotAllPacketId;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Ack "+toHostPort+" "+gotAllPacketId;
|
||||
}
|
||||
|
||||
public boolean isControlMessage() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getToHostPort() {
|
||||
return toHostPort;
|
||||
}
|
||||
|
||||
public long getGotAllPacketId() {
|
||||
return gotAllPacketId;
|
||||
}
|
||||
|
||||
|
||||
public static MessageAck readBinaryMessage(DataInput dataInput) throws IOException {
|
||||
|
||||
String hostPort = dataInput.readUTF();
|
||||
long gotAllPacketId = dataInput.readLong();
|
||||
return new MessageAck(hostPort, gotAllPacketId);
|
||||
}
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
|
||||
BinaryMessage m = new BinaryMessage(toHostPort.length() * 2 + 20);
|
||||
|
||||
DataOutputStream os = m.getOs();
|
||||
os.writeInt(BinaryMessage.TYPE_MSGACK);
|
||||
os.writeUTF(toHostPort);
|
||||
os.writeLong(gotAllPacketId);
|
||||
os.flush();
|
||||
|
||||
msgList.add(m);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
|
||||
|
||||
public class MessageAck implements Message {
|
||||
|
||||
private final String toHostPort;
|
||||
|
||||
private final long gotAllPacketId;
|
||||
|
||||
public MessageAck(String toHostPort, long gotAllPacketId) {
|
||||
this.toHostPort = toHostPort;
|
||||
this.gotAllPacketId = gotAllPacketId;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Ack "+toHostPort+" "+gotAllPacketId;
|
||||
}
|
||||
|
||||
public boolean isControlMessage() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getToHostPort() {
|
||||
return toHostPort;
|
||||
}
|
||||
|
||||
public long getGotAllPacketId() {
|
||||
return gotAllPacketId;
|
||||
}
|
||||
|
||||
|
||||
public static MessageAck readBinaryMessage(DataInput dataInput) throws IOException {
|
||||
|
||||
String hostPort = dataInput.readUTF();
|
||||
long gotAllPacketId = dataInput.readLong();
|
||||
return new MessageAck(hostPort, gotAllPacketId);
|
||||
}
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
|
||||
BinaryMessage m = new BinaryMessage(toHostPort.length() * 2 + 20);
|
||||
|
||||
DataOutputStream os = m.getOs();
|
||||
os.writeInt(BinaryMessage.TYPE_MSGACK);
|
||||
os.writeUTF(toHostPort);
|
||||
os.writeLong(gotAllPacketId);
|
||||
os.flush();
|
||||
|
||||
msgList.add(m);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,92 +1,73 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
|
||||
|
||||
public class MessageControl implements Message {
|
||||
|
||||
public static final short TYPE_JOIN = 1;
|
||||
public static final short TYPE_LEAVE = 2;
|
||||
public static final short TYPE_PING = 3;
|
||||
public static final short TYPE_JOINRESPONSE = 7;
|
||||
public static final short TYPE_PINGRESPONSE = 8;
|
||||
|
||||
private final short controlType;
|
||||
private final String fromHostPort;
|
||||
|
||||
public static MessageControl readBinaryMessage(DataInput dataInput) throws IOException {
|
||||
short controlType = dataInput.readShort();
|
||||
String hostPort = dataInput.readUTF();
|
||||
return new MessageControl(controlType, hostPort);
|
||||
}
|
||||
|
||||
public MessageControl(short controlType, String helloFromHostPort) {
|
||||
this.controlType = controlType;
|
||||
this.fromHostPort = helloFromHostPort;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
switch (controlType) {
|
||||
case TYPE_JOIN: return "Join "+fromHostPort;
|
||||
case TYPE_LEAVE: return "Leave "+fromHostPort;
|
||||
case TYPE_PING: return "Ping "+fromHostPort;
|
||||
case TYPE_PINGRESPONSE: return "PingResponse "+fromHostPort;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid controlType "+controlType);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isControlMessage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public short getControlType() {
|
||||
return controlType;
|
||||
}
|
||||
|
||||
public String getToHostPort() {
|
||||
return "*";
|
||||
}
|
||||
|
||||
public String getFromHostPort() {
|
||||
return fromHostPort;
|
||||
}
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
|
||||
BinaryMessage m = new BinaryMessage(fromHostPort.length() * 2 + 10);
|
||||
|
||||
DataOutputStream os = m.getOs();
|
||||
os.writeInt(BinaryMessage.TYPE_MSGCONTROL);
|
||||
os.writeShort(controlType);
|
||||
os.writeUTF(fromHostPort);
|
||||
os.flush();
|
||||
|
||||
msgList.add(m);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
|
||||
|
||||
public class MessageControl implements Message {
|
||||
|
||||
public static final short TYPE_JOIN = 1;
|
||||
public static final short TYPE_LEAVE = 2;
|
||||
public static final short TYPE_PING = 3;
|
||||
public static final short TYPE_JOINRESPONSE = 7;
|
||||
public static final short TYPE_PINGRESPONSE = 8;
|
||||
|
||||
private final short controlType;
|
||||
private final String fromHostPort;
|
||||
|
||||
public static MessageControl readBinaryMessage(DataInput dataInput) throws IOException {
|
||||
short controlType = dataInput.readShort();
|
||||
String hostPort = dataInput.readUTF();
|
||||
return new MessageControl(controlType, hostPort);
|
||||
}
|
||||
|
||||
public MessageControl(short controlType, String helloFromHostPort) {
|
||||
this.controlType = controlType;
|
||||
this.fromHostPort = helloFromHostPort;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
switch (controlType) {
|
||||
case TYPE_JOIN: return "Join "+fromHostPort;
|
||||
case TYPE_LEAVE: return "Leave "+fromHostPort;
|
||||
case TYPE_PING: return "Ping "+fromHostPort;
|
||||
case TYPE_PINGRESPONSE: return "PingResponse "+fromHostPort;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid controlType "+controlType);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isControlMessage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public short getControlType() {
|
||||
return controlType;
|
||||
}
|
||||
|
||||
public String getToHostPort() {
|
||||
return "*";
|
||||
}
|
||||
|
||||
public String getFromHostPort() {
|
||||
return fromHostPort;
|
||||
}
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
|
||||
BinaryMessage m = new BinaryMessage(fromHostPort.length() * 2 + 10);
|
||||
|
||||
DataOutputStream os = m.getOs();
|
||||
os.writeInt(BinaryMessage.TYPE_MSGCONTROL);
|
||||
os.writeShort(controlType);
|
||||
os.writeUTF(fromHostPort);
|
||||
os.flush();
|
||||
|
||||
msgList.add(m);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,96 +1,77 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
|
||||
|
||||
public class MessageResend implements Message {
|
||||
|
||||
private final String toHostPort;
|
||||
|
||||
private final List<Long> resendPacketIds;
|
||||
|
||||
public MessageResend(String toHostPort, List<Long> resendPacketIds) {
|
||||
this.toHostPort = toHostPort;
|
||||
this.resendPacketIds = resendPacketIds;
|
||||
}
|
||||
|
||||
public MessageResend(String toHostPort) {
|
||||
this(toHostPort, new ArrayList<Long>(4));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Resend "+toHostPort+" "+resendPacketIds;
|
||||
}
|
||||
|
||||
public boolean isControlMessage() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getToHostPort() {
|
||||
return toHostPort;
|
||||
}
|
||||
|
||||
public void add(long packetId){
|
||||
resendPacketIds.add(Long.valueOf(packetId));
|
||||
}
|
||||
|
||||
public List<Long> getResendPacketIds() {
|
||||
return resendPacketIds;
|
||||
}
|
||||
|
||||
public static MessageResend readBinaryMessage(DataInput dataInput) throws IOException {
|
||||
|
||||
String hostPort = dataInput.readUTF();
|
||||
|
||||
MessageResend msg = new MessageResend(hostPort);
|
||||
|
||||
int numberOfPacketIds = dataInput.readInt();
|
||||
for (int i = 0; i < numberOfPacketIds; i++) {
|
||||
long packetId = dataInput.readLong();
|
||||
msg.add(packetId);
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
|
||||
BinaryMessage m = new BinaryMessage(toHostPort.length() * 2 + 20);
|
||||
|
||||
DataOutputStream os = m.getOs();
|
||||
os.writeInt(BinaryMessage.TYPE_MSGRESEND);
|
||||
os.writeUTF(toHostPort);
|
||||
os.writeInt(resendPacketIds.size());
|
||||
for (int i = 0; i < resendPacketIds.size(); i++) {
|
||||
Long packetId = resendPacketIds.get(i);
|
||||
os.writeLong(packetId.longValue());
|
||||
}
|
||||
os.flush();
|
||||
msgList.add(m);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
|
||||
|
||||
public class MessageResend implements Message {
|
||||
|
||||
private final String toHostPort;
|
||||
|
||||
private final List<Long> resendPacketIds;
|
||||
|
||||
public MessageResend(String toHostPort, List<Long> resendPacketIds) {
|
||||
this.toHostPort = toHostPort;
|
||||
this.resendPacketIds = resendPacketIds;
|
||||
}
|
||||
|
||||
public MessageResend(String toHostPort) {
|
||||
this(toHostPort, new ArrayList<Long>(4));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Resend "+toHostPort+" "+resendPacketIds;
|
||||
}
|
||||
|
||||
public boolean isControlMessage() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getToHostPort() {
|
||||
return toHostPort;
|
||||
}
|
||||
|
||||
public void add(long packetId){
|
||||
resendPacketIds.add(Long.valueOf(packetId));
|
||||
}
|
||||
|
||||
public List<Long> getResendPacketIds() {
|
||||
return resendPacketIds;
|
||||
}
|
||||
|
||||
public static MessageResend readBinaryMessage(DataInput dataInput) throws IOException {
|
||||
|
||||
String hostPort = dataInput.readUTF();
|
||||
|
||||
MessageResend msg = new MessageResend(hostPort);
|
||||
|
||||
int numberOfPacketIds = dataInput.readInt();
|
||||
for (int i = 0; i < numberOfPacketIds; i++) {
|
||||
long packetId = dataInput.readLong();
|
||||
msg.add(packetId);
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
|
||||
BinaryMessage m = new BinaryMessage(toHostPort.length() * 2 + 20);
|
||||
|
||||
DataOutputStream os = m.getOs();
|
||||
os.writeInt(BinaryMessage.TYPE_MSGRESEND);
|
||||
os.writeUTF(toHostPort);
|
||||
os.writeInt(resendPacketIds.size());
|
||||
for (int i = 0; i < resendPacketIds.size(); i++) {
|
||||
Long packetId = resendPacketIds.get(i);
|
||||
os.writeLong(packetId.longValue());
|
||||
}
|
||||
os.flush();
|
||||
msgList.add(m);
|
||||
}
|
||||
}
|
||||
|
||||
+106
-125
@@ -1,125 +1,106 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class OutgoingPacketsAcked {
|
||||
|
||||
private long minimumGotAllPacketId;
|
||||
|
||||
private Map<String, GroupMemberAck> recievedByMap = new HashMap<String, GroupMemberAck>();
|
||||
|
||||
public int getGroupSize() {
|
||||
synchronized (this) {
|
||||
return recievedByMap.size();
|
||||
}
|
||||
}
|
||||
|
||||
public long getMinimumGotAllPacketId() {
|
||||
synchronized (this) {
|
||||
return minimumGotAllPacketId;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeMember(String groupMember){
|
||||
synchronized (this) {
|
||||
recievedByMap.remove(groupMember);
|
||||
resetGotAllMin();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean resetGotAllMin() {
|
||||
|
||||
long tempMin;
|
||||
if (recievedByMap.isEmpty()){
|
||||
//System.out.println(" -- -- -- -- "+recievedByMap.isEmpty());
|
||||
tempMin = Long.MAX_VALUE;
|
||||
} else {
|
||||
tempMin = Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
for (GroupMemberAck groupMemAck : recievedByMap.values()) {
|
||||
long memberMin = groupMemAck.getGotAllPacketId();
|
||||
if (memberMin < tempMin){
|
||||
//System.out.println(" -- new tmpMin "+memberMin);
|
||||
tempMin = memberMin;
|
||||
}
|
||||
}
|
||||
|
||||
if (tempMin != minimumGotAllPacketId) {
|
||||
minimumGotAllPacketId = tempMin;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public long receivedAck(String groupMember, MessageAck ack) {
|
||||
|
||||
synchronized (this) {
|
||||
|
||||
boolean checkMin = false;
|
||||
|
||||
GroupMemberAck groupMemberAck = recievedByMap.get(groupMember);
|
||||
if (groupMemberAck == null) {
|
||||
//System.out.println(" -- new groupMemberAck");
|
||||
groupMemberAck = new GroupMemberAck();
|
||||
groupMemberAck.setIfBigger(ack.getGotAllPacketId());
|
||||
recievedByMap.put(groupMember, groupMemberAck);
|
||||
checkMin = true;
|
||||
} else {
|
||||
checkMin = groupMemberAck.getGotAllPacketId() == minimumGotAllPacketId;
|
||||
//System.out.println(" -- existing groupMemberAck, checkMin:"+checkMin+" "+groupMemberAck.getGotAllPacketId());
|
||||
groupMemberAck.setIfBigger(ack.getGotAllPacketId());
|
||||
}
|
||||
|
||||
boolean minChanged = false;
|
||||
|
||||
//System.out.println(" -- checkMin:"+checkMin+" minimumGotAllPacketId:"+minimumGotAllPacketId);
|
||||
if (checkMin || minimumGotAllPacketId == 0){
|
||||
|
||||
minChanged = resetGotAllMin();
|
||||
//System.out.println(" -- minChanged:"+minChanged+" minimumGotAllPacketId:"+minimumGotAllPacketId);
|
||||
}
|
||||
|
||||
return minChanged ? minimumGotAllPacketId : 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GroupMemberAck {
|
||||
|
||||
private long gotAllPacketId;
|
||||
|
||||
private GroupMemberAck() {
|
||||
}
|
||||
|
||||
private long getGotAllPacketId() {
|
||||
return gotAllPacketId;
|
||||
}
|
||||
|
||||
private void setIfBigger(long newGotAll) {
|
||||
if (newGotAll > gotAllPacketId) {
|
||||
gotAllPacketId = newGotAll;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class OutgoingPacketsAcked {
|
||||
|
||||
private long minimumGotAllPacketId;
|
||||
|
||||
private Map<String, GroupMemberAck> recievedByMap = new HashMap<String, GroupMemberAck>();
|
||||
|
||||
public int getGroupSize() {
|
||||
synchronized (this) {
|
||||
return recievedByMap.size();
|
||||
}
|
||||
}
|
||||
|
||||
public long getMinimumGotAllPacketId() {
|
||||
synchronized (this) {
|
||||
return minimumGotAllPacketId;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeMember(String groupMember){
|
||||
synchronized (this) {
|
||||
recievedByMap.remove(groupMember);
|
||||
resetGotAllMin();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean resetGotAllMin() {
|
||||
|
||||
long tempMin;
|
||||
if (recievedByMap.isEmpty()){
|
||||
//System.out.println(" -- -- -- -- "+recievedByMap.isEmpty());
|
||||
tempMin = Long.MAX_VALUE;
|
||||
} else {
|
||||
tempMin = Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
for (GroupMemberAck groupMemAck : recievedByMap.values()) {
|
||||
long memberMin = groupMemAck.getGotAllPacketId();
|
||||
if (memberMin < tempMin){
|
||||
//System.out.println(" -- new tmpMin "+memberMin);
|
||||
tempMin = memberMin;
|
||||
}
|
||||
}
|
||||
|
||||
if (tempMin != minimumGotAllPacketId) {
|
||||
minimumGotAllPacketId = tempMin;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public long receivedAck(String groupMember, MessageAck ack) {
|
||||
|
||||
synchronized (this) {
|
||||
|
||||
boolean checkMin = false;
|
||||
|
||||
GroupMemberAck groupMemberAck = recievedByMap.get(groupMember);
|
||||
if (groupMemberAck == null) {
|
||||
//System.out.println(" -- new groupMemberAck");
|
||||
groupMemberAck = new GroupMemberAck();
|
||||
groupMemberAck.setIfBigger(ack.getGotAllPacketId());
|
||||
recievedByMap.put(groupMember, groupMemberAck);
|
||||
checkMin = true;
|
||||
} else {
|
||||
checkMin = groupMemberAck.getGotAllPacketId() == minimumGotAllPacketId;
|
||||
//System.out.println(" -- existing groupMemberAck, checkMin:"+checkMin+" "+groupMemberAck.getGotAllPacketId());
|
||||
groupMemberAck.setIfBigger(ack.getGotAllPacketId());
|
||||
}
|
||||
|
||||
boolean minChanged = false;
|
||||
|
||||
//System.out.println(" -- checkMin:"+checkMin+" minimumGotAllPacketId:"+minimumGotAllPacketId);
|
||||
if (checkMin || minimumGotAllPacketId == 0){
|
||||
|
||||
minChanged = resetGotAllMin();
|
||||
//System.out.println(" -- minChanged:"+minChanged+" minimumGotAllPacketId:"+minimumGotAllPacketId);
|
||||
}
|
||||
|
||||
return minChanged ? minimumGotAllPacketId : 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GroupMemberAck {
|
||||
|
||||
private long gotAllPacketId;
|
||||
|
||||
private GroupMemberAck() {
|
||||
}
|
||||
|
||||
private long getGotAllPacketId() {
|
||||
return gotAllPacketId;
|
||||
}
|
||||
|
||||
private void setIfBigger(long newGotAll) {
|
||||
if (newGotAll > gotAllPacketId) {
|
||||
gotAllPacketId = newGotAll;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+66
-85
@@ -1,85 +1,66 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.Packet;
|
||||
|
||||
/**
|
||||
* Cache of the outgoing packets.
|
||||
* <p>
|
||||
* These are held until we receive ACKs from the other members of the cluster to
|
||||
* say they have received the packets.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class OutgoingPacketsCache {
|
||||
|
||||
private final Map<Long, Packet> packetMap = new TreeMap<Long, Packet>();
|
||||
|
||||
public int size() {
|
||||
return packetMap.size();
|
||||
}
|
||||
|
||||
public Packet getPacket(Long packetId) {
|
||||
return packetMap.get(packetId);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return packetMap.keySet().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the packet when we give up trying to send it out.
|
||||
*/
|
||||
public void remove(Packet packet) {
|
||||
packetMap.remove(packet.getPacketId());
|
||||
}
|
||||
|
||||
public void registerPackets(List<Packet> packets) {
|
||||
for (int i = 0; i < packets.size(); i++) {
|
||||
Packet p = packets.get(i);
|
||||
packetMap.put(p.getPacketId(), p);
|
||||
}
|
||||
}
|
||||
|
||||
public int trimAll() {
|
||||
int size = packetMap.size();
|
||||
packetMap.clear();
|
||||
return size;
|
||||
}
|
||||
|
||||
public void trimAcknowledgedMessages(long minAcked) {
|
||||
Iterator<Long> it = packetMap.keySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Long pktId = it.next();
|
||||
if (minAcked >= pktId.longValue()) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.Packet;
|
||||
|
||||
/**
|
||||
* Cache of the outgoing packets.
|
||||
* <p>
|
||||
* These are held until we receive ACKs from the other members of the cluster to
|
||||
* say they have received the packets.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class OutgoingPacketsCache {
|
||||
|
||||
private final Map<Long, Packet> packetMap = new TreeMap<Long, Packet>();
|
||||
|
||||
public int size() {
|
||||
return packetMap.size();
|
||||
}
|
||||
|
||||
public Packet getPacket(Long packetId) {
|
||||
return packetMap.get(packetId);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return packetMap.keySet().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the packet when we give up trying to send it out.
|
||||
*/
|
||||
public void remove(Packet packet) {
|
||||
packetMap.remove(packet.getPacketId());
|
||||
}
|
||||
|
||||
public void registerPackets(List<Packet> packets) {
|
||||
for (int i = 0; i < packets.size(); i++) {
|
||||
Packet p = packets.get(i);
|
||||
packetMap.put(p.getPacketId(), p);
|
||||
}
|
||||
}
|
||||
|
||||
public int trimAll() {
|
||||
int size = packetMap.size();
|
||||
packetMap.clear();
|
||||
return size;
|
||||
}
|
||||
|
||||
public void trimAcknowledgedMessages(long minAcked) {
|
||||
Iterator<Long> it = packetMap.keySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Long pktId = it.next();
|
||||
if (minAcked >= pktId.longValue()) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,76 +1,59 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This parses and dispatches a request to the appropriate handler.
|
||||
* <p>
|
||||
* Looks up the appropriate RequestHandler
|
||||
* and then gets it to process the Client request.<P>
|
||||
* </p>
|
||||
* Note that this is a Runnable because it is assigned to the ThreadPool.
|
||||
*/
|
||||
class RequestProcessor implements Runnable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RequestProcessor.class.getName());
|
||||
|
||||
private final Socket clientSocket;
|
||||
|
||||
private final SocketClusterBroadcast owner;
|
||||
|
||||
/**
|
||||
* Create including the Listener (used to lookup the Request Handler) and
|
||||
* the socket itself.
|
||||
*/
|
||||
public RequestProcessor(SocketClusterBroadcast owner, Socket clientSocket) {
|
||||
this.clientSocket = clientSocket;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will parse out the command. Lookup the appropriate Handler and
|
||||
* pass the information to the handler for processing.
|
||||
* <P>Dev Note: the command parsing is processed here so that it is preformed
|
||||
* by the assigned thread rather than the listeners thread.</P>
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
SocketConnection sc = new SocketConnection(clientSocket);
|
||||
|
||||
while(true){
|
||||
if (owner.process(sc)) {
|
||||
// got the offline message or timeout
|
||||
break;
|
||||
}
|
||||
}
|
||||
sc.disconnect();
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This parses and dispatches a request to the appropriate handler.
|
||||
* <p>
|
||||
* Looks up the appropriate RequestHandler
|
||||
* and then gets it to process the Client request.<P>
|
||||
* </p>
|
||||
* Note that this is a Runnable because it is assigned to the ThreadPool.
|
||||
*/
|
||||
class RequestProcessor implements Runnable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RequestProcessor.class.getName());
|
||||
|
||||
private final Socket clientSocket;
|
||||
|
||||
private final SocketClusterBroadcast owner;
|
||||
|
||||
/**
|
||||
* Create including the Listener (used to lookup the Request Handler) and
|
||||
* the socket itself.
|
||||
*/
|
||||
public RequestProcessor(SocketClusterBroadcast owner, Socket clientSocket) {
|
||||
this.clientSocket = clientSocket;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will parse out the command. Lookup the appropriate Handler and
|
||||
* pass the information to the handler for processing.
|
||||
* <P>Dev Note: the command parsing is processed here so that it is preformed
|
||||
* by the assigned thread rather than the listeners thread.</P>
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
SocketConnection sc = new SocketConnection(clientSocket);
|
||||
|
||||
while(true){
|
||||
if (owner.process(sc)) {
|
||||
// got the offline message or timeout
|
||||
break;
|
||||
}
|
||||
}
|
||||
sc.disconnect();
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -1,151 +1,134 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* The client side of the socket clustering.
|
||||
*/
|
||||
class SocketClient {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SocketClient.class.getName());
|
||||
|
||||
private final InetSocketAddress address;
|
||||
|
||||
private final String hostPort;
|
||||
|
||||
private boolean online;
|
||||
|
||||
private Socket socket;
|
||||
private OutputStream os;
|
||||
private ObjectOutputStream oos;
|
||||
|
||||
/**
|
||||
* Construct with an IP address and port.
|
||||
*/
|
||||
public SocketClient(InetSocketAddress address) {
|
||||
this.address = address;
|
||||
this.hostPort = address.getHostName()+":"+address.getPort();
|
||||
}
|
||||
|
||||
public String getHostPort() {
|
||||
return hostPort;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return address.getPort();
|
||||
}
|
||||
|
||||
public boolean isOnline() {
|
||||
return online;
|
||||
}
|
||||
|
||||
public void setOnline(boolean online) throws IOException {
|
||||
if (online){
|
||||
setOnline();
|
||||
} else {
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether the client is thought to be online.
|
||||
*/
|
||||
private void setOnline() throws IOException {
|
||||
connect();
|
||||
this.online = true;
|
||||
}
|
||||
|
||||
public void reconnect() throws IOException {
|
||||
disconnect();
|
||||
connect();
|
||||
}
|
||||
|
||||
private void connect() throws IOException {
|
||||
if (socket != null){
|
||||
throw new IllegalStateException("Already got a socket connection?");
|
||||
}
|
||||
Socket s = new Socket();
|
||||
s.setKeepAlive(true);
|
||||
s.connect(address);
|
||||
|
||||
this.socket = s;
|
||||
this.os = socket.getOutputStream();
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
this.online = false;
|
||||
if (socket != null){
|
||||
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
String msg = "Error disconnecting from Cluster member "+hostPort;
|
||||
logger.log(Level.INFO, msg, e);
|
||||
}
|
||||
|
||||
os = null;
|
||||
oos = null;
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean register(SocketClusterMessage registerMsg) {
|
||||
|
||||
try {
|
||||
setOnline();
|
||||
send(registerMsg);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean send(SocketClusterMessage msg) throws IOException {
|
||||
|
||||
if (online){
|
||||
writeObject(msg);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void writeObject(Object object) throws IOException {
|
||||
if (oos == null){
|
||||
this.oos = new ObjectOutputStream(os);
|
||||
}
|
||||
oos.writeObject(object);
|
||||
oos.flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* The client side of the socket clustering.
|
||||
*/
|
||||
class SocketClient {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SocketClient.class.getName());
|
||||
|
||||
private final InetSocketAddress address;
|
||||
|
||||
private final String hostPort;
|
||||
|
||||
private boolean online;
|
||||
|
||||
private Socket socket;
|
||||
private OutputStream os;
|
||||
private ObjectOutputStream oos;
|
||||
|
||||
/**
|
||||
* Construct with an IP address and port.
|
||||
*/
|
||||
public SocketClient(InetSocketAddress address) {
|
||||
this.address = address;
|
||||
this.hostPort = address.getHostName()+":"+address.getPort();
|
||||
}
|
||||
|
||||
public String getHostPort() {
|
||||
return hostPort;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return address.getPort();
|
||||
}
|
||||
|
||||
public boolean isOnline() {
|
||||
return online;
|
||||
}
|
||||
|
||||
public void setOnline(boolean online) throws IOException {
|
||||
if (online){
|
||||
setOnline();
|
||||
} else {
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether the client is thought to be online.
|
||||
*/
|
||||
private void setOnline() throws IOException {
|
||||
connect();
|
||||
this.online = true;
|
||||
}
|
||||
|
||||
public void reconnect() throws IOException {
|
||||
disconnect();
|
||||
connect();
|
||||
}
|
||||
|
||||
private void connect() throws IOException {
|
||||
if (socket != null){
|
||||
throw new IllegalStateException("Already got a socket connection?");
|
||||
}
|
||||
Socket s = new Socket();
|
||||
s.setKeepAlive(true);
|
||||
s.connect(address);
|
||||
|
||||
this.socket = s;
|
||||
this.os = socket.getOutputStream();
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
this.online = false;
|
||||
if (socket != null){
|
||||
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
String msg = "Error disconnecting from Cluster member "+hostPort;
|
||||
logger.log(Level.INFO, msg, e);
|
||||
}
|
||||
|
||||
os = null;
|
||||
oos = null;
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean register(SocketClusterMessage registerMsg) {
|
||||
|
||||
try {
|
||||
setOnline();
|
||||
send(registerMsg);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean send(SocketClusterMessage msg) throws IOException {
|
||||
|
||||
if (online){
|
||||
writeObject(msg);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void writeObject(Object object) throws IOException {
|
||||
if (oos == null){
|
||||
this.oos = new ObjectOutputStream(os);
|
||||
}
|
||||
oos.writeObject(object);
|
||||
oos.flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+248
-265
@@ -1,265 +1,248 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterBroadcast;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.cluster.DataHolder;
|
||||
import com.avaje.ebeaninternal.server.cluster.SerialiseTransactionHelper;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
/**
|
||||
* Broadcast messages across the cluster using sockets.
|
||||
*/
|
||||
public class SocketClusterBroadcast implements ClusterBroadcast {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SocketClusterBroadcast.class.getName());
|
||||
|
||||
private final SocketClient local;
|
||||
|
||||
private final HashMap<String,SocketClient> clientMap;
|
||||
|
||||
private final SocketClusterListener listener;
|
||||
|
||||
private SocketClient[] members;
|
||||
|
||||
private ClusterManager clusterManager;
|
||||
|
||||
private final TxnSerialiseHelper txnSerialiseHelper = new TxnSerialiseHelper();
|
||||
|
||||
private final AtomicInteger txnOutgoing = new AtomicInteger();
|
||||
private final AtomicInteger txnIncoming = new AtomicInteger();
|
||||
|
||||
|
||||
public SocketClusterBroadcast( ){
|
||||
|
||||
String localHostPort = GlobalProperties.get("ebean.cluster.local", null);
|
||||
String members = GlobalProperties.get("ebean.cluster.members", null);
|
||||
|
||||
logger.info("Clustering using Sockets local["+localHostPort+"] members["+members+"]");
|
||||
|
||||
this.local = new SocketClient(parseFullName(localHostPort));
|
||||
this.clientMap = new HashMap<String, SocketClient>();
|
||||
|
||||
String[] memArray = StringHelper.delimitedToArray(members, ",", false);
|
||||
for (int i = 0; i < memArray.length; i++) {
|
||||
InetSocketAddress member = parseFullName(memArray[i]);
|
||||
SocketClient client = new SocketClient(member);
|
||||
if (!local.getHostPort().equalsIgnoreCase(client.getHostPort())) {
|
||||
// don't add the local one ...
|
||||
clientMap.put(client.getHostPort(), client);
|
||||
}
|
||||
}
|
||||
|
||||
this.members = clientMap.values().toArray(new SocketClient[clientMap.size()]);
|
||||
this.listener = new SocketClusterListener(this, local.getPort());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current status of this instance.
|
||||
*/
|
||||
public SocketClusterStatus getStatus() {
|
||||
|
||||
// count of online members
|
||||
int currentGroupSize = 0;
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
if (members[i].isOnline()) {
|
||||
++currentGroupSize;
|
||||
}
|
||||
}
|
||||
int txnIn = txnIncoming.get();
|
||||
int txnOut = txnOutgoing.get();
|
||||
|
||||
return new SocketClusterStatus(currentGroupSize, txnIn, txnOut);
|
||||
}
|
||||
|
||||
public void startup(ClusterManager clusterManager) {
|
||||
|
||||
this.clusterManager = clusterManager;
|
||||
try {
|
||||
listener.startListening();
|
||||
register();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
deregister();
|
||||
listener.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register with all the other members of the Cluster.
|
||||
*/
|
||||
private void register() {
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), true);
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
boolean online = members[i].register(h);
|
||||
|
||||
String msg = "Cluster Member ["+members[i].getHostPort()+"] online["+online+"]";
|
||||
logger.info(msg);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setMemberOnline(String fullName, boolean online) throws IOException {
|
||||
synchronized (clientMap) {
|
||||
String msg = "Cluster Member ["+fullName+"] online["+online+"]";
|
||||
logger.info(msg);
|
||||
SocketClient member = clientMap.get(fullName);
|
||||
member.setOnline(online);
|
||||
}
|
||||
}
|
||||
|
||||
private void send(SocketClient client, SocketClusterMessage msg) {
|
||||
|
||||
try {
|
||||
// alternative would be to connect/disconnect here
|
||||
// but prefer to use keepalive
|
||||
client.send(msg);
|
||||
|
||||
} catch (Exception ex){
|
||||
logger.log(Level.SEVERE, "Error sending message", ex);
|
||||
try {
|
||||
client.reconnect();
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, "Error trying to reconnect", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the payload to all the members of the cluster.
|
||||
*/
|
||||
public void broadcast(RemoteTransactionEvent remoteTransEvent) {
|
||||
try {
|
||||
|
||||
txnOutgoing.incrementAndGet();
|
||||
DataHolder dataHolder = txnSerialiseHelper.createDataHolder(remoteTransEvent);
|
||||
SocketClusterMessage msg = SocketClusterMessage.transEvent(dataHolder);
|
||||
broadcast(msg);
|
||||
} catch (Exception e){
|
||||
String msg = "Error sending RemoteTransactionEvent "+remoteTransEvent+" to cluster members.";
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void broadcast(SocketClusterMessage msg) {
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
send(members[i], msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave the cluster.
|
||||
*/
|
||||
private void deregister() {
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), false);
|
||||
broadcast(h);
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
members[i].disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a Cluster message.
|
||||
*/
|
||||
protected boolean process(SocketConnection request) throws IOException, ClassNotFoundException {
|
||||
|
||||
try {
|
||||
SocketClusterMessage h = (SocketClusterMessage)request.readObject();
|
||||
|
||||
if (h.isRegisterEvent()){
|
||||
setMemberOnline(h.getRegisterHost(), h.isRegister());
|
||||
|
||||
} else {
|
||||
txnIncoming.incrementAndGet();
|
||||
DataHolder dataHolder = h.getDataHolder();
|
||||
RemoteTransactionEvent transEvent = txnSerialiseHelper.read(dataHolder);
|
||||
transEvent.run();
|
||||
}
|
||||
|
||||
if (h.isRegisterEvent() && !h.isRegister()){
|
||||
// instance shutting down
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (InterruptedIOException e) {
|
||||
String msg = "Timeout waiting for message";
|
||||
logger.log(Level.INFO, msg, e);
|
||||
try {
|
||||
request.disconnect();
|
||||
} catch (IOException ex){
|
||||
logger.log(Level.INFO, "Error disconnecting after timeout", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a host:port into a InetSocketAddress.
|
||||
*/
|
||||
private InetSocketAddress parseFullName(String hostAndPort) {
|
||||
|
||||
try {
|
||||
hostAndPort = hostAndPort.trim();
|
||||
int colonPos = hostAndPort.indexOf(":");
|
||||
if (colonPos == -1) {
|
||||
String msg = "No colon \":\" in "+hostAndPort;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
String host = hostAndPort.substring(0, colonPos);
|
||||
String sPort = hostAndPort.substring(colonPos + 1, hostAndPort.length());
|
||||
int port = Integer.parseInt(sPort);
|
||||
|
||||
return new InetSocketAddress(host, port);
|
||||
|
||||
} catch (Exception ex){
|
||||
throw new RuntimeException("Error parsing ["+hostAndPort+"] for the form [host:port]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
class TxnSerialiseHelper extends SerialiseTransactionHelper {
|
||||
|
||||
@Override
|
||||
public SpiEbeanServer getEbeanServer(String serverName) {
|
||||
return (SpiEbeanServer)clusterManager.getServer(serverName);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterBroadcast;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.cluster.DataHolder;
|
||||
import com.avaje.ebeaninternal.server.cluster.SerialiseTransactionHelper;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
/**
|
||||
* Broadcast messages across the cluster using sockets.
|
||||
*/
|
||||
public class SocketClusterBroadcast implements ClusterBroadcast {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SocketClusterBroadcast.class.getName());
|
||||
|
||||
private final SocketClient local;
|
||||
|
||||
private final HashMap<String,SocketClient> clientMap;
|
||||
|
||||
private final SocketClusterListener listener;
|
||||
|
||||
private SocketClient[] members;
|
||||
|
||||
private ClusterManager clusterManager;
|
||||
|
||||
private final TxnSerialiseHelper txnSerialiseHelper = new TxnSerialiseHelper();
|
||||
|
||||
private final AtomicInteger txnOutgoing = new AtomicInteger();
|
||||
private final AtomicInteger txnIncoming = new AtomicInteger();
|
||||
|
||||
|
||||
public SocketClusterBroadcast( ){
|
||||
|
||||
String localHostPort = GlobalProperties.get("ebean.cluster.local", null);
|
||||
String members = GlobalProperties.get("ebean.cluster.members", null);
|
||||
|
||||
logger.info("Clustering using Sockets local["+localHostPort+"] members["+members+"]");
|
||||
|
||||
this.local = new SocketClient(parseFullName(localHostPort));
|
||||
this.clientMap = new HashMap<String, SocketClient>();
|
||||
|
||||
String[] memArray = StringHelper.delimitedToArray(members, ",", false);
|
||||
for (int i = 0; i < memArray.length; i++) {
|
||||
InetSocketAddress member = parseFullName(memArray[i]);
|
||||
SocketClient client = new SocketClient(member);
|
||||
if (!local.getHostPort().equalsIgnoreCase(client.getHostPort())) {
|
||||
// don't add the local one ...
|
||||
clientMap.put(client.getHostPort(), client);
|
||||
}
|
||||
}
|
||||
|
||||
this.members = clientMap.values().toArray(new SocketClient[clientMap.size()]);
|
||||
this.listener = new SocketClusterListener(this, local.getPort());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current status of this instance.
|
||||
*/
|
||||
public SocketClusterStatus getStatus() {
|
||||
|
||||
// count of online members
|
||||
int currentGroupSize = 0;
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
if (members[i].isOnline()) {
|
||||
++currentGroupSize;
|
||||
}
|
||||
}
|
||||
int txnIn = txnIncoming.get();
|
||||
int txnOut = txnOutgoing.get();
|
||||
|
||||
return new SocketClusterStatus(currentGroupSize, txnIn, txnOut);
|
||||
}
|
||||
|
||||
public void startup(ClusterManager clusterManager) {
|
||||
|
||||
this.clusterManager = clusterManager;
|
||||
try {
|
||||
listener.startListening();
|
||||
register();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
deregister();
|
||||
listener.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register with all the other members of the Cluster.
|
||||
*/
|
||||
private void register() {
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), true);
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
boolean online = members[i].register(h);
|
||||
|
||||
String msg = "Cluster Member ["+members[i].getHostPort()+"] online["+online+"]";
|
||||
logger.info(msg);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setMemberOnline(String fullName, boolean online) throws IOException {
|
||||
synchronized (clientMap) {
|
||||
String msg = "Cluster Member ["+fullName+"] online["+online+"]";
|
||||
logger.info(msg);
|
||||
SocketClient member = clientMap.get(fullName);
|
||||
member.setOnline(online);
|
||||
}
|
||||
}
|
||||
|
||||
private void send(SocketClient client, SocketClusterMessage msg) {
|
||||
|
||||
try {
|
||||
// alternative would be to connect/disconnect here
|
||||
// but prefer to use keepalive
|
||||
client.send(msg);
|
||||
|
||||
} catch (Exception ex){
|
||||
logger.log(Level.SEVERE, "Error sending message", ex);
|
||||
try {
|
||||
client.reconnect();
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, "Error trying to reconnect", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the payload to all the members of the cluster.
|
||||
*/
|
||||
public void broadcast(RemoteTransactionEvent remoteTransEvent) {
|
||||
try {
|
||||
|
||||
txnOutgoing.incrementAndGet();
|
||||
DataHolder dataHolder = txnSerialiseHelper.createDataHolder(remoteTransEvent);
|
||||
SocketClusterMessage msg = SocketClusterMessage.transEvent(dataHolder);
|
||||
broadcast(msg);
|
||||
} catch (Exception e){
|
||||
String msg = "Error sending RemoteTransactionEvent "+remoteTransEvent+" to cluster members.";
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void broadcast(SocketClusterMessage msg) {
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
send(members[i], msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave the cluster.
|
||||
*/
|
||||
private void deregister() {
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), false);
|
||||
broadcast(h);
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
members[i].disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a Cluster message.
|
||||
*/
|
||||
protected boolean process(SocketConnection request) throws IOException, ClassNotFoundException {
|
||||
|
||||
try {
|
||||
SocketClusterMessage h = (SocketClusterMessage)request.readObject();
|
||||
|
||||
if (h.isRegisterEvent()){
|
||||
setMemberOnline(h.getRegisterHost(), h.isRegister());
|
||||
|
||||
} else {
|
||||
txnIncoming.incrementAndGet();
|
||||
DataHolder dataHolder = h.getDataHolder();
|
||||
RemoteTransactionEvent transEvent = txnSerialiseHelper.read(dataHolder);
|
||||
transEvent.run();
|
||||
}
|
||||
|
||||
if (h.isRegisterEvent() && !h.isRegister()){
|
||||
// instance shutting down
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (InterruptedIOException e) {
|
||||
String msg = "Timeout waiting for message";
|
||||
logger.log(Level.INFO, msg, e);
|
||||
try {
|
||||
request.disconnect();
|
||||
} catch (IOException ex){
|
||||
logger.log(Level.INFO, "Error disconnecting after timeout", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a host:port into a InetSocketAddress.
|
||||
*/
|
||||
private InetSocketAddress parseFullName(String hostAndPort) {
|
||||
|
||||
try {
|
||||
hostAndPort = hostAndPort.trim();
|
||||
int colonPos = hostAndPort.indexOf(":");
|
||||
if (colonPos == -1) {
|
||||
String msg = "No colon \":\" in "+hostAndPort;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
String host = hostAndPort.substring(0, colonPos);
|
||||
String sPort = hostAndPort.substring(colonPos + 1, hostAndPort.length());
|
||||
int port = Integer.parseInt(sPort);
|
||||
|
||||
return new InetSocketAddress(host, port);
|
||||
|
||||
} catch (Exception ex){
|
||||
throw new RuntimeException("Error parsing ["+hostAndPort+"] for the form [host:port]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
class TxnSerialiseHelper extends SerialiseTransactionHelper {
|
||||
|
||||
@Override
|
||||
public SpiEbeanServer getEbeanServer(String serverName) {
|
||||
return (SpiEbeanServer)clusterManager.getServer(serverName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+164
-181
@@ -1,181 +1,164 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPoolManager;
|
||||
|
||||
/**
|
||||
* Serverside multithreaded socket listener. Accepts connections and dispatches
|
||||
* them to an appropriate handler.
|
||||
* <p>
|
||||
* This is designed as a single port listener, where part of the connection
|
||||
* protocol determines which service the client is requesting (rather than a
|
||||
* port per service).
|
||||
* </p>
|
||||
* <p>
|
||||
* It has its own daemon background thread that handles the accept() loop on the
|
||||
* ServerSocket.
|
||||
* </p>
|
||||
*/
|
||||
class SocketClusterListener implements Runnable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SocketClusterListener.class.getName());
|
||||
|
||||
/**
|
||||
* The port the SocketListener uses.
|
||||
*/
|
||||
private final int port;
|
||||
|
||||
/**
|
||||
* The length of the socket accept timeout.
|
||||
*/
|
||||
private final int listenTimeout = 60000;
|
||||
|
||||
/**
|
||||
* The server socket used to listen for requests.
|
||||
*/
|
||||
private final ServerSocket serverListenSocket;
|
||||
|
||||
/**
|
||||
* The listening thread.
|
||||
*/
|
||||
private final Thread listenerThread;
|
||||
|
||||
/**
|
||||
* The pool of threads that actually do the parsing execution of requests.
|
||||
*/
|
||||
private final ThreadPool threadPool;
|
||||
|
||||
private final SocketClusterBroadcast owner;
|
||||
|
||||
/**
|
||||
* shutting down flag.
|
||||
*/
|
||||
boolean doingShutdown;
|
||||
|
||||
/**
|
||||
* Whether the listening thread is busy assigning a request to a thread.
|
||||
*/
|
||||
boolean isActive;
|
||||
|
||||
/**
|
||||
* Construct with a given thread pool name.
|
||||
*/
|
||||
public SocketClusterListener(SocketClusterBroadcast owner, int port) {
|
||||
this.owner = owner;
|
||||
this.threadPool = ThreadPoolManager.getThreadPool("EbeanClusterMember");
|
||||
this.port = port;
|
||||
|
||||
try {
|
||||
this.serverListenSocket = new ServerSocket(port);
|
||||
this.serverListenSocket.setSoTimeout(listenTimeout);
|
||||
this.listenerThread = new Thread(this, "EbeanClusterListener");
|
||||
|
||||
} catch (IOException e){
|
||||
String msg = "Error starting cluster socket listener on port "+port;
|
||||
throw new RuntimeException(msg,e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port the listener is using.
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening for requests.
|
||||
*/
|
||||
public void startListening() throws IOException {
|
||||
this.listenerThread.setDaemon(true);
|
||||
this.listenerThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this listener.
|
||||
*/
|
||||
public void shutdown() {
|
||||
doingShutdown = true;
|
||||
try {
|
||||
if (isActive) {
|
||||
synchronized (listenerThread) {
|
||||
try {
|
||||
listenerThread.wait(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// OK to ignore as expected to Interrupt for shutdown.
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
listenerThread.interrupt();
|
||||
serverListenSocket.close();
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a runnable and so this must be public. Don't call this externally
|
||||
* but rather call the startListening() method.
|
||||
*/
|
||||
public void run() {
|
||||
// run in loop until doingShutdown is true...
|
||||
while (!doingShutdown) {
|
||||
try {
|
||||
synchronized (listenerThread) {
|
||||
Socket clientSocket = serverListenSocket.accept();
|
||||
|
||||
isActive = true;
|
||||
|
||||
Runnable request = new RequestProcessor(owner, clientSocket);
|
||||
threadPool.assign(request, true);
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
if (doingShutdown) {
|
||||
String msg = "doingShutdown and accept threw:"+ e.getMessage();
|
||||
logger.info(msg);
|
||||
|
||||
} else {
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
|
||||
} catch (InterruptedIOException e) {
|
||||
// this will happen when the server is very quiet.
|
||||
// that is, no requests
|
||||
logger.fine("Possibly expected due to accept timeout?" + e.getMessage());
|
||||
|
||||
} catch (IOException e) {
|
||||
// log it and continue in the loop...
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPoolManager;
|
||||
|
||||
/**
|
||||
* Serverside multithreaded socket listener. Accepts connections and dispatches
|
||||
* them to an appropriate handler.
|
||||
* <p>
|
||||
* This is designed as a single port listener, where part of the connection
|
||||
* protocol determines which service the client is requesting (rather than a
|
||||
* port per service).
|
||||
* </p>
|
||||
* <p>
|
||||
* It has its own daemon background thread that handles the accept() loop on the
|
||||
* ServerSocket.
|
||||
* </p>
|
||||
*/
|
||||
class SocketClusterListener implements Runnable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SocketClusterListener.class.getName());
|
||||
|
||||
/**
|
||||
* The port the SocketListener uses.
|
||||
*/
|
||||
private final int port;
|
||||
|
||||
/**
|
||||
* The length of the socket accept timeout.
|
||||
*/
|
||||
private final int listenTimeout = 60000;
|
||||
|
||||
/**
|
||||
* The server socket used to listen for requests.
|
||||
*/
|
||||
private final ServerSocket serverListenSocket;
|
||||
|
||||
/**
|
||||
* The listening thread.
|
||||
*/
|
||||
private final Thread listenerThread;
|
||||
|
||||
/**
|
||||
* The pool of threads that actually do the parsing execution of requests.
|
||||
*/
|
||||
private final ThreadPool threadPool;
|
||||
|
||||
private final SocketClusterBroadcast owner;
|
||||
|
||||
/**
|
||||
* shutting down flag.
|
||||
*/
|
||||
boolean doingShutdown;
|
||||
|
||||
/**
|
||||
* Whether the listening thread is busy assigning a request to a thread.
|
||||
*/
|
||||
boolean isActive;
|
||||
|
||||
/**
|
||||
* Construct with a given thread pool name.
|
||||
*/
|
||||
public SocketClusterListener(SocketClusterBroadcast owner, int port) {
|
||||
this.owner = owner;
|
||||
this.threadPool = ThreadPoolManager.getThreadPool("EbeanClusterMember");
|
||||
this.port = port;
|
||||
|
||||
try {
|
||||
this.serverListenSocket = new ServerSocket(port);
|
||||
this.serverListenSocket.setSoTimeout(listenTimeout);
|
||||
this.listenerThread = new Thread(this, "EbeanClusterListener");
|
||||
|
||||
} catch (IOException e){
|
||||
String msg = "Error starting cluster socket listener on port "+port;
|
||||
throw new RuntimeException(msg,e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port the listener is using.
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening for requests.
|
||||
*/
|
||||
public void startListening() throws IOException {
|
||||
this.listenerThread.setDaemon(true);
|
||||
this.listenerThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this listener.
|
||||
*/
|
||||
public void shutdown() {
|
||||
doingShutdown = true;
|
||||
try {
|
||||
if (isActive) {
|
||||
synchronized (listenerThread) {
|
||||
try {
|
||||
listenerThread.wait(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// OK to ignore as expected to Interrupt for shutdown.
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
listenerThread.interrupt();
|
||||
serverListenSocket.close();
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a runnable and so this must be public. Don't call this externally
|
||||
* but rather call the startListening() method.
|
||||
*/
|
||||
public void run() {
|
||||
// run in loop until doingShutdown is true...
|
||||
while (!doingShutdown) {
|
||||
try {
|
||||
synchronized (listenerThread) {
|
||||
Socket clientSocket = serverListenSocket.accept();
|
||||
|
||||
isActive = true;
|
||||
|
||||
Runnable request = new RequestProcessor(owner, clientSocket);
|
||||
threadPool.assign(request, true);
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
if (doingShutdown) {
|
||||
String msg = "doingShutdown and accept threw:"+ e.getMessage();
|
||||
logger.info(msg);
|
||||
|
||||
} else {
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
|
||||
} catch (InterruptedIOException e) {
|
||||
// this will happen when the server is very quiet.
|
||||
// that is, no requests
|
||||
logger.fine("Possibly expected due to accept timeout?" + e.getMessage());
|
||||
|
||||
} catch (IOException e) {
|
||||
// log it and continue in the loop...
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+78
-95
@@ -1,95 +1,78 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.DataHolder;
|
||||
import com.avaje.ebeaninternal.server.cluster.Packet;
|
||||
|
||||
/**
|
||||
* The messages broadcast around the cluster.
|
||||
*/
|
||||
public class SocketClusterMessage implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2993350408394934473L;
|
||||
|
||||
private final String registerHost;
|
||||
|
||||
private final boolean register;
|
||||
|
||||
private final DataHolder dataHolder;
|
||||
|
||||
public static SocketClusterMessage register(String registerHost, boolean register){
|
||||
return new SocketClusterMessage(registerHost, register);
|
||||
}
|
||||
|
||||
public static SocketClusterMessage transEvent(DataHolder transEvent){
|
||||
return new SocketClusterMessage(transEvent);
|
||||
}
|
||||
|
||||
public static SocketClusterMessage packet(Packet packet){
|
||||
DataHolder d = new DataHolder(packet.getBytes());
|
||||
return new SocketClusterMessage(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to construct a Child AttributeMap.
|
||||
*/
|
||||
private SocketClusterMessage(String registerHost, boolean register) {
|
||||
this.registerHost = registerHost;
|
||||
this.register = register;
|
||||
this.dataHolder = null;
|
||||
}
|
||||
|
||||
private SocketClusterMessage(DataHolder dataHolder) {
|
||||
this.dataHolder = dataHolder;
|
||||
this.registerHost = null;
|
||||
this.register = false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (registerHost != null){
|
||||
sb.append("register ");
|
||||
sb.append(register);
|
||||
sb.append(" ");
|
||||
sb.append(registerHost);
|
||||
} else {
|
||||
sb.append("transEvent ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public boolean isRegisterEvent() {
|
||||
return registerHost != null;
|
||||
}
|
||||
|
||||
public String getRegisterHost() {
|
||||
return registerHost;
|
||||
}
|
||||
|
||||
public boolean isRegister() {
|
||||
return register;
|
||||
}
|
||||
|
||||
public DataHolder getDataHolder() {
|
||||
return dataHolder;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.DataHolder;
|
||||
import com.avaje.ebeaninternal.server.cluster.Packet;
|
||||
|
||||
/**
|
||||
* The messages broadcast around the cluster.
|
||||
*/
|
||||
public class SocketClusterMessage implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2993350408394934473L;
|
||||
|
||||
private final String registerHost;
|
||||
|
||||
private final boolean register;
|
||||
|
||||
private final DataHolder dataHolder;
|
||||
|
||||
public static SocketClusterMessage register(String registerHost, boolean register){
|
||||
return new SocketClusterMessage(registerHost, register);
|
||||
}
|
||||
|
||||
public static SocketClusterMessage transEvent(DataHolder transEvent){
|
||||
return new SocketClusterMessage(transEvent);
|
||||
}
|
||||
|
||||
public static SocketClusterMessage packet(Packet packet){
|
||||
DataHolder d = new DataHolder(packet.getBytes());
|
||||
return new SocketClusterMessage(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to construct a Child AttributeMap.
|
||||
*/
|
||||
private SocketClusterMessage(String registerHost, boolean register) {
|
||||
this.registerHost = registerHost;
|
||||
this.register = register;
|
||||
this.dataHolder = null;
|
||||
}
|
||||
|
||||
private SocketClusterMessage(DataHolder dataHolder) {
|
||||
this.dataHolder = dataHolder;
|
||||
this.registerHost = null;
|
||||
this.register = false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (registerHost != null){
|
||||
sb.append("register ");
|
||||
sb.append(register);
|
||||
sb.append(" ");
|
||||
sb.append(registerHost);
|
||||
} else {
|
||||
sb.append("transEvent ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public boolean isRegisterEvent() {
|
||||
return registerHost != null;
|
||||
}
|
||||
|
||||
public String getRegisterHost() {
|
||||
return registerHost;
|
||||
}
|
||||
|
||||
public boolean isRegister() {
|
||||
return register;
|
||||
}
|
||||
|
||||
public DataHolder getDataHolder() {
|
||||
return dataHolder;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+41
-60
@@ -1,60 +1,41 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
/**
|
||||
* The current state of this cluster member.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class SocketClusterStatus {
|
||||
|
||||
private final int currentGroupSize;
|
||||
private final int txnIncoming;
|
||||
private final int txtOutgoing;
|
||||
|
||||
public SocketClusterStatus(int currentGroupSize, int txnIncoming, int txnOutgoing) {
|
||||
this.currentGroupSize = currentGroupSize;
|
||||
this.txnIncoming = txnIncoming;
|
||||
this.txtOutgoing = txnOutgoing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of members of the cluster currently online.
|
||||
*/
|
||||
public int getCurrentGroupSize() {
|
||||
return currentGroupSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of Remote transactions received.
|
||||
*/
|
||||
public int getTxnIncoming() {
|
||||
return txnIncoming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of transactions sent to the cluster.
|
||||
*/
|
||||
public int getTxtOutgoing() {
|
||||
return txtOutgoing;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
/**
|
||||
* The current state of this cluster member.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class SocketClusterStatus {
|
||||
|
||||
private final int currentGroupSize;
|
||||
private final int txnIncoming;
|
||||
private final int txtOutgoing;
|
||||
|
||||
public SocketClusterStatus(int currentGroupSize, int txnIncoming, int txnOutgoing) {
|
||||
this.currentGroupSize = currentGroupSize;
|
||||
this.txnIncoming = txnIncoming;
|
||||
this.txtOutgoing = txnOutgoing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of members of the cluster currently online.
|
||||
*/
|
||||
public int getCurrentGroupSize() {
|
||||
return currentGroupSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of Remote transactions received.
|
||||
*/
|
||||
public int getTxnIncoming() {
|
||||
return txnIncoming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of transactions sent to the cluster.
|
||||
*/
|
||||
public int getTxtOutgoing() {
|
||||
return txtOutgoing;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+129
-146
@@ -1,146 +1,129 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This library 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 library 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* The client side of a TCP Sockect connection.
|
||||
*/
|
||||
class SocketConnection {
|
||||
|
||||
/**
|
||||
* The object underlying objectOutputStream.
|
||||
*/
|
||||
ObjectOutputStream oos;
|
||||
|
||||
/**
|
||||
* The underlying ObjectInputStream.
|
||||
*/
|
||||
ObjectInputStream ois;
|
||||
|
||||
/**
|
||||
* The underlying inputStream.
|
||||
*/
|
||||
InputStream is;
|
||||
|
||||
/**
|
||||
* The underlying outputStream.
|
||||
*/
|
||||
OutputStream os;
|
||||
|
||||
/**
|
||||
* The underlying socket.
|
||||
*/
|
||||
Socket socket;
|
||||
|
||||
/**
|
||||
* Create for a given Socket.
|
||||
*/
|
||||
public SocketConnection(Socket socket) throws IOException {
|
||||
this.is = socket.getInputStream();
|
||||
this.os = socket.getOutputStream();
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the server.
|
||||
*/
|
||||
public void disconnect() throws IOException {
|
||||
os.flush();
|
||||
socket.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the outputStream.
|
||||
*/
|
||||
public void flush() throws IOException {
|
||||
os.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an object from the object input stream.
|
||||
*/
|
||||
public Object readObject() throws IOException, ClassNotFoundException {
|
||||
return getObjectInputStream().readObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an object to the object output stream.
|
||||
*/
|
||||
public ObjectOutputStream writeObject(Object object) throws IOException {
|
||||
ObjectOutputStream oos = getObjectOutputStream();
|
||||
oos.writeObject(object);
|
||||
return oos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object output stream.
|
||||
*/
|
||||
public ObjectOutputStream getObjectOutputStream() throws IOException {
|
||||
if (oos == null){
|
||||
oos = new ObjectOutputStream(os);
|
||||
}
|
||||
return oos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object input stream.
|
||||
*/
|
||||
public ObjectInputStream getObjectInputStream() throws IOException {
|
||||
if (ois == null){
|
||||
ois = new ObjectInputStream(is);
|
||||
}
|
||||
return ois;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the ObjectInputStream to use.
|
||||
*/
|
||||
public void setObjectInputStream(ObjectInputStream ois) {
|
||||
this.ois = ois;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ObjectOutputStream to use.
|
||||
*/
|
||||
public void setObjectOutputStream(ObjectOutputStream oos) {
|
||||
this.oos = oos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying input stream.
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying output stream.
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* The client side of a TCP Sockect connection.
|
||||
*/
|
||||
class SocketConnection {
|
||||
|
||||
/**
|
||||
* The object underlying objectOutputStream.
|
||||
*/
|
||||
ObjectOutputStream oos;
|
||||
|
||||
/**
|
||||
* The underlying ObjectInputStream.
|
||||
*/
|
||||
ObjectInputStream ois;
|
||||
|
||||
/**
|
||||
* The underlying inputStream.
|
||||
*/
|
||||
InputStream is;
|
||||
|
||||
/**
|
||||
* The underlying outputStream.
|
||||
*/
|
||||
OutputStream os;
|
||||
|
||||
/**
|
||||
* The underlying socket.
|
||||
*/
|
||||
Socket socket;
|
||||
|
||||
/**
|
||||
* Create for a given Socket.
|
||||
*/
|
||||
public SocketConnection(Socket socket) throws IOException {
|
||||
this.is = socket.getInputStream();
|
||||
this.os = socket.getOutputStream();
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the server.
|
||||
*/
|
||||
public void disconnect() throws IOException {
|
||||
os.flush();
|
||||
socket.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the outputStream.
|
||||
*/
|
||||
public void flush() throws IOException {
|
||||
os.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an object from the object input stream.
|
||||
*/
|
||||
public Object readObject() throws IOException, ClassNotFoundException {
|
||||
return getObjectInputStream().readObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an object to the object output stream.
|
||||
*/
|
||||
public ObjectOutputStream writeObject(Object object) throws IOException {
|
||||
ObjectOutputStream oos = getObjectOutputStream();
|
||||
oos.writeObject(object);
|
||||
return oos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object output stream.
|
||||
*/
|
||||
public ObjectOutputStream getObjectOutputStream() throws IOException {
|
||||
if (oos == null){
|
||||
oos = new ObjectOutputStream(os);
|
||||
}
|
||||
return oos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object input stream.
|
||||
*/
|
||||
public ObjectInputStream getObjectInputStream() throws IOException {
|
||||
if (ois == null){
|
||||
ois = new ObjectInputStream(is);
|
||||
}
|
||||
return ois;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the ObjectInputStream to use.
|
||||
*/
|
||||
public void setObjectInputStream(ObjectInputStream ois) {
|
||||
this.ois = ois;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ObjectOutputStream to use.
|
||||
*/
|
||||
public void setObjectOutputStream(ObjectOutputStream oos) {
|
||||
this.oos = oos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying input stream.
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying output stream.
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,493 +1,474 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.util.Calendar;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of TypeConverter.
|
||||
* <p>
|
||||
* Converts objects to the required type if required.
|
||||
* </p>
|
||||
*/
|
||||
public final class BasicTypeConverter implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7691463236204070311L;
|
||||
|
||||
/**
|
||||
* Type code for java.util.Calendar.
|
||||
*/
|
||||
public static final int UTIL_CALENDAR = -999998986;
|
||||
|
||||
/**
|
||||
* Type code for java.util.Date.
|
||||
*/
|
||||
public static final int UTIL_DATE = -999998988;
|
||||
|
||||
/**
|
||||
* Type code for java.math.BigInteger.
|
||||
*/
|
||||
public static final int MATH_BIGINTEGER = -999998987;
|
||||
|
||||
/**
|
||||
* Type code for an Enum type.
|
||||
*/
|
||||
public static final int ENUM = -999998989;
|
||||
|
||||
private BasicTypeConverter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the Object to the required data type.
|
||||
*
|
||||
* @param value
|
||||
* the Object value
|
||||
* @param toDataType
|
||||
* the dataType as per java.sql.Types.
|
||||
*/
|
||||
public static Object convert(Object value, int toDataType) {
|
||||
|
||||
try {
|
||||
switch (toDataType) {
|
||||
case UTIL_DATE: {
|
||||
return toUtilDate(value);
|
||||
}
|
||||
case UTIL_CALENDAR: {
|
||||
return toCalendar(value);
|
||||
}
|
||||
case Types.BIGINT: {
|
||||
return toLong(value);
|
||||
}
|
||||
case Types.INTEGER: {
|
||||
return toInteger(value);
|
||||
}
|
||||
case Types.BIT: {
|
||||
return toBoolean(value);
|
||||
}
|
||||
case Types.TINYINT: {
|
||||
return toByte(value);
|
||||
}
|
||||
case Types.SMALLINT: {
|
||||
return toShort(value);
|
||||
}
|
||||
case Types.NUMERIC: {
|
||||
return toBigDecimal(value);
|
||||
}
|
||||
case Types.DECIMAL: {
|
||||
return toBigDecimal(value);
|
||||
}
|
||||
case Types.REAL: {
|
||||
return toFloat(value);
|
||||
}
|
||||
case Types.DOUBLE: {
|
||||
return toDouble(value);
|
||||
}
|
||||
case Types.FLOAT: {
|
||||
return toDouble(value);
|
||||
}
|
||||
case Types.BOOLEAN: {
|
||||
return toBoolean(value);
|
||||
}
|
||||
case Types.TIMESTAMP: {
|
||||
return toTimestamp(value);
|
||||
}
|
||||
case Types.DATE: {
|
||||
return toDate(value);
|
||||
}
|
||||
case Types.VARCHAR: {
|
||||
return toString(value);
|
||||
}
|
||||
case Types.CHAR: {
|
||||
return toString(value);
|
||||
}
|
||||
case Types.OTHER: {
|
||||
return value;
|
||||
}
|
||||
case Types.JAVA_OBJECT: {
|
||||
return value;
|
||||
}
|
||||
case Types.BINARY:
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.BLOB: {
|
||||
return value;
|
||||
}
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.CLOB: {
|
||||
return value;
|
||||
}
|
||||
default: {
|
||||
String msg = "Unhandled data type [" + toDataType + "] converting [" + value + "]";
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
} catch (ClassCastException e) {
|
||||
String m = "ClassCastException converting to data type [" + toDataType + "] value [" + value + "]";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a String.
|
||||
*/
|
||||
public static String toString(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return (String) value;
|
||||
}
|
||||
if (value instanceof char[]) {
|
||||
return String.valueOf((char[]) value);
|
||||
}
|
||||
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the value to a Boolean with an explicit String true value.
|
||||
*/
|
||||
public static Boolean toBoolean(Object value, String dbTrueValue) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
String s = value.toString();
|
||||
return s.equalsIgnoreCase(dbTrueValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a Boolean. Can be a Boolean or the string values
|
||||
* "true" or "false".
|
||||
*/
|
||||
public static Boolean toBoolean(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
|
||||
return Boolean.valueOf(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a UUID.
|
||||
*/
|
||||
public static UUID toUUID(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return UUID.fromString((String) value);
|
||||
}
|
||||
return (UUID) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a BigDecimal. It should be another
|
||||
* numeric type.
|
||||
*/
|
||||
public static BigDecimal toBigDecimal(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof BigDecimal) {
|
||||
return (BigDecimal) value;
|
||||
}
|
||||
return new BigDecimal(value.toString());
|
||||
}
|
||||
|
||||
public static Float toFloat(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Float) {
|
||||
return (Float) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return Float.valueOf(((Number) value).floatValue());
|
||||
}
|
||||
return Float.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public static Short toShort(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Short) {
|
||||
return (Short) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return Short.valueOf(((Number) value).shortValue());
|
||||
}
|
||||
return Short.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public static Byte toByte(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Byte) {
|
||||
return (Byte) value;
|
||||
}
|
||||
return Byte.valueOf(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a Integer. It should be another numeric
|
||||
* type.
|
||||
*/
|
||||
public static Integer toInteger(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
return (Integer) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return Integer.valueOf(((Number) value).intValue());
|
||||
}
|
||||
return Integer.valueOf(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object to a Long. It should be another numeric type.
|
||||
*/
|
||||
public static Long toLong(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Long) {
|
||||
return (Long) value;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return Long.valueOf((String) value);
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return Long.valueOf(((Number) value).longValue());
|
||||
}
|
||||
if (value instanceof java.util.Date) {
|
||||
return Long.valueOf(((java.util.Date) value).getTime());
|
||||
}
|
||||
if (value instanceof Calendar) {
|
||||
return Long.valueOf(((Calendar) value).getTime().getTime());
|
||||
}
|
||||
return Long.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public static BigInteger toMathBigInteger(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof BigInteger) {
|
||||
return (BigInteger) value;
|
||||
}
|
||||
return new BigInteger(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object to a Double. It should be another numberic type.
|
||||
*/
|
||||
public static Double toDouble(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Double) {
|
||||
return (Double) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return Double.valueOf(((Number) value).doubleValue());
|
||||
}
|
||||
return Double.valueOf(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a Timestamp. It is expected to be a
|
||||
* java.sql.Date really.
|
||||
*/
|
||||
public static Timestamp toTimestamp(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Timestamp) {
|
||||
return (Timestamp) value;
|
||||
|
||||
} else if (value instanceof java.util.Date) {
|
||||
// no nanos here... so hopefully ok
|
||||
return new Timestamp(((java.util.Date) value).getTime());
|
||||
|
||||
} else if (value instanceof Calendar) {
|
||||
return new Timestamp(((Calendar) value).getTime().getTime());
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return Timestamp.valueOf((String) value);
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
return new Timestamp(((Number) value).longValue());
|
||||
|
||||
} else {
|
||||
String msg = "Unable to convert [" + value.getClass().getName() + "] into a Timestamp.";
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static java.sql.Time toTime(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Time) {
|
||||
return (java.sql.Time) value;
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return java.sql.Time.valueOf((String) value);
|
||||
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.sql.Date.";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static java.sql.Date toDate(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Date) {
|
||||
return (java.sql.Date) value;
|
||||
|
||||
} else if (value instanceof java.util.Date) {
|
||||
return new java.sql.Date(((java.util.Date) value).getTime());
|
||||
|
||||
} else if (value instanceof Calendar) {
|
||||
return new java.sql.Date(((Calendar) value).getTime().getTime());
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return java.sql.Date.valueOf((String) value);
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
return new java.sql.Date(((Number) value).longValue());
|
||||
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.sql.Date.";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static java.util.Date toUtilDate(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Timestamp) {
|
||||
// loss of nanos precision
|
||||
return new java.util.Date(((java.sql.Timestamp) value).getTime());
|
||||
}
|
||||
// DEVNOTE: strictly speaking do I need to convert a java.sql.Date to
|
||||
// java.util.Date? equals() is symmetrical so perhaps this is not
|
||||
// really required?
|
||||
if (value instanceof java.sql.Date) {
|
||||
return new java.util.Date(((java.sql.Date) value).getTime());
|
||||
}
|
||||
if (value instanceof java.util.Date) {
|
||||
return (java.util.Date) value;
|
||||
|
||||
} else if (value instanceof Calendar) {
|
||||
return ((Calendar) value).getTime();
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return new java.util.Date(Timestamp.valueOf((String) value).getTime());
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
return new java.util.Date(((Number) value).longValue());
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unable to convert [" + value.getClass().getName() + "] into a java.util.Date");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static Calendar toCalendar(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Calendar) {
|
||||
return (Calendar) value;
|
||||
|
||||
} else if (value instanceof java.util.Date) {
|
||||
java.util.Date date = ((java.util.Date) value);
|
||||
return toCalendarFromDate(date);
|
||||
|
||||
} else if (value instanceof String) {
|
||||
java.util.Date date = toUtilDate(value);
|
||||
return toCalendarFromDate(date);
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
long timeMillis = ((Number) value).longValue();
|
||||
java.util.Date date = new java.util.Date(timeMillis);
|
||||
return toCalendarFromDate(date);
|
||||
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.util.Date";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
private static Calendar toCalendarFromDate(java.util.Date date) {
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(date);
|
||||
|
||||
return cal;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.util.Calendar;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of TypeConverter.
|
||||
* <p>
|
||||
* Converts objects to the required type if required.
|
||||
* </p>
|
||||
*/
|
||||
public final class BasicTypeConverter implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7691463236204070311L;
|
||||
|
||||
/**
|
||||
* Type code for java.util.Calendar.
|
||||
*/
|
||||
public static final int UTIL_CALENDAR = -999998986;
|
||||
|
||||
/**
|
||||
* Type code for java.util.Date.
|
||||
*/
|
||||
public static final int UTIL_DATE = -999998988;
|
||||
|
||||
/**
|
||||
* Type code for java.math.BigInteger.
|
||||
*/
|
||||
public static final int MATH_BIGINTEGER = -999998987;
|
||||
|
||||
/**
|
||||
* Type code for an Enum type.
|
||||
*/
|
||||
public static final int ENUM = -999998989;
|
||||
|
||||
private BasicTypeConverter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the Object to the required data type.
|
||||
*
|
||||
* @param value
|
||||
* the Object value
|
||||
* @param toDataType
|
||||
* the dataType as per java.sql.Types.
|
||||
*/
|
||||
public static Object convert(Object value, int toDataType) {
|
||||
|
||||
try {
|
||||
switch (toDataType) {
|
||||
case UTIL_DATE: {
|
||||
return toUtilDate(value);
|
||||
}
|
||||
case UTIL_CALENDAR: {
|
||||
return toCalendar(value);
|
||||
}
|
||||
case Types.BIGINT: {
|
||||
return toLong(value);
|
||||
}
|
||||
case Types.INTEGER: {
|
||||
return toInteger(value);
|
||||
}
|
||||
case Types.BIT: {
|
||||
return toBoolean(value);
|
||||
}
|
||||
case Types.TINYINT: {
|
||||
return toByte(value);
|
||||
}
|
||||
case Types.SMALLINT: {
|
||||
return toShort(value);
|
||||
}
|
||||
case Types.NUMERIC: {
|
||||
return toBigDecimal(value);
|
||||
}
|
||||
case Types.DECIMAL: {
|
||||
return toBigDecimal(value);
|
||||
}
|
||||
case Types.REAL: {
|
||||
return toFloat(value);
|
||||
}
|
||||
case Types.DOUBLE: {
|
||||
return toDouble(value);
|
||||
}
|
||||
case Types.FLOAT: {
|
||||
return toDouble(value);
|
||||
}
|
||||
case Types.BOOLEAN: {
|
||||
return toBoolean(value);
|
||||
}
|
||||
case Types.TIMESTAMP: {
|
||||
return toTimestamp(value);
|
||||
}
|
||||
case Types.DATE: {
|
||||
return toDate(value);
|
||||
}
|
||||
case Types.VARCHAR: {
|
||||
return toString(value);
|
||||
}
|
||||
case Types.CHAR: {
|
||||
return toString(value);
|
||||
}
|
||||
case Types.OTHER: {
|
||||
return value;
|
||||
}
|
||||
case Types.JAVA_OBJECT: {
|
||||
return value;
|
||||
}
|
||||
case Types.BINARY:
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.BLOB: {
|
||||
return value;
|
||||
}
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.CLOB: {
|
||||
return value;
|
||||
}
|
||||
default: {
|
||||
String msg = "Unhandled data type [" + toDataType + "] converting [" + value + "]";
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
} catch (ClassCastException e) {
|
||||
String m = "ClassCastException converting to data type [" + toDataType + "] value [" + value + "]";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a String.
|
||||
*/
|
||||
public static String toString(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return (String) value;
|
||||
}
|
||||
if (value instanceof char[]) {
|
||||
return String.valueOf((char[]) value);
|
||||
}
|
||||
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the value to a Boolean with an explicit String true value.
|
||||
*/
|
||||
public static Boolean toBoolean(Object value, String dbTrueValue) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
String s = value.toString();
|
||||
return s.equalsIgnoreCase(dbTrueValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a Boolean. Can be a Boolean or the string values
|
||||
* "true" or "false".
|
||||
*/
|
||||
public static Boolean toBoolean(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
|
||||
return Boolean.valueOf(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a UUID.
|
||||
*/
|
||||
public static UUID toUUID(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return UUID.fromString((String) value);
|
||||
}
|
||||
return (UUID) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a BigDecimal. It should be another
|
||||
* numeric type.
|
||||
*/
|
||||
public static BigDecimal toBigDecimal(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof BigDecimal) {
|
||||
return (BigDecimal) value;
|
||||
}
|
||||
return new BigDecimal(value.toString());
|
||||
}
|
||||
|
||||
public static Float toFloat(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Float) {
|
||||
return (Float) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return Float.valueOf(((Number) value).floatValue());
|
||||
}
|
||||
return Float.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public static Short toShort(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Short) {
|
||||
return (Short) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return Short.valueOf(((Number) value).shortValue());
|
||||
}
|
||||
return Short.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public static Byte toByte(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Byte) {
|
||||
return (Byte) value;
|
||||
}
|
||||
return Byte.valueOf(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a Integer. It should be another numeric
|
||||
* type.
|
||||
*/
|
||||
public static Integer toInteger(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
return (Integer) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return Integer.valueOf(((Number) value).intValue());
|
||||
}
|
||||
return Integer.valueOf(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object to a Long. It should be another numeric type.
|
||||
*/
|
||||
public static Long toLong(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Long) {
|
||||
return (Long) value;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return Long.valueOf((String) value);
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return Long.valueOf(((Number) value).longValue());
|
||||
}
|
||||
if (value instanceof java.util.Date) {
|
||||
return Long.valueOf(((java.util.Date) value).getTime());
|
||||
}
|
||||
if (value instanceof Calendar) {
|
||||
return Long.valueOf(((Calendar) value).getTime().getTime());
|
||||
}
|
||||
return Long.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public static BigInteger toMathBigInteger(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof BigInteger) {
|
||||
return (BigInteger) value;
|
||||
}
|
||||
return new BigInteger(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object to a Double. It should be another numberic type.
|
||||
*/
|
||||
public static Double toDouble(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Double) {
|
||||
return (Double) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return Double.valueOf(((Number) value).doubleValue());
|
||||
}
|
||||
return Double.valueOf(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a Timestamp. It is expected to be a
|
||||
* java.sql.Date really.
|
||||
*/
|
||||
public static Timestamp toTimestamp(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Timestamp) {
|
||||
return (Timestamp) value;
|
||||
|
||||
} else if (value instanceof java.util.Date) {
|
||||
// no nanos here... so hopefully ok
|
||||
return new Timestamp(((java.util.Date) value).getTime());
|
||||
|
||||
} else if (value instanceof Calendar) {
|
||||
return new Timestamp(((Calendar) value).getTime().getTime());
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return Timestamp.valueOf((String) value);
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
return new Timestamp(((Number) value).longValue());
|
||||
|
||||
} else {
|
||||
String msg = "Unable to convert [" + value.getClass().getName() + "] into a Timestamp.";
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static java.sql.Time toTime(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Time) {
|
||||
return (java.sql.Time) value;
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return java.sql.Time.valueOf((String) value);
|
||||
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.sql.Date.";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static java.sql.Date toDate(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Date) {
|
||||
return (java.sql.Date) value;
|
||||
|
||||
} else if (value instanceof java.util.Date) {
|
||||
return new java.sql.Date(((java.util.Date) value).getTime());
|
||||
|
||||
} else if (value instanceof Calendar) {
|
||||
return new java.sql.Date(((Calendar) value).getTime().getTime());
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return java.sql.Date.valueOf((String) value);
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
return new java.sql.Date(((Number) value).longValue());
|
||||
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.sql.Date.";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static java.util.Date toUtilDate(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Timestamp) {
|
||||
// loss of nanos precision
|
||||
return new java.util.Date(((java.sql.Timestamp) value).getTime());
|
||||
}
|
||||
// DEVNOTE: strictly speaking do I need to convert a java.sql.Date to
|
||||
// java.util.Date? equals() is symmetrical so perhaps this is not
|
||||
// really required?
|
||||
if (value instanceof java.sql.Date) {
|
||||
return new java.util.Date(((java.sql.Date) value).getTime());
|
||||
}
|
||||
if (value instanceof java.util.Date) {
|
||||
return (java.util.Date) value;
|
||||
|
||||
} else if (value instanceof Calendar) {
|
||||
return ((Calendar) value).getTime();
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return new java.util.Date(Timestamp.valueOf((String) value).getTime());
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
return new java.util.Date(((Number) value).longValue());
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unable to convert [" + value.getClass().getName() + "] into a java.util.Date");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static Calendar toCalendar(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Calendar) {
|
||||
return (Calendar) value;
|
||||
|
||||
} else if (value instanceof java.util.Date) {
|
||||
java.util.Date date = ((java.util.Date) value);
|
||||
return toCalendarFromDate(date);
|
||||
|
||||
} else if (value instanceof String) {
|
||||
java.util.Date date = toUtilDate(value);
|
||||
return toCalendarFromDate(date);
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
long timeMillis = ((Number) value).longValue();
|
||||
java.util.Date date = new java.util.Date(timeMillis);
|
||||
return toCalendarFromDate(date);
|
||||
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.util.Date";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
private static Calendar toCalendarFromDate(java.util.Date date) {
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(date);
|
||||
|
||||
return cal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,146 +1,127 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.LogLevel;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
|
||||
/**
|
||||
* Base class for find and persist requests.
|
||||
*/
|
||||
public abstract class BeanRequest {
|
||||
|
||||
/**
|
||||
* The server processing the request.
|
||||
*/
|
||||
final SpiEbeanServer ebeanServer;
|
||||
|
||||
final String serverName;
|
||||
|
||||
/**
|
||||
* The transaction this is part of.
|
||||
*/
|
||||
SpiTransaction transaction;
|
||||
|
||||
boolean createdTransaction;
|
||||
|
||||
boolean readOnly;
|
||||
|
||||
public BeanRequest(SpiEbeanServer ebeanServer, SpiTransaction t) {
|
||||
this.ebeanServer = ebeanServer;
|
||||
this.serverName = ebeanServer.getName();
|
||||
this.transaction = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* initialise an implicit transaction if one is not currently supplied.
|
||||
* <p>
|
||||
* A transaction may have been passed in or active in the thread local. If
|
||||
* not then create one implicitly to handle the request.
|
||||
* </p>
|
||||
*/
|
||||
public abstract void initTransIfRequired();
|
||||
|
||||
/**
|
||||
* A helper method for creating an implicit transaction is it is required.
|
||||
* <p>
|
||||
* A transaction may have been passed in or active in the thread local. If
|
||||
* not then create one implicitly to handle the request.
|
||||
* </p>
|
||||
*/
|
||||
public void createImplicitTransIfRequired(boolean readOnlyTransaction) {
|
||||
if (transaction == null) {
|
||||
transaction = ebeanServer.getCurrentServerTransaction();
|
||||
if (transaction == null || !transaction.isActive()) {
|
||||
// create an implicit transaction to execute this query
|
||||
transaction = ebeanServer.createServerTransaction(false, -1);
|
||||
// commented out for performance reasons...
|
||||
// TODO: review performance of trans.setReadOnly(true)
|
||||
//if (readOnlyTransaction) {
|
||||
// readOnly = true;
|
||||
// transaction.setReadOnly(true);
|
||||
//}
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit this transaction if it was created for this request.
|
||||
*/
|
||||
public void commitTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
if (readOnly) {
|
||||
transaction.rollback();
|
||||
} else {
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if it was created for this request.
|
||||
*/
|
||||
public void rollbackTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
transaction.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server processing the request. Made available for
|
||||
* BeanController and BeanFinder.
|
||||
*/
|
||||
public EbeanServer getEbeanServer() {
|
||||
return ebeanServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Transaction associated with this request.
|
||||
*/
|
||||
public SpiTransaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection from the Transaction.
|
||||
*/
|
||||
public Connection getConnection() {
|
||||
return transaction.getInternalConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if SQL should be logged for this transaction.
|
||||
*/
|
||||
public boolean isLogSql() {
|
||||
return transaction.getLogLevel().ordinal() >= LogLevel.SQL.ordinal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if SUMMARY information should be logged for this transaction.
|
||||
*/
|
||||
public boolean isLogSummary() {
|
||||
return transaction.getLogLevel().ordinal() >= LogLevel.SUMMARY.ordinal();
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.LogLevel;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
|
||||
/**
|
||||
* Base class for find and persist requests.
|
||||
*/
|
||||
public abstract class BeanRequest {
|
||||
|
||||
/**
|
||||
* The server processing the request.
|
||||
*/
|
||||
final SpiEbeanServer ebeanServer;
|
||||
|
||||
final String serverName;
|
||||
|
||||
/**
|
||||
* The transaction this is part of.
|
||||
*/
|
||||
SpiTransaction transaction;
|
||||
|
||||
boolean createdTransaction;
|
||||
|
||||
boolean readOnly;
|
||||
|
||||
public BeanRequest(SpiEbeanServer ebeanServer, SpiTransaction t) {
|
||||
this.ebeanServer = ebeanServer;
|
||||
this.serverName = ebeanServer.getName();
|
||||
this.transaction = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* initialise an implicit transaction if one is not currently supplied.
|
||||
* <p>
|
||||
* A transaction may have been passed in or active in the thread local. If
|
||||
* not then create one implicitly to handle the request.
|
||||
* </p>
|
||||
*/
|
||||
public abstract void initTransIfRequired();
|
||||
|
||||
/**
|
||||
* A helper method for creating an implicit transaction is it is required.
|
||||
* <p>
|
||||
* A transaction may have been passed in or active in the thread local. If
|
||||
* not then create one implicitly to handle the request.
|
||||
* </p>
|
||||
*/
|
||||
public void createImplicitTransIfRequired(boolean readOnlyTransaction) {
|
||||
if (transaction == null) {
|
||||
transaction = ebeanServer.getCurrentServerTransaction();
|
||||
if (transaction == null || !transaction.isActive()) {
|
||||
// create an implicit transaction to execute this query
|
||||
transaction = ebeanServer.createServerTransaction(false, -1);
|
||||
// commented out for performance reasons...
|
||||
// TODO: review performance of trans.setReadOnly(true)
|
||||
//if (readOnlyTransaction) {
|
||||
// readOnly = true;
|
||||
// transaction.setReadOnly(true);
|
||||
//}
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit this transaction if it was created for this request.
|
||||
*/
|
||||
public void commitTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
if (readOnly) {
|
||||
transaction.rollback();
|
||||
} else {
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if it was created for this request.
|
||||
*/
|
||||
public void rollbackTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
transaction.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server processing the request. Made available for
|
||||
* BeanController and BeanFinder.
|
||||
*/
|
||||
public EbeanServer getEbeanServer() {
|
||||
return ebeanServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Transaction associated with this request.
|
||||
*/
|
||||
public SpiTransaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection from the Transaction.
|
||||
*/
|
||||
public Connection getConnection() {
|
||||
return transaction.getInternalConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if SQL should be logged for this transaction.
|
||||
*/
|
||||
public boolean isLogSql() {
|
||||
return transaction.getLogLevel().ordinal() >= LogLevel.SQL.ordinal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if SUMMARY information should be logged for this transaction.
|
||||
*/
|
||||
public boolean isLogSummary() {
|
||||
return transaction.getLogLevel().ordinal() >= LogLevel.SUMMARY.ordinal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,460 +1,441 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import com.avaje.ebean.annotation.LdapDomain;
|
||||
import com.avaje.ebean.config.CompoundType;
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.ServerConfigStartup;
|
||||
import com.avaje.ebean.event.TransactionEventListener;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
|
||||
|
||||
/**
|
||||
* Interesting classes for a EbeanServer such as Embeddable, Entity,
|
||||
* ScalarTypes, Finders, Listeners and Controllers.
|
||||
*/
|
||||
public class BootupClasses implements ClassPathSearchMatcher {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(BootupClasses.class.getName());
|
||||
|
||||
private ArrayList<Class<?>> xmlBeanList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> embeddableList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> entityList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> scalarTypeList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> scalarConverterList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> compoundTypeList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanControllerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> transactionEventListenerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanFinderList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanListenerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> luceneIndexList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> serverConfigStartupList = new ArrayList<Class<?>>();
|
||||
private ArrayList<ServerConfigStartup> serverConfigStartupInstances = new ArrayList<ServerConfigStartup>();
|
||||
|
||||
private List<BeanPersistController> persistControllerInstances = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPersistListener<?>> persistListenerInstances = new ArrayList<BeanPersistListener<?>>();
|
||||
private List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
|
||||
private List<TransactionEventListener> transactionEventListenerInstances = new ArrayList<TransactionEventListener>();
|
||||
|
||||
public BootupClasses() {
|
||||
}
|
||||
|
||||
public BootupClasses(List<Class<?>> list) {
|
||||
if (list != null) {
|
||||
process(list.iterator());
|
||||
}
|
||||
}
|
||||
|
||||
private BootupClasses(BootupClasses parent) {
|
||||
this.xmlBeanList.addAll(parent.xmlBeanList);
|
||||
this.embeddableList.addAll(parent.embeddableList);
|
||||
this.entityList.addAll(parent.entityList);
|
||||
this.scalarTypeList.addAll(parent.scalarTypeList);
|
||||
this.scalarConverterList.addAll(parent.scalarConverterList);
|
||||
this.compoundTypeList.addAll(parent.compoundTypeList);
|
||||
this.beanControllerList.addAll(parent.beanControllerList);
|
||||
this.transactionEventListenerList.addAll(parent.transactionEventListenerList);
|
||||
this.beanFinderList.addAll(parent.beanFinderList);
|
||||
this.beanListenerList.addAll(parent.beanListenerList);
|
||||
this.beanQueryAdapterList.addAll(parent.beanQueryAdapterList);
|
||||
this.luceneIndexList.addAll(parent.luceneIndexList);
|
||||
this.serverConfigStartupList.addAll(parent.serverConfigStartupList);
|
||||
}
|
||||
|
||||
private void process(Iterator<Class<?>> it) {
|
||||
while (it.hasNext()) {
|
||||
Class<?> cls = it.next();
|
||||
isMatch(cls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this object so that classes can be added to it.
|
||||
*/
|
||||
public BootupClasses createCopy() {
|
||||
return new BootupClasses(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run any ServerConfigStartup listeners.
|
||||
*/
|
||||
public void runServerConfigStartup(ServerConfig serverConfig) {
|
||||
|
||||
for (Class<?> cls : serverConfigStartupList) {
|
||||
try {
|
||||
ServerConfigStartup newInstance = (ServerConfigStartup) cls.newInstance();
|
||||
newInstance.onStart(serverConfig);
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addQueryAdapters(List<BeanQueryAdapter> queryAdapterInstances) {
|
||||
if (queryAdapterInstances != null) {
|
||||
for (BeanQueryAdapter a : queryAdapterInstances) {
|
||||
this.queryAdapterInstances.add(a);
|
||||
// don't automatically instantiate
|
||||
this.beanQueryAdapterList.remove(a.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add BeanPersistController instances.
|
||||
*/
|
||||
public void addPersistControllers(List<BeanPersistController> beanControllerInstances) {
|
||||
if (beanControllerInstances != null) {
|
||||
for (BeanPersistController c : beanControllerInstances) {
|
||||
this.persistControllerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.beanControllerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add TransactionEventListeners instances.
|
||||
*/
|
||||
public void addTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
|
||||
if (transactionEventListeners != null) {
|
||||
for (TransactionEventListener c : transactionEventListeners) {
|
||||
this.transactionEventListenerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.transactionEventListenerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addPersistListeners(List<BeanPersistListener<?>> listenerInstances) {
|
||||
if (listenerInstances != null) {
|
||||
for (BeanPersistListener<?> l : listenerInstances) {
|
||||
this.persistListenerInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.beanListenerList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addServerConfigStartup(List<ServerConfigStartup> startupInstances) {
|
||||
if (startupInstances != null) {
|
||||
for (ServerConfigStartup l : startupInstances) {
|
||||
this.serverConfigStartupInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.serverConfigStartupList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<BeanQueryAdapter> getBeanQueryAdapters() {
|
||||
// add class registered BeanQueryAdapter to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanQueryAdapterList) {
|
||||
try {
|
||||
BeanQueryAdapter newInstance = (BeanQueryAdapter) cls.newInstance();
|
||||
queryAdapterInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return queryAdapterInstances;
|
||||
}
|
||||
|
||||
public List<BeanPersistListener<?>> getBeanPersistListeners() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanListenerList) {
|
||||
try {
|
||||
BeanPersistListener<?> newInstance = (BeanPersistListener<?>) cls.newInstance();
|
||||
persistListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return persistListenerInstances;
|
||||
}
|
||||
|
||||
public List<BeanPersistController> getBeanPersistControllers() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanControllerList) {
|
||||
try {
|
||||
BeanPersistController newInstance = (BeanPersistController) cls.newInstance();
|
||||
persistControllerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return persistControllerInstances;
|
||||
}
|
||||
|
||||
public List<TransactionEventListener> getTransactionEventListeners() {
|
||||
// add class registered TransactionEventListener to the
|
||||
// already created instances
|
||||
for (Class<?> cls : transactionEventListenerList) {
|
||||
try {
|
||||
TransactionEventListener newInstance = (TransactionEventListener) cls.newInstance();
|
||||
transactionEventListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating TransactionEventListener " + cls;
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return transactionEventListenerInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of Embeddable classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEmbeddables() {
|
||||
return embeddableList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of entity classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEntities() {
|
||||
return entityList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarTypes found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarTypes() {
|
||||
return scalarTypeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarConverters() {
|
||||
return scalarConverterList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getCompoundTypes() {
|
||||
return compoundTypeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanControllers found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanControllers() {
|
||||
return beanControllerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of TransactionEventListeners found
|
||||
*/
|
||||
public ArrayList<Class<?>> getTransactionEventListenerList() {
|
||||
return transactionEventListenerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanFinders found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanFinders() {
|
||||
return beanFinderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanListeners found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanListeners() {
|
||||
return beanListenerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of XML Beans.
|
||||
*/
|
||||
public ArrayList<Class<?>> getXmlBeanList() {
|
||||
return xmlBeanList;
|
||||
}
|
||||
|
||||
public void add(Iterator<Class<?>> it) {
|
||||
while (it.hasNext()) {
|
||||
Class<?> clazz = it.next();
|
||||
isMatch(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMatch(Class<?> cls) {
|
||||
|
||||
if (isEmbeddable(cls)) {
|
||||
embeddableList.add(cls);
|
||||
|
||||
} else if (isEntity(cls)) {
|
||||
entityList.add(cls);
|
||||
|
||||
} else if (isXmlBean(cls)){
|
||||
entityList.add(cls);
|
||||
//xmlBeanList.add(cls);
|
||||
|
||||
} else if (isInterestingInterface(cls)) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for interesting interfaces.
|
||||
* <p>
|
||||
* This includes ScalarType, BeanController, BeanFinder and BeanListener.
|
||||
* </p>
|
||||
*/
|
||||
private boolean isInterestingInterface(Class<?> cls) {
|
||||
|
||||
boolean interesting = false;
|
||||
|
||||
if (BeanPersistController.class.isAssignableFrom(cls)) {
|
||||
beanControllerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (TransactionEventListener.class.isAssignableFrom(cls)) {
|
||||
transactionEventListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ScalarType.class.isAssignableFrom(cls)) {
|
||||
scalarTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ScalarTypeConverter.class.isAssignableFrom(cls)) {
|
||||
scalarConverterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (CompoundType.class.isAssignableFrom(cls)) {
|
||||
compoundTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanFinder.class.isAssignableFrom(cls)) {
|
||||
beanFinderList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanPersistListener.class.isAssignableFrom(cls)) {
|
||||
beanListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanQueryAdapter.class.isAssignableFrom(cls)) {
|
||||
beanQueryAdapterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ServerConfigStartup.class.isAssignableFrom(cls)){
|
||||
serverConfigStartupList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
return interesting;
|
||||
}
|
||||
|
||||
private boolean isEntity(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(Entity.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
ann = cls.getAnnotation(Table.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
ann = cls.getAnnotation(LdapDomain.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isEmbeddable(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(Embeddable.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isXmlBean(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(XmlRootElement.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
ann = cls.getAnnotation(XmlType.class);
|
||||
if (ann != null) {
|
||||
// Only looking for Beans and not Enums
|
||||
return !cls.isEnum();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import com.avaje.ebean.annotation.LdapDomain;
|
||||
import com.avaje.ebean.config.CompoundType;
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.ServerConfigStartup;
|
||||
import com.avaje.ebean.event.TransactionEventListener;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
|
||||
|
||||
/**
|
||||
* Interesting classes for a EbeanServer such as Embeddable, Entity,
|
||||
* ScalarTypes, Finders, Listeners and Controllers.
|
||||
*/
|
||||
public class BootupClasses implements ClassPathSearchMatcher {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(BootupClasses.class.getName());
|
||||
|
||||
private ArrayList<Class<?>> xmlBeanList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> embeddableList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> entityList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> scalarTypeList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> scalarConverterList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> compoundTypeList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanControllerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> transactionEventListenerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanFinderList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanListenerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> luceneIndexList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> serverConfigStartupList = new ArrayList<Class<?>>();
|
||||
private ArrayList<ServerConfigStartup> serverConfigStartupInstances = new ArrayList<ServerConfigStartup>();
|
||||
|
||||
private List<BeanPersistController> persistControllerInstances = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPersistListener<?>> persistListenerInstances = new ArrayList<BeanPersistListener<?>>();
|
||||
private List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
|
||||
private List<TransactionEventListener> transactionEventListenerInstances = new ArrayList<TransactionEventListener>();
|
||||
|
||||
public BootupClasses() {
|
||||
}
|
||||
|
||||
public BootupClasses(List<Class<?>> list) {
|
||||
if (list != null) {
|
||||
process(list.iterator());
|
||||
}
|
||||
}
|
||||
|
||||
private BootupClasses(BootupClasses parent) {
|
||||
this.xmlBeanList.addAll(parent.xmlBeanList);
|
||||
this.embeddableList.addAll(parent.embeddableList);
|
||||
this.entityList.addAll(parent.entityList);
|
||||
this.scalarTypeList.addAll(parent.scalarTypeList);
|
||||
this.scalarConverterList.addAll(parent.scalarConverterList);
|
||||
this.compoundTypeList.addAll(parent.compoundTypeList);
|
||||
this.beanControllerList.addAll(parent.beanControllerList);
|
||||
this.transactionEventListenerList.addAll(parent.transactionEventListenerList);
|
||||
this.beanFinderList.addAll(parent.beanFinderList);
|
||||
this.beanListenerList.addAll(parent.beanListenerList);
|
||||
this.beanQueryAdapterList.addAll(parent.beanQueryAdapterList);
|
||||
this.luceneIndexList.addAll(parent.luceneIndexList);
|
||||
this.serverConfigStartupList.addAll(parent.serverConfigStartupList);
|
||||
}
|
||||
|
||||
private void process(Iterator<Class<?>> it) {
|
||||
while (it.hasNext()) {
|
||||
Class<?> cls = it.next();
|
||||
isMatch(cls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this object so that classes can be added to it.
|
||||
*/
|
||||
public BootupClasses createCopy() {
|
||||
return new BootupClasses(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run any ServerConfigStartup listeners.
|
||||
*/
|
||||
public void runServerConfigStartup(ServerConfig serverConfig) {
|
||||
|
||||
for (Class<?> cls : serverConfigStartupList) {
|
||||
try {
|
||||
ServerConfigStartup newInstance = (ServerConfigStartup) cls.newInstance();
|
||||
newInstance.onStart(serverConfig);
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addQueryAdapters(List<BeanQueryAdapter> queryAdapterInstances) {
|
||||
if (queryAdapterInstances != null) {
|
||||
for (BeanQueryAdapter a : queryAdapterInstances) {
|
||||
this.queryAdapterInstances.add(a);
|
||||
// don't automatically instantiate
|
||||
this.beanQueryAdapterList.remove(a.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add BeanPersistController instances.
|
||||
*/
|
||||
public void addPersistControllers(List<BeanPersistController> beanControllerInstances) {
|
||||
if (beanControllerInstances != null) {
|
||||
for (BeanPersistController c : beanControllerInstances) {
|
||||
this.persistControllerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.beanControllerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add TransactionEventListeners instances.
|
||||
*/
|
||||
public void addTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
|
||||
if (transactionEventListeners != null) {
|
||||
for (TransactionEventListener c : transactionEventListeners) {
|
||||
this.transactionEventListenerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.transactionEventListenerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addPersistListeners(List<BeanPersistListener<?>> listenerInstances) {
|
||||
if (listenerInstances != null) {
|
||||
for (BeanPersistListener<?> l : listenerInstances) {
|
||||
this.persistListenerInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.beanListenerList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addServerConfigStartup(List<ServerConfigStartup> startupInstances) {
|
||||
if (startupInstances != null) {
|
||||
for (ServerConfigStartup l : startupInstances) {
|
||||
this.serverConfigStartupInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.serverConfigStartupList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<BeanQueryAdapter> getBeanQueryAdapters() {
|
||||
// add class registered BeanQueryAdapter to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanQueryAdapterList) {
|
||||
try {
|
||||
BeanQueryAdapter newInstance = (BeanQueryAdapter) cls.newInstance();
|
||||
queryAdapterInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return queryAdapterInstances;
|
||||
}
|
||||
|
||||
public List<BeanPersistListener<?>> getBeanPersistListeners() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanListenerList) {
|
||||
try {
|
||||
BeanPersistListener<?> newInstance = (BeanPersistListener<?>) cls.newInstance();
|
||||
persistListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return persistListenerInstances;
|
||||
}
|
||||
|
||||
public List<BeanPersistController> getBeanPersistControllers() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanControllerList) {
|
||||
try {
|
||||
BeanPersistController newInstance = (BeanPersistController) cls.newInstance();
|
||||
persistControllerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return persistControllerInstances;
|
||||
}
|
||||
|
||||
public List<TransactionEventListener> getTransactionEventListeners() {
|
||||
// add class registered TransactionEventListener to the
|
||||
// already created instances
|
||||
for (Class<?> cls : transactionEventListenerList) {
|
||||
try {
|
||||
TransactionEventListener newInstance = (TransactionEventListener) cls.newInstance();
|
||||
transactionEventListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating TransactionEventListener " + cls;
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return transactionEventListenerInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of Embeddable classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEmbeddables() {
|
||||
return embeddableList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of entity classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEntities() {
|
||||
return entityList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarTypes found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarTypes() {
|
||||
return scalarTypeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarConverters() {
|
||||
return scalarConverterList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getCompoundTypes() {
|
||||
return compoundTypeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanControllers found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanControllers() {
|
||||
return beanControllerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of TransactionEventListeners found
|
||||
*/
|
||||
public ArrayList<Class<?>> getTransactionEventListenerList() {
|
||||
return transactionEventListenerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanFinders found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanFinders() {
|
||||
return beanFinderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanListeners found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanListeners() {
|
||||
return beanListenerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of XML Beans.
|
||||
*/
|
||||
public ArrayList<Class<?>> getXmlBeanList() {
|
||||
return xmlBeanList;
|
||||
}
|
||||
|
||||
public void add(Iterator<Class<?>> it) {
|
||||
while (it.hasNext()) {
|
||||
Class<?> clazz = it.next();
|
||||
isMatch(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMatch(Class<?> cls) {
|
||||
|
||||
if (isEmbeddable(cls)) {
|
||||
embeddableList.add(cls);
|
||||
|
||||
} else if (isEntity(cls)) {
|
||||
entityList.add(cls);
|
||||
|
||||
} else if (isXmlBean(cls)){
|
||||
entityList.add(cls);
|
||||
//xmlBeanList.add(cls);
|
||||
|
||||
} else if (isInterestingInterface(cls)) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for interesting interfaces.
|
||||
* <p>
|
||||
* This includes ScalarType, BeanController, BeanFinder and BeanListener.
|
||||
* </p>
|
||||
*/
|
||||
private boolean isInterestingInterface(Class<?> cls) {
|
||||
|
||||
boolean interesting = false;
|
||||
|
||||
if (BeanPersistController.class.isAssignableFrom(cls)) {
|
||||
beanControllerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (TransactionEventListener.class.isAssignableFrom(cls)) {
|
||||
transactionEventListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ScalarType.class.isAssignableFrom(cls)) {
|
||||
scalarTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ScalarTypeConverter.class.isAssignableFrom(cls)) {
|
||||
scalarConverterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (CompoundType.class.isAssignableFrom(cls)) {
|
||||
compoundTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanFinder.class.isAssignableFrom(cls)) {
|
||||
beanFinderList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanPersistListener.class.isAssignableFrom(cls)) {
|
||||
beanListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanQueryAdapter.class.isAssignableFrom(cls)) {
|
||||
beanQueryAdapterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ServerConfigStartup.class.isAssignableFrom(cls)){
|
||||
serverConfigStartupList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
return interesting;
|
||||
}
|
||||
|
||||
private boolean isEntity(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(Entity.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
ann = cls.getAnnotation(Table.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
ann = cls.getAnnotation(LdapDomain.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isEmbeddable(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(Embeddable.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isXmlBean(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(XmlRootElement.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
ann = cls.getAnnotation(XmlType.class);
|
||||
if (ann != null) {
|
||||
// Only looking for Beans and not Enums
|
||||
return !cls.isEnum();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,191 +1,172 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.H2Platform;
|
||||
import com.avaje.ebean.config.dbplatform.HsqldbPlatform;
|
||||
import com.avaje.ebean.config.dbplatform.MsSqlServer2000Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MsSqlServer2005Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
|
||||
import com.avaje.ebean.config.dbplatform.Oracle10Platform;
|
||||
import com.avaje.ebean.config.dbplatform.Oracle9Platform;
|
||||
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
|
||||
import com.avaje.ebean.config.dbplatform.SQLitePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.SqlAnywherePlatform;
|
||||
|
||||
/**
|
||||
* Create a DatabasePlatform from the configuration.
|
||||
* <p>
|
||||
* Will used platform name or use the meta data from the JDBC driver to
|
||||
* determine the platform automatically.
|
||||
* </p>
|
||||
*/
|
||||
public class DatabasePlatformFactory {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DatabasePlatformFactory.class.getName());
|
||||
|
||||
/**
|
||||
* Create the appropriate database specific platform.
|
||||
*/
|
||||
public DatabasePlatform create(ServerConfig serverConfig) {
|
||||
|
||||
try {
|
||||
|
||||
if (serverConfig.getDatabasePlatformName() != null) {
|
||||
// choose based on dbName
|
||||
return byDatabaseName(serverConfig.getDatabasePlatformName());
|
||||
|
||||
}
|
||||
if (serverConfig.getDataSourceConfig().isOffline()) {
|
||||
String m = "You must specify a DatabasePlatformName when you are offline";
|
||||
throw new PersistenceException(m);
|
||||
}
|
||||
// guess using meta data from driver
|
||||
return byDataSource(serverConfig.getDataSource());
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the platform by name.
|
||||
*/
|
||||
private DatabasePlatform byDatabaseName(String dbName) throws SQLException {
|
||||
|
||||
dbName = dbName.toLowerCase();
|
||||
if (dbName.equals("postgres83")) {
|
||||
return new PostgresPlatform();
|
||||
}
|
||||
if (dbName.equals("oracle9")) {
|
||||
return new Oracle9Platform();
|
||||
}
|
||||
if (dbName.equals("oracle10")) {
|
||||
return new Oracle10Platform();
|
||||
}
|
||||
if (dbName.equals("oracle")) {
|
||||
return new Oracle10Platform();
|
||||
}
|
||||
if (dbName.equals("sqlserver2005")) {
|
||||
return new MsSqlServer2005Platform();
|
||||
}
|
||||
if (dbName.equals("sqlserver2000")) {
|
||||
return new MsSqlServer2000Platform();
|
||||
}
|
||||
if (dbName.equals("sqlanywhere")) {
|
||||
return new SqlAnywherePlatform();
|
||||
}
|
||||
|
||||
if (dbName.equals("mysql")) {
|
||||
return new MySqlPlatform();
|
||||
}
|
||||
|
||||
if (dbName.equals("sqlite")) {
|
||||
return new SQLitePlatform();
|
||||
}
|
||||
|
||||
throw new RuntimeException("database platform " + dbName + " is not known?");
|
||||
}
|
||||
|
||||
/**
|
||||
* Use JDBC DatabaseMetaData to determine the platform.
|
||||
*/
|
||||
private DatabasePlatform byDataSource(DataSource dataSource) {
|
||||
|
||||
Connection conn = null;
|
||||
try {
|
||||
conn = dataSource.getConnection();
|
||||
DatabaseMetaData metaData = conn.getMetaData();
|
||||
|
||||
return byDatabaseMeta(metaData);
|
||||
|
||||
} catch (SQLException ex) {
|
||||
throw new PersistenceException(ex);
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the platform by the metaData.getDatabaseProductName().
|
||||
*/
|
||||
private DatabasePlatform byDatabaseMeta(DatabaseMetaData metaData) throws SQLException {
|
||||
|
||||
String dbProductName = metaData.getDatabaseProductName();
|
||||
dbProductName = dbProductName.toLowerCase();
|
||||
|
||||
int majorVersion = metaData.getDatabaseMajorVersion();
|
||||
|
||||
if (dbProductName.indexOf("oracle") > -1) {
|
||||
if (majorVersion > 9) {
|
||||
return new Oracle10Platform();
|
||||
} else {
|
||||
return new Oracle9Platform();
|
||||
}
|
||||
}
|
||||
if (dbProductName.indexOf("microsoft") > -1) {
|
||||
if (majorVersion > 8) {
|
||||
return new MsSqlServer2005Platform();
|
||||
} else {
|
||||
return new MsSqlServer2000Platform();
|
||||
}
|
||||
}
|
||||
|
||||
if (dbProductName.indexOf("mysql") > -1) {
|
||||
return new MySqlPlatform();
|
||||
}
|
||||
if (dbProductName.indexOf("h2") > -1) {
|
||||
return new H2Platform();
|
||||
}
|
||||
if (dbProductName.indexOf("hsql database engine") > -1) {
|
||||
return new HsqldbPlatform();
|
||||
}
|
||||
if (dbProductName.indexOf("postgres") > -1) {
|
||||
return new PostgresPlatform();
|
||||
}
|
||||
if (dbProductName.indexOf("sqlite") > -1) {
|
||||
return new SQLitePlatform();
|
||||
}
|
||||
if (dbProductName.indexOf("sql anywhere") > -1) {
|
||||
return new SqlAnywherePlatform();
|
||||
}
|
||||
|
||||
// use the standard one
|
||||
return new DatabasePlatform();
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.H2Platform;
|
||||
import com.avaje.ebean.config.dbplatform.HsqldbPlatform;
|
||||
import com.avaje.ebean.config.dbplatform.MsSqlServer2000Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MsSqlServer2005Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
|
||||
import com.avaje.ebean.config.dbplatform.Oracle10Platform;
|
||||
import com.avaje.ebean.config.dbplatform.Oracle9Platform;
|
||||
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
|
||||
import com.avaje.ebean.config.dbplatform.SQLitePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.SqlAnywherePlatform;
|
||||
|
||||
/**
|
||||
* Create a DatabasePlatform from the configuration.
|
||||
* <p>
|
||||
* Will used platform name or use the meta data from the JDBC driver to
|
||||
* determine the platform automatically.
|
||||
* </p>
|
||||
*/
|
||||
public class DatabasePlatformFactory {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DatabasePlatformFactory.class.getName());
|
||||
|
||||
/**
|
||||
* Create the appropriate database specific platform.
|
||||
*/
|
||||
public DatabasePlatform create(ServerConfig serverConfig) {
|
||||
|
||||
try {
|
||||
|
||||
if (serverConfig.getDatabasePlatformName() != null) {
|
||||
// choose based on dbName
|
||||
return byDatabaseName(serverConfig.getDatabasePlatformName());
|
||||
|
||||
}
|
||||
if (serverConfig.getDataSourceConfig().isOffline()) {
|
||||
String m = "You must specify a DatabasePlatformName when you are offline";
|
||||
throw new PersistenceException(m);
|
||||
}
|
||||
// guess using meta data from driver
|
||||
return byDataSource(serverConfig.getDataSource());
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the platform by name.
|
||||
*/
|
||||
private DatabasePlatform byDatabaseName(String dbName) throws SQLException {
|
||||
|
||||
dbName = dbName.toLowerCase();
|
||||
if (dbName.equals("postgres83")) {
|
||||
return new PostgresPlatform();
|
||||
}
|
||||
if (dbName.equals("oracle9")) {
|
||||
return new Oracle9Platform();
|
||||
}
|
||||
if (dbName.equals("oracle10")) {
|
||||
return new Oracle10Platform();
|
||||
}
|
||||
if (dbName.equals("oracle")) {
|
||||
return new Oracle10Platform();
|
||||
}
|
||||
if (dbName.equals("sqlserver2005")) {
|
||||
return new MsSqlServer2005Platform();
|
||||
}
|
||||
if (dbName.equals("sqlserver2000")) {
|
||||
return new MsSqlServer2000Platform();
|
||||
}
|
||||
if (dbName.equals("sqlanywhere")) {
|
||||
return new SqlAnywherePlatform();
|
||||
}
|
||||
|
||||
if (dbName.equals("mysql")) {
|
||||
return new MySqlPlatform();
|
||||
}
|
||||
|
||||
if (dbName.equals("sqlite")) {
|
||||
return new SQLitePlatform();
|
||||
}
|
||||
|
||||
throw new RuntimeException("database platform " + dbName + " is not known?");
|
||||
}
|
||||
|
||||
/**
|
||||
* Use JDBC DatabaseMetaData to determine the platform.
|
||||
*/
|
||||
private DatabasePlatform byDataSource(DataSource dataSource) {
|
||||
|
||||
Connection conn = null;
|
||||
try {
|
||||
conn = dataSource.getConnection();
|
||||
DatabaseMetaData metaData = conn.getMetaData();
|
||||
|
||||
return byDatabaseMeta(metaData);
|
||||
|
||||
} catch (SQLException ex) {
|
||||
throw new PersistenceException(ex);
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the platform by the metaData.getDatabaseProductName().
|
||||
*/
|
||||
private DatabasePlatform byDatabaseMeta(DatabaseMetaData metaData) throws SQLException {
|
||||
|
||||
String dbProductName = metaData.getDatabaseProductName();
|
||||
dbProductName = dbProductName.toLowerCase();
|
||||
|
||||
int majorVersion = metaData.getDatabaseMajorVersion();
|
||||
|
||||
if (dbProductName.indexOf("oracle") > -1) {
|
||||
if (majorVersion > 9) {
|
||||
return new Oracle10Platform();
|
||||
} else {
|
||||
return new Oracle9Platform();
|
||||
}
|
||||
}
|
||||
if (dbProductName.indexOf("microsoft") > -1) {
|
||||
if (majorVersion > 8) {
|
||||
return new MsSqlServer2005Platform();
|
||||
} else {
|
||||
return new MsSqlServer2000Platform();
|
||||
}
|
||||
}
|
||||
|
||||
if (dbProductName.indexOf("mysql") > -1) {
|
||||
return new MySqlPlatform();
|
||||
}
|
||||
if (dbProductName.indexOf("h2") > -1) {
|
||||
return new H2Platform();
|
||||
}
|
||||
if (dbProductName.indexOf("hsql database engine") > -1) {
|
||||
return new HsqldbPlatform();
|
||||
}
|
||||
if (dbProductName.indexOf("postgres") > -1) {
|
||||
return new PostgresPlatform();
|
||||
}
|
||||
if (dbProductName.indexOf("sqlite") > -1) {
|
||||
return new SQLitePlatform();
|
||||
}
|
||||
if (dbProductName.indexOf("sql anywhere") > -1) {
|
||||
return new SqlAnywherePlatform();
|
||||
}
|
||||
|
||||
// use the standard one
|
||||
return new DatabasePlatform();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,71 +1,52 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonScheduleThreadPool;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonThreadPool;
|
||||
|
||||
/**
|
||||
* The default implementation of the BackgroundExecutor.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final DaemonThreadPool pool;
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*
|
||||
* @param mainPoolSize
|
||||
* the core size of the thread pool.
|
||||
* @param keepAliveSecs
|
||||
* the time in seconds idle threads are keep alive
|
||||
* @param shutdownWaitSeconds
|
||||
* the time in seconds allowed for the pool to shutdown nicely.
|
||||
* After this the pool is forced to shutdown.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int mainPoolSize, int schedulePoolSize, long keepAliveSecs,int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = new DaemonThreadPool(mainPoolSize, keepAliveSecs, shutdownWaitSeconds, namePrefix);
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix+"-periodic-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Runnable using a background thread.
|
||||
*/
|
||||
public void execute(Runnable r) {
|
||||
pool.execute(r);
|
||||
}
|
||||
|
||||
public void executePeriodically(Runnable r, long delay, TimeUnit unit) {
|
||||
schedulePool.scheduleWithFixedDelay(r, delay, delay, unit);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
pool.shutdown();
|
||||
schedulePool.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonScheduleThreadPool;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonThreadPool;
|
||||
|
||||
/**
|
||||
* The default implementation of the BackgroundExecutor.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final DaemonThreadPool pool;
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*
|
||||
* @param mainPoolSize
|
||||
* the core size of the thread pool.
|
||||
* @param keepAliveSecs
|
||||
* the time in seconds idle threads are keep alive
|
||||
* @param shutdownWaitSeconds
|
||||
* the time in seconds allowed for the pool to shutdown nicely.
|
||||
* After this the pool is forced to shutdown.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int mainPoolSize, int schedulePoolSize, long keepAliveSecs,int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = new DaemonThreadPool(mainPoolSize, keepAliveSecs, shutdownWaitSeconds, namePrefix);
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix+"-periodic-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Runnable using a background thread.
|
||||
*/
|
||||
public void execute(Runnable r) {
|
||||
pool.execute(r);
|
||||
}
|
||||
|
||||
public void executePeriodically(Runnable r, long delay, TimeUnit unit) {
|
||||
schedulePool.scheduleWithFixedDelay(r, delay, delay, unit);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
pool.shutdown();
|
||||
schedulePool.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,478 +1,459 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanContext;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanRequest;
|
||||
import com.avaje.ebeaninternal.api.LoadManyContext;
|
||||
import com.avaje.ebeaninternal.api.LoadManyRequest;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
|
||||
/**
|
||||
* Helper to handle lazy loading and refreshing of beans.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class DefaultBeanLoader {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DefaultBeanLoader.class.getName());
|
||||
|
||||
private final DebugLazyLoad debugLazyLoad;
|
||||
|
||||
private final DefaultServer server;
|
||||
|
||||
protected DefaultBeanLoader(DefaultServer server, DebugLazyLoad debugLazyLoad) {
|
||||
this.server = server;
|
||||
this.debugLazyLoad = debugLazyLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a batch size that might be less than the requestedBatchSize.
|
||||
* <p>
|
||||
* This means we can have large and variable requestedBatchSizes.
|
||||
* </p>
|
||||
* <p>
|
||||
* We want to restrict the number of different batch sizes as we want to
|
||||
* re-use the query plan cache and get DB statement re-use.
|
||||
* </p>
|
||||
*/
|
||||
private int getBatchSize(int batchListSize, int requestedBatchSize) {
|
||||
if (batchListSize == requestedBatchSize) {
|
||||
return batchListSize;
|
||||
}
|
||||
if (batchListSize == 1) {
|
||||
// there is only one bean/collection to load
|
||||
return 1;
|
||||
}
|
||||
if (requestedBatchSize <= 5) {
|
||||
// anything less than 5 becomes 5
|
||||
return 5;
|
||||
}
|
||||
if (batchListSize <= 10 || requestedBatchSize <= 10) {
|
||||
// 10 or less to load
|
||||
// ... or we wanted a batch size between 6 and 10
|
||||
return 10;
|
||||
}
|
||||
if (batchListSize <= 20 || requestedBatchSize <= 20) {
|
||||
// 20 or less to load
|
||||
// ... or we wanted a batch size between 11 and 20
|
||||
return 20;
|
||||
}
|
||||
if (batchListSize <= 50) {
|
||||
return 50;
|
||||
}
|
||||
return requestedBatchSize;
|
||||
}
|
||||
|
||||
public void refreshMany(Object parentBean, String propertyName) {
|
||||
refreshMany(parentBean, propertyName, null);
|
||||
}
|
||||
|
||||
public void loadMany(LoadManyRequest loadRequest) {
|
||||
|
||||
List<BeanCollection<?>> batch = loadRequest.getBatch();
|
||||
|
||||
int batchSize = getBatchSize(batch.size(), loadRequest.getBatchSize());
|
||||
|
||||
LoadManyContext ctx = loadRequest.getLoadContext();
|
||||
BeanPropertyAssocMany<?> many = ctx.getBeanProperty();
|
||||
|
||||
PersistenceContext pc = ctx.getPersistenceContext();
|
||||
|
||||
ArrayList<Object> idList = new ArrayList<Object>(batchSize);
|
||||
|
||||
for (int i = 0; i < batch.size(); i++) {
|
||||
BeanCollection<?> bc = batch.get(i);
|
||||
Object ownerBean = bc.getOwnerBean();
|
||||
Object id = many.getParentId(ownerBean);
|
||||
idList.add(id);
|
||||
}
|
||||
int extraIds = batchSize - batch.size();
|
||||
if (extraIds > 0) {
|
||||
Object firstId = idList.get(0);
|
||||
for (int i = 0; i < extraIds; i++) {
|
||||
idList.add(firstId);
|
||||
}
|
||||
}
|
||||
|
||||
BeanDescriptor<?> desc = ctx.getBeanDescriptor();
|
||||
|
||||
String idProperty = desc.getIdBinder().getIdProperty();
|
||||
|
||||
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(desc.getBeanType());
|
||||
query.setMode(Mode.LAZYLOAD_MANY);
|
||||
query.setLazyLoadManyPath(many.getName());
|
||||
query.setPersistenceContext(pc);
|
||||
query.select(idProperty);
|
||||
query.fetch(many.getName());
|
||||
|
||||
if (idList.size() == 1) {
|
||||
query.where().idEq(idList.get(0));
|
||||
} else {
|
||||
query.where().idIn(idList);
|
||||
}
|
||||
|
||||
String mode = loadRequest.isLazy() ? "+lazy" : "+query";
|
||||
query.setLoadDescription(mode, loadRequest.getDescription());
|
||||
|
||||
// potentially changes the joins and selected properties
|
||||
ctx.configureQuery(query);
|
||||
|
||||
if (loadRequest.isOnlyIds()) {
|
||||
// override to just select the Id values
|
||||
query.fetch(many.getName(), many.getTargetIdProperty());
|
||||
}
|
||||
|
||||
server.findList(query, loadRequest.getTransaction());
|
||||
|
||||
// check for BeanCollection's that where never processed
|
||||
// in the +query or +lazy load due to no rows (predicates)
|
||||
for (int i = 0; i < batch.size(); i++) {
|
||||
BeanCollection<?> bc = batch.get(i);
|
||||
if (bc.checkEmptyLazyLoad()) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.fine("BeanCollection after load was empty. Owner:" + batch.get(i).getOwnerBean());
|
||||
}
|
||||
} else if (loadRequest.isLoadCache()) {
|
||||
Object parentId = desc.getId(bc.getOwnerBean());
|
||||
desc.cachePutMany(many, bc, parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadMany(BeanCollection<?> bc, LoadManyContext ctx, boolean onlyIds) {
|
||||
|
||||
Object parentBean = bc.getOwnerBean();
|
||||
String propertyName = bc.getPropertyName();
|
||||
|
||||
ObjectGraphNode node = ctx == null ? null : ctx.getObjectGraphNode();
|
||||
|
||||
loadManyInternal(parentBean, propertyName, null, false, node, onlyIds);
|
||||
|
||||
if (server.getAdminLogging().isDebugLazyLoad()) {
|
||||
|
||||
Class<?> cls = parentBean.getClass();
|
||||
BeanDescriptor<?> desc = server.getBeanDescriptor(cls);
|
||||
BeanPropertyAssocMany<?> many = (BeanPropertyAssocMany<?>) desc.getBeanProperty(propertyName);
|
||||
|
||||
StackTraceElement cause = debugLazyLoad.getStackTraceElement(cls);
|
||||
|
||||
String msg = "debug.lazyLoad " + many.getManyType() + " [" + desc + "][" + propertyName + "]";
|
||||
if (cause != null) {
|
||||
msg += " at: " + cause;
|
||||
}
|
||||
System.err.println(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshMany(Object parentBean, String propertyName, Transaction t) {
|
||||
loadManyInternal(parentBean, propertyName, t, true, null, false);
|
||||
}
|
||||
|
||||
private void loadManyInternal(Object parentBean, String propertyName, Transaction t, boolean refresh, ObjectGraphNode node, boolean onlyIds) {
|
||||
|
||||
boolean vanilla = (parentBean instanceof EntityBean == false);
|
||||
|
||||
EntityBeanIntercept ebi = null;
|
||||
PersistenceContext pc = null;
|
||||
BeanCollection<?> beanCollection = null;
|
||||
ExpressionList<?> filterMany = null;
|
||||
|
||||
if (!vanilla) {
|
||||
ebi = ((EntityBean) parentBean)._ebean_getIntercept();
|
||||
pc = ebi.getPersistenceContext();
|
||||
}
|
||||
|
||||
BeanDescriptor<?> parentDesc = server.getBeanDescriptor(parentBean.getClass());
|
||||
BeanPropertyAssocMany<?> many = (BeanPropertyAssocMany<?>) parentDesc.getBeanProperty(propertyName);
|
||||
|
||||
Object currentValue = many.getValueUnderlying(parentBean);
|
||||
if (currentValue instanceof BeanCollection<?>) {
|
||||
beanCollection = (BeanCollection<?>) currentValue;
|
||||
filterMany = beanCollection.getFilterMany();
|
||||
}
|
||||
|
||||
Object parentId = parentDesc.getId(parentBean);
|
||||
|
||||
if (pc == null) {
|
||||
pc = new DefaultPersistenceContext();
|
||||
pc.put(parentId, parentBean);
|
||||
}
|
||||
|
||||
boolean useManyIdCache = !vanilla && beanCollection != null && parentDesc.cacheIsUseManyId();
|
||||
if (useManyIdCache) {
|
||||
Boolean readOnly = null;
|
||||
if (ebi != null && ebi.isReadOnly()) {
|
||||
readOnly = Boolean.TRUE;
|
||||
}
|
||||
if (parentDesc.cacheLoadMany(many, beanCollection, parentId, readOnly, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(parentDesc.getBeanType());
|
||||
|
||||
if (refresh) {
|
||||
// populate a new collection
|
||||
Object emptyCollection = many.createEmpty(vanilla);
|
||||
many.setValue(parentBean, emptyCollection);
|
||||
query.setLoadDescription("+refresh", null);
|
||||
} else {
|
||||
query.setLoadDescription("+lazy", null);
|
||||
}
|
||||
|
||||
if (node != null) {
|
||||
// so we can hook back to the root query
|
||||
query.setParentNode(node);
|
||||
}
|
||||
|
||||
String idProperty = parentDesc.getIdBinder().getIdProperty();
|
||||
query.select(idProperty);
|
||||
|
||||
if (onlyIds) {
|
||||
query.fetch(many.getName(), many.getTargetIdProperty());
|
||||
} else {
|
||||
query.fetch(many.getName());
|
||||
}
|
||||
if (filterMany != null) {
|
||||
query.setFilterMany(many.getName(), filterMany);
|
||||
}
|
||||
|
||||
query.where().idEq(parentId);
|
||||
query.setUseCache(false);
|
||||
query.setMode(Mode.LAZYLOAD_MANY);
|
||||
query.setLazyLoadManyPath(many.getName());
|
||||
query.setPersistenceContext(pc);
|
||||
query.setVanillaMode(vanilla);
|
||||
|
||||
if (ebi != null) {
|
||||
if (ebi.isReadOnly()) {
|
||||
query.setReadOnly(true);
|
||||
}
|
||||
}
|
||||
|
||||
server.findUnique(query, t);
|
||||
|
||||
if (beanCollection != null) {
|
||||
if (beanCollection.checkEmptyLazyLoad()) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.fine("BeanCollection after load was empty. Owner:" + beanCollection.getOwnerBean());
|
||||
}
|
||||
} else if (useManyIdCache) {
|
||||
parentDesc.cachePutMany(many, beanCollection, parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a batch of beans for +query or +lazy loading.
|
||||
*/
|
||||
public void loadBean(LoadBeanRequest loadRequest) {
|
||||
|
||||
List<EntityBeanIntercept> batch = loadRequest.getBatch();
|
||||
|
||||
if (batch.isEmpty()) {
|
||||
throw new RuntimeException("Nothing in batch?");
|
||||
}
|
||||
|
||||
int batchSize = getBatchSize(batch.size(), loadRequest.getBatchSize());
|
||||
|
||||
LoadBeanContext ctx = loadRequest.getLoadContext();
|
||||
BeanDescriptor<?> desc = ctx.getBeanDescriptor();
|
||||
|
||||
Class<?> beanType = desc.getBeanType();
|
||||
|
||||
EntityBeanIntercept[] ebis = batch.toArray(new EntityBeanIntercept[batch.size()]);
|
||||
ArrayList<Object> idList = new ArrayList<Object>(batchSize);
|
||||
|
||||
for (int i = 0; i < batch.size(); i++) {
|
||||
EntityBeanIntercept ebi = batch.get(i);
|
||||
Object bean = ebi.getOwner();
|
||||
Object id = desc.getId(bean);
|
||||
idList.add(id);
|
||||
}
|
||||
|
||||
if (idList.isEmpty()) {
|
||||
// everything was loaded from cache
|
||||
return;
|
||||
}
|
||||
|
||||
int extraIds = batchSize - batch.size();
|
||||
if (extraIds > 0) {
|
||||
// for performance make up the Id's to the batch size
|
||||
// so we get the same query (for Ebean and the db)
|
||||
Object firstId = idList.get(0);
|
||||
for (int i = 0; i < extraIds; i++) {
|
||||
// just add the first Id again
|
||||
idList.add(firstId);
|
||||
}
|
||||
}
|
||||
|
||||
PersistenceContext persistenceContext = ctx.getPersistenceContext();
|
||||
|
||||
// query the database
|
||||
for (int i = 0; i < ebis.length; i++) {
|
||||
Object parentBean = ebis[i].getParentBean();
|
||||
if (parentBean != null) {
|
||||
// Special case for OneToOne
|
||||
BeanDescriptor<?> parentDesc = server.getBeanDescriptor(parentBean.getClass());
|
||||
Object parentId = parentDesc.getId(parentBean);
|
||||
persistenceContext.put(parentId, parentBean);
|
||||
}
|
||||
}
|
||||
|
||||
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(beanType);
|
||||
|
||||
query.setMode(Mode.LAZYLOAD_BEAN);
|
||||
query.setPersistenceContext(persistenceContext);
|
||||
|
||||
String mode = loadRequest.isLazy() ? "+lazy" : "+query";
|
||||
query.setLoadDescription(mode, loadRequest.getDescription());
|
||||
|
||||
ctx.configureQuery(query, loadRequest.getLazyLoadProperty());
|
||||
|
||||
// make sure the query doesn't use the cache
|
||||
// query.setUseCache(false);
|
||||
if (idList.size() == 1) {
|
||||
query.where().idEq(idList.get(0));
|
||||
} else {
|
||||
query.where().idIn(idList);
|
||||
}
|
||||
|
||||
List<?> list = server.findList(query, loadRequest.getTransaction());
|
||||
|
||||
if (loadRequest.isLoadCache()) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
desc.cachePutBeanData(list.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < ebis.length; i++) {
|
||||
if (ebis[i].isReference()) {
|
||||
// The underlying row in DB was deleted. Mark this bean as 'failed'
|
||||
// but allow processing to continue until it is accessed by client code
|
||||
ebis[i].setLazyLoadFailure();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void refresh(Object bean) {
|
||||
refreshBeanInternal(bean, SpiQuery.Mode.REFRESH_BEAN);
|
||||
}
|
||||
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
refreshBeanInternal(ebi.getOwner(), SpiQuery.Mode.LAZYLOAD_BEAN);
|
||||
}
|
||||
|
||||
private void refreshBeanInternal(Object bean, SpiQuery.Mode mode) {
|
||||
|
||||
boolean vanilla = (bean instanceof EntityBean == false);
|
||||
|
||||
EntityBeanIntercept ebi = null;
|
||||
PersistenceContext pc = null;
|
||||
|
||||
if (!vanilla) {
|
||||
ebi = ((EntityBean) bean)._ebean_getIntercept();
|
||||
pc = ebi.getPersistenceContext();
|
||||
}
|
||||
|
||||
BeanDescriptor<?> desc = server.getBeanDescriptor(bean.getClass());
|
||||
Object id = desc.getId(bean);
|
||||
|
||||
if (pc == null) {
|
||||
// a reference with no existing persistenceContext
|
||||
pc = new DefaultPersistenceContext();
|
||||
pc.put(id, bean);
|
||||
if (ebi != null) {
|
||||
ebi.setPersistenceContext(pc);
|
||||
}
|
||||
}
|
||||
|
||||
if (ebi != null) {
|
||||
if (SpiQuery.Mode.LAZYLOAD_BEAN.equals(mode) && desc.isBeanCaching()) {
|
||||
// lazy loading and the bean cache is active
|
||||
if (desc.loadFromCache(bean, ebi, id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (desc.lazyLoadMany(ebi)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(desc.getBeanType());
|
||||
if (ebi != null) {
|
||||
Object parentBean = ebi.getParentBean();
|
||||
if (parentBean != null) {
|
||||
// Special case for OneToOne
|
||||
BeanDescriptor<?> parentDesc = server.getBeanDescriptor(parentBean.getClass());
|
||||
Object parentId = parentDesc.getId(parentBean);
|
||||
pc.putIfAbsent(parentId, parentBean);
|
||||
}
|
||||
|
||||
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
|
||||
}
|
||||
|
||||
// don't collect autoFetch usage profiling information
|
||||
// as we just copy the data out of these fetched beans
|
||||
// and put the data into the original bean
|
||||
query.setUsageProfiling(false);
|
||||
query.setPersistenceContext(pc);
|
||||
|
||||
query.setMode(mode);
|
||||
query.setId(id);
|
||||
// make sure the query doesn't use the cache
|
||||
if (mode.equals(SpiQuery.Mode.REFRESH_BEAN)) {
|
||||
query.setUseCache(false);
|
||||
}
|
||||
query.setVanillaMode(vanilla);
|
||||
|
||||
if (ebi != null && ebi.isReadOnly()) {
|
||||
query.setReadOnly(true);
|
||||
}
|
||||
|
||||
Object dbBean = query.findUnique();
|
||||
if (dbBean == null) {
|
||||
String msg = "Bean not found during lazy load or refresh." + " id[" + id + "] type[" + desc.getBeanType() + "]";
|
||||
throw new EntityNotFoundException(msg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanContext;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanRequest;
|
||||
import com.avaje.ebeaninternal.api.LoadManyContext;
|
||||
import com.avaje.ebeaninternal.api.LoadManyRequest;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
|
||||
/**
|
||||
* Helper to handle lazy loading and refreshing of beans.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class DefaultBeanLoader {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DefaultBeanLoader.class.getName());
|
||||
|
||||
private final DebugLazyLoad debugLazyLoad;
|
||||
|
||||
private final DefaultServer server;
|
||||
|
||||
protected DefaultBeanLoader(DefaultServer server, DebugLazyLoad debugLazyLoad) {
|
||||
this.server = server;
|
||||
this.debugLazyLoad = debugLazyLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a batch size that might be less than the requestedBatchSize.
|
||||
* <p>
|
||||
* This means we can have large and variable requestedBatchSizes.
|
||||
* </p>
|
||||
* <p>
|
||||
* We want to restrict the number of different batch sizes as we want to
|
||||
* re-use the query plan cache and get DB statement re-use.
|
||||
* </p>
|
||||
*/
|
||||
private int getBatchSize(int batchListSize, int requestedBatchSize) {
|
||||
if (batchListSize == requestedBatchSize) {
|
||||
return batchListSize;
|
||||
}
|
||||
if (batchListSize == 1) {
|
||||
// there is only one bean/collection to load
|
||||
return 1;
|
||||
}
|
||||
if (requestedBatchSize <= 5) {
|
||||
// anything less than 5 becomes 5
|
||||
return 5;
|
||||
}
|
||||
if (batchListSize <= 10 || requestedBatchSize <= 10) {
|
||||
// 10 or less to load
|
||||
// ... or we wanted a batch size between 6 and 10
|
||||
return 10;
|
||||
}
|
||||
if (batchListSize <= 20 || requestedBatchSize <= 20) {
|
||||
// 20 or less to load
|
||||
// ... or we wanted a batch size between 11 and 20
|
||||
return 20;
|
||||
}
|
||||
if (batchListSize <= 50) {
|
||||
return 50;
|
||||
}
|
||||
return requestedBatchSize;
|
||||
}
|
||||
|
||||
public void refreshMany(Object parentBean, String propertyName) {
|
||||
refreshMany(parentBean, propertyName, null);
|
||||
}
|
||||
|
||||
public void loadMany(LoadManyRequest loadRequest) {
|
||||
|
||||
List<BeanCollection<?>> batch = loadRequest.getBatch();
|
||||
|
||||
int batchSize = getBatchSize(batch.size(), loadRequest.getBatchSize());
|
||||
|
||||
LoadManyContext ctx = loadRequest.getLoadContext();
|
||||
BeanPropertyAssocMany<?> many = ctx.getBeanProperty();
|
||||
|
||||
PersistenceContext pc = ctx.getPersistenceContext();
|
||||
|
||||
ArrayList<Object> idList = new ArrayList<Object>(batchSize);
|
||||
|
||||
for (int i = 0; i < batch.size(); i++) {
|
||||
BeanCollection<?> bc = batch.get(i);
|
||||
Object ownerBean = bc.getOwnerBean();
|
||||
Object id = many.getParentId(ownerBean);
|
||||
idList.add(id);
|
||||
}
|
||||
int extraIds = batchSize - batch.size();
|
||||
if (extraIds > 0) {
|
||||
Object firstId = idList.get(0);
|
||||
for (int i = 0; i < extraIds; i++) {
|
||||
idList.add(firstId);
|
||||
}
|
||||
}
|
||||
|
||||
BeanDescriptor<?> desc = ctx.getBeanDescriptor();
|
||||
|
||||
String idProperty = desc.getIdBinder().getIdProperty();
|
||||
|
||||
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(desc.getBeanType());
|
||||
query.setMode(Mode.LAZYLOAD_MANY);
|
||||
query.setLazyLoadManyPath(many.getName());
|
||||
query.setPersistenceContext(pc);
|
||||
query.select(idProperty);
|
||||
query.fetch(many.getName());
|
||||
|
||||
if (idList.size() == 1) {
|
||||
query.where().idEq(idList.get(0));
|
||||
} else {
|
||||
query.where().idIn(idList);
|
||||
}
|
||||
|
||||
String mode = loadRequest.isLazy() ? "+lazy" : "+query";
|
||||
query.setLoadDescription(mode, loadRequest.getDescription());
|
||||
|
||||
// potentially changes the joins and selected properties
|
||||
ctx.configureQuery(query);
|
||||
|
||||
if (loadRequest.isOnlyIds()) {
|
||||
// override to just select the Id values
|
||||
query.fetch(many.getName(), many.getTargetIdProperty());
|
||||
}
|
||||
|
||||
server.findList(query, loadRequest.getTransaction());
|
||||
|
||||
// check for BeanCollection's that where never processed
|
||||
// in the +query or +lazy load due to no rows (predicates)
|
||||
for (int i = 0; i < batch.size(); i++) {
|
||||
BeanCollection<?> bc = batch.get(i);
|
||||
if (bc.checkEmptyLazyLoad()) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.fine("BeanCollection after load was empty. Owner:" + batch.get(i).getOwnerBean());
|
||||
}
|
||||
} else if (loadRequest.isLoadCache()) {
|
||||
Object parentId = desc.getId(bc.getOwnerBean());
|
||||
desc.cachePutMany(many, bc, parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadMany(BeanCollection<?> bc, LoadManyContext ctx, boolean onlyIds) {
|
||||
|
||||
Object parentBean = bc.getOwnerBean();
|
||||
String propertyName = bc.getPropertyName();
|
||||
|
||||
ObjectGraphNode node = ctx == null ? null : ctx.getObjectGraphNode();
|
||||
|
||||
loadManyInternal(parentBean, propertyName, null, false, node, onlyIds);
|
||||
|
||||
if (server.getAdminLogging().isDebugLazyLoad()) {
|
||||
|
||||
Class<?> cls = parentBean.getClass();
|
||||
BeanDescriptor<?> desc = server.getBeanDescriptor(cls);
|
||||
BeanPropertyAssocMany<?> many = (BeanPropertyAssocMany<?>) desc.getBeanProperty(propertyName);
|
||||
|
||||
StackTraceElement cause = debugLazyLoad.getStackTraceElement(cls);
|
||||
|
||||
String msg = "debug.lazyLoad " + many.getManyType() + " [" + desc + "][" + propertyName + "]";
|
||||
if (cause != null) {
|
||||
msg += " at: " + cause;
|
||||
}
|
||||
System.err.println(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshMany(Object parentBean, String propertyName, Transaction t) {
|
||||
loadManyInternal(parentBean, propertyName, t, true, null, false);
|
||||
}
|
||||
|
||||
private void loadManyInternal(Object parentBean, String propertyName, Transaction t, boolean refresh, ObjectGraphNode node, boolean onlyIds) {
|
||||
|
||||
boolean vanilla = (parentBean instanceof EntityBean == false);
|
||||
|
||||
EntityBeanIntercept ebi = null;
|
||||
PersistenceContext pc = null;
|
||||
BeanCollection<?> beanCollection = null;
|
||||
ExpressionList<?> filterMany = null;
|
||||
|
||||
if (!vanilla) {
|
||||
ebi = ((EntityBean) parentBean)._ebean_getIntercept();
|
||||
pc = ebi.getPersistenceContext();
|
||||
}
|
||||
|
||||
BeanDescriptor<?> parentDesc = server.getBeanDescriptor(parentBean.getClass());
|
||||
BeanPropertyAssocMany<?> many = (BeanPropertyAssocMany<?>) parentDesc.getBeanProperty(propertyName);
|
||||
|
||||
Object currentValue = many.getValueUnderlying(parentBean);
|
||||
if (currentValue instanceof BeanCollection<?>) {
|
||||
beanCollection = (BeanCollection<?>) currentValue;
|
||||
filterMany = beanCollection.getFilterMany();
|
||||
}
|
||||
|
||||
Object parentId = parentDesc.getId(parentBean);
|
||||
|
||||
if (pc == null) {
|
||||
pc = new DefaultPersistenceContext();
|
||||
pc.put(parentId, parentBean);
|
||||
}
|
||||
|
||||
boolean useManyIdCache = !vanilla && beanCollection != null && parentDesc.cacheIsUseManyId();
|
||||
if (useManyIdCache) {
|
||||
Boolean readOnly = null;
|
||||
if (ebi != null && ebi.isReadOnly()) {
|
||||
readOnly = Boolean.TRUE;
|
||||
}
|
||||
if (parentDesc.cacheLoadMany(many, beanCollection, parentId, readOnly, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(parentDesc.getBeanType());
|
||||
|
||||
if (refresh) {
|
||||
// populate a new collection
|
||||
Object emptyCollection = many.createEmpty(vanilla);
|
||||
many.setValue(parentBean, emptyCollection);
|
||||
query.setLoadDescription("+refresh", null);
|
||||
} else {
|
||||
query.setLoadDescription("+lazy", null);
|
||||
}
|
||||
|
||||
if (node != null) {
|
||||
// so we can hook back to the root query
|
||||
query.setParentNode(node);
|
||||
}
|
||||
|
||||
String idProperty = parentDesc.getIdBinder().getIdProperty();
|
||||
query.select(idProperty);
|
||||
|
||||
if (onlyIds) {
|
||||
query.fetch(many.getName(), many.getTargetIdProperty());
|
||||
} else {
|
||||
query.fetch(many.getName());
|
||||
}
|
||||
if (filterMany != null) {
|
||||
query.setFilterMany(many.getName(), filterMany);
|
||||
}
|
||||
|
||||
query.where().idEq(parentId);
|
||||
query.setUseCache(false);
|
||||
query.setMode(Mode.LAZYLOAD_MANY);
|
||||
query.setLazyLoadManyPath(many.getName());
|
||||
query.setPersistenceContext(pc);
|
||||
query.setVanillaMode(vanilla);
|
||||
|
||||
if (ebi != null) {
|
||||
if (ebi.isReadOnly()) {
|
||||
query.setReadOnly(true);
|
||||
}
|
||||
}
|
||||
|
||||
server.findUnique(query, t);
|
||||
|
||||
if (beanCollection != null) {
|
||||
if (beanCollection.checkEmptyLazyLoad()) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.fine("BeanCollection after load was empty. Owner:" + beanCollection.getOwnerBean());
|
||||
}
|
||||
} else if (useManyIdCache) {
|
||||
parentDesc.cachePutMany(many, beanCollection, parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a batch of beans for +query or +lazy loading.
|
||||
*/
|
||||
public void loadBean(LoadBeanRequest loadRequest) {
|
||||
|
||||
List<EntityBeanIntercept> batch = loadRequest.getBatch();
|
||||
|
||||
if (batch.isEmpty()) {
|
||||
throw new RuntimeException("Nothing in batch?");
|
||||
}
|
||||
|
||||
int batchSize = getBatchSize(batch.size(), loadRequest.getBatchSize());
|
||||
|
||||
LoadBeanContext ctx = loadRequest.getLoadContext();
|
||||
BeanDescriptor<?> desc = ctx.getBeanDescriptor();
|
||||
|
||||
Class<?> beanType = desc.getBeanType();
|
||||
|
||||
EntityBeanIntercept[] ebis = batch.toArray(new EntityBeanIntercept[batch.size()]);
|
||||
ArrayList<Object> idList = new ArrayList<Object>(batchSize);
|
||||
|
||||
for (int i = 0; i < batch.size(); i++) {
|
||||
EntityBeanIntercept ebi = batch.get(i);
|
||||
Object bean = ebi.getOwner();
|
||||
Object id = desc.getId(bean);
|
||||
idList.add(id);
|
||||
}
|
||||
|
||||
if (idList.isEmpty()) {
|
||||
// everything was loaded from cache
|
||||
return;
|
||||
}
|
||||
|
||||
int extraIds = batchSize - batch.size();
|
||||
if (extraIds > 0) {
|
||||
// for performance make up the Id's to the batch size
|
||||
// so we get the same query (for Ebean and the db)
|
||||
Object firstId = idList.get(0);
|
||||
for (int i = 0; i < extraIds; i++) {
|
||||
// just add the first Id again
|
||||
idList.add(firstId);
|
||||
}
|
||||
}
|
||||
|
||||
PersistenceContext persistenceContext = ctx.getPersistenceContext();
|
||||
|
||||
// query the database
|
||||
for (int i = 0; i < ebis.length; i++) {
|
||||
Object parentBean = ebis[i].getParentBean();
|
||||
if (parentBean != null) {
|
||||
// Special case for OneToOne
|
||||
BeanDescriptor<?> parentDesc = server.getBeanDescriptor(parentBean.getClass());
|
||||
Object parentId = parentDesc.getId(parentBean);
|
||||
persistenceContext.put(parentId, parentBean);
|
||||
}
|
||||
}
|
||||
|
||||
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(beanType);
|
||||
|
||||
query.setMode(Mode.LAZYLOAD_BEAN);
|
||||
query.setPersistenceContext(persistenceContext);
|
||||
|
||||
String mode = loadRequest.isLazy() ? "+lazy" : "+query";
|
||||
query.setLoadDescription(mode, loadRequest.getDescription());
|
||||
|
||||
ctx.configureQuery(query, loadRequest.getLazyLoadProperty());
|
||||
|
||||
// make sure the query doesn't use the cache
|
||||
// query.setUseCache(false);
|
||||
if (idList.size() == 1) {
|
||||
query.where().idEq(idList.get(0));
|
||||
} else {
|
||||
query.where().idIn(idList);
|
||||
}
|
||||
|
||||
List<?> list = server.findList(query, loadRequest.getTransaction());
|
||||
|
||||
if (loadRequest.isLoadCache()) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
desc.cachePutBeanData(list.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < ebis.length; i++) {
|
||||
if (ebis[i].isReference()) {
|
||||
// The underlying row in DB was deleted. Mark this bean as 'failed'
|
||||
// but allow processing to continue until it is accessed by client code
|
||||
ebis[i].setLazyLoadFailure();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void refresh(Object bean) {
|
||||
refreshBeanInternal(bean, SpiQuery.Mode.REFRESH_BEAN);
|
||||
}
|
||||
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
refreshBeanInternal(ebi.getOwner(), SpiQuery.Mode.LAZYLOAD_BEAN);
|
||||
}
|
||||
|
||||
private void refreshBeanInternal(Object bean, SpiQuery.Mode mode) {
|
||||
|
||||
boolean vanilla = (bean instanceof EntityBean == false);
|
||||
|
||||
EntityBeanIntercept ebi = null;
|
||||
PersistenceContext pc = null;
|
||||
|
||||
if (!vanilla) {
|
||||
ebi = ((EntityBean) bean)._ebean_getIntercept();
|
||||
pc = ebi.getPersistenceContext();
|
||||
}
|
||||
|
||||
BeanDescriptor<?> desc = server.getBeanDescriptor(bean.getClass());
|
||||
Object id = desc.getId(bean);
|
||||
|
||||
if (pc == null) {
|
||||
// a reference with no existing persistenceContext
|
||||
pc = new DefaultPersistenceContext();
|
||||
pc.put(id, bean);
|
||||
if (ebi != null) {
|
||||
ebi.setPersistenceContext(pc);
|
||||
}
|
||||
}
|
||||
|
||||
if (ebi != null) {
|
||||
if (SpiQuery.Mode.LAZYLOAD_BEAN.equals(mode) && desc.isBeanCaching()) {
|
||||
// lazy loading and the bean cache is active
|
||||
if (desc.loadFromCache(bean, ebi, id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (desc.lazyLoadMany(ebi)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(desc.getBeanType());
|
||||
if (ebi != null) {
|
||||
Object parentBean = ebi.getParentBean();
|
||||
if (parentBean != null) {
|
||||
// Special case for OneToOne
|
||||
BeanDescriptor<?> parentDesc = server.getBeanDescriptor(parentBean.getClass());
|
||||
Object parentId = parentDesc.getId(parentBean);
|
||||
pc.putIfAbsent(parentId, parentBean);
|
||||
}
|
||||
|
||||
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
|
||||
}
|
||||
|
||||
// don't collect autoFetch usage profiling information
|
||||
// as we just copy the data out of these fetched beans
|
||||
// and put the data into the original bean
|
||||
query.setUsageProfiling(false);
|
||||
query.setPersistenceContext(pc);
|
||||
|
||||
query.setMode(mode);
|
||||
query.setId(id);
|
||||
// make sure the query doesn't use the cache
|
||||
if (mode.equals(SpiQuery.Mode.REFRESH_BEAN)) {
|
||||
query.setUseCache(false);
|
||||
}
|
||||
query.setVanillaMode(vanilla);
|
||||
|
||||
if (ebi != null && ebi.isReadOnly()) {
|
||||
query.setReadOnly(true);
|
||||
}
|
||||
|
||||
Object dbBean = query.findUnique();
|
||||
if (dbBean == null) {
|
||||
String msg = "Bean not found during lazy load or refresh." + " id[" + id + "] type[" + desc.getBeanType() + "]";
|
||||
throw new EntityNotFoundException(msg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,143 +1,124 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.avaje.ebean.CallableSql;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.api.SpiCallableSql;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable;
|
||||
import com.avaje.ebeaninternal.api.BindParams.Param;
|
||||
|
||||
|
||||
public class DefaultCallableSql implements Serializable, SpiCallableSql {
|
||||
|
||||
private static final long serialVersionUID = 8984272253185424701L;
|
||||
|
||||
private transient final EbeanServer server;
|
||||
|
||||
/**
|
||||
* The callable sql.
|
||||
*/
|
||||
private String sql;
|
||||
|
||||
/**
|
||||
* To display in the transaction log to help identify the procedure.
|
||||
*/
|
||||
private String label;
|
||||
|
||||
private int timeout;
|
||||
|
||||
/**
|
||||
* Holds the table modification information. On commit this information is
|
||||
* used to manage the cache etc.
|
||||
*/
|
||||
private TransactionEventTable transactionEvent = new TransactionEventTable();
|
||||
|
||||
private BindParams bindParameters = new BindParams();
|
||||
|
||||
/**
|
||||
* Create with callable sql.
|
||||
*/
|
||||
public DefaultCallableSql(EbeanServer server, String sql) {
|
||||
this.server = server;
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
server.execute(this, null);
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public CallableSql setLabel(String label) {
|
||||
this.label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public CallableSql setTimeout(int secs) {
|
||||
this.timeout = secs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CallableSql setSql(String sql) {
|
||||
this.sql = sql;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CallableSql bind(int position, Object value) {
|
||||
bindParameters.setParameter(position, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CallableSql setParameter(int position, Object value) {
|
||||
bindParameters.setParameter(position, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CallableSql registerOut(int position, int type) {
|
||||
bindParameters.registerOut(position, type);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object getObject(int position) {
|
||||
Param p = bindParameters.getParameter(position);
|
||||
return p.getOutValue();
|
||||
}
|
||||
|
||||
public boolean executeOverride(CallableStatement cstmt) throws SQLException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public CallableSql addModification(String tableName, boolean inserts, boolean updates,
|
||||
boolean deletes) {
|
||||
|
||||
transactionEvent.add(tableName, inserts, updates, deletes);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TransactionEvent which holds the table modification
|
||||
* information for this CallableSql. This information is merged into the
|
||||
* transaction after the transaction is commited.
|
||||
*/
|
||||
public TransactionEventTable getTransactionEventTable() {
|
||||
return transactionEvent;
|
||||
}
|
||||
|
||||
public BindParams getBindParams() {
|
||||
return bindParameters;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.avaje.ebean.CallableSql;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.api.SpiCallableSql;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable;
|
||||
import com.avaje.ebeaninternal.api.BindParams.Param;
|
||||
|
||||
|
||||
public class DefaultCallableSql implements Serializable, SpiCallableSql {
|
||||
|
||||
private static final long serialVersionUID = 8984272253185424701L;
|
||||
|
||||
private transient final EbeanServer server;
|
||||
|
||||
/**
|
||||
* The callable sql.
|
||||
*/
|
||||
private String sql;
|
||||
|
||||
/**
|
||||
* To display in the transaction log to help identify the procedure.
|
||||
*/
|
||||
private String label;
|
||||
|
||||
private int timeout;
|
||||
|
||||
/**
|
||||
* Holds the table modification information. On commit this information is
|
||||
* used to manage the cache etc.
|
||||
*/
|
||||
private TransactionEventTable transactionEvent = new TransactionEventTable();
|
||||
|
||||
private BindParams bindParameters = new BindParams();
|
||||
|
||||
/**
|
||||
* Create with callable sql.
|
||||
*/
|
||||
public DefaultCallableSql(EbeanServer server, String sql) {
|
||||
this.server = server;
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
server.execute(this, null);
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public CallableSql setLabel(String label) {
|
||||
this.label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public CallableSql setTimeout(int secs) {
|
||||
this.timeout = secs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CallableSql setSql(String sql) {
|
||||
this.sql = sql;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CallableSql bind(int position, Object value) {
|
||||
bindParameters.setParameter(position, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CallableSql setParameter(int position, Object value) {
|
||||
bindParameters.setParameter(position, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CallableSql registerOut(int position, int type) {
|
||||
bindParameters.registerOut(position, type);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object getObject(int position) {
|
||||
Param p = bindParameters.getParameter(position);
|
||||
return p.getOutValue();
|
||||
}
|
||||
|
||||
public boolean executeOverride(CallableStatement cstmt) throws SQLException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public CallableSql addModification(String tableName, boolean inserts, boolean updates,
|
||||
boolean deletes) {
|
||||
|
||||
transactionEvent.add(tableName, inserts, updates, deletes);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TransactionEvent which holds the table modification
|
||||
* information for this CallableSql. This information is merged into the
|
||||
* transaction after the transaction is commited.
|
||||
*/
|
||||
public TransactionEventTable getTransactionEventTable() {
|
||||
return transactionEvent;
|
||||
}
|
||||
|
||||
public BindParams getBindParams() {
|
||||
return bindParameters;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,246 +1,227 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.Update;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.api.SpiSqlUpdate;
|
||||
|
||||
/**
|
||||
* A SQL Update Delete or Insert statement that can be executed. For the times
|
||||
* when you want to use Sql DML rather than a ORM bean approach. Refer to the
|
||||
* Ebean execute() method.
|
||||
* <p>
|
||||
* There is also {@link Update} which is similar except should use logical bean and
|
||||
* property names rather than physical table and column names.
|
||||
* </p>
|
||||
* <p>
|
||||
* SqlUpdate is designed for general DML sql and CallableSql is
|
||||
* designed for use with stored procedures.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // String sql = "update f_topic set post_count = :count where id = :topicId";
|
||||
*
|
||||
* SqlUpdate update = new SqlUpdate(sql);
|
||||
* update.setParameter("count", 1);
|
||||
* update.setParameter("topicId", 50);
|
||||
*
|
||||
* int modifiedCount = Ebean.execute(update);
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Note that when the SqlUpdate is executed via Ebean.execute() the sql is
|
||||
* parsed to determine if it is an update, delete or insert. In addition the
|
||||
* table modified is deduced. If <em>isAutoTableMod()</em> is true, then this
|
||||
* is then added to the TransactionEvent and cache invalidation etc is
|
||||
* maintained. This means you don't need to use the Ebean.externalModification()
|
||||
* method as this has already been done.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can sql.setAutoTableMod(false); to stop the automatic table modification
|
||||
* </p>
|
||||
* <p>
|
||||
* EXAMPLE: Using JDBC batching with SqlUpdate
|
||||
* </p>
|
||||
* <pre class="code">
|
||||
*
|
||||
* String data = "This is a simple test of the batch processing"
|
||||
* + " mode and the transaction execute batch method";
|
||||
*
|
||||
* String[] da = data.split(" ");
|
||||
*
|
||||
* String sql = "insert into junk (word) values (?)";
|
||||
*
|
||||
* SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql);
|
||||
*
|
||||
* Transaction t = Ebean.beginTransaction();
|
||||
* t.setBatchMode(true);
|
||||
* t.setBatchSize(3);
|
||||
* try {
|
||||
* for (int i = 0; i < da.length; i++) {
|
||||
*
|
||||
* sqlUpdate.setParameter(1, da[i]);
|
||||
* sqlUpdate.execute();
|
||||
* }
|
||||
*
|
||||
* // NB: commit implicitly flushes the batch
|
||||
* Ebean.commitTransaction();
|
||||
*
|
||||
* } finally {
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* </pre>
|
||||
* @see com.avaje.ebean.CallableSql
|
||||
* @see com.avaje.ebean.Ebean#execute(SqlUpdate)
|
||||
*/
|
||||
public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
|
||||
|
||||
private static final long serialVersionUID = -6493829438421253102L;
|
||||
|
||||
private transient final EbeanServer server;
|
||||
|
||||
/**
|
||||
* The parameters used to bind to the sql.
|
||||
*/
|
||||
private final BindParams bindParams;
|
||||
|
||||
/**
|
||||
* The sql update or delete statement.
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
/**
|
||||
* Some descriptive text that can be put into the transaction log.
|
||||
*/
|
||||
private String label = "";
|
||||
|
||||
/**
|
||||
* The statement execution timeout.
|
||||
*/
|
||||
private int timeout;
|
||||
|
||||
/**
|
||||
* Automatically detect the table being modified by this sql. This will
|
||||
* register this information so that eBean invalidates cached objects if
|
||||
* required.
|
||||
*/
|
||||
private boolean isAutoTableMod = true;
|
||||
|
||||
/**
|
||||
* Helper to add positioned parameters in order.
|
||||
*/
|
||||
private int addPos;
|
||||
|
||||
/**
|
||||
* Create with server sql and bindParams object.
|
||||
* <p>
|
||||
* Useful if you are building the sql and binding parameters at the
|
||||
* same time.
|
||||
* </p>
|
||||
*/
|
||||
public DefaultSqlUpdate(EbeanServer server, String sql, BindParams bindParams) {
|
||||
this.server = server;
|
||||
this.sql = sql;
|
||||
this.bindParams = bindParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with a specific server. This means you can use the
|
||||
* SqlUpdate.execute() method.
|
||||
*/
|
||||
public DefaultSqlUpdate(EbeanServer server, String sql) {
|
||||
this(server, sql, new BindParams());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with some sql.
|
||||
*/
|
||||
public DefaultSqlUpdate(String sql) {
|
||||
this(null, sql, new BindParams());
|
||||
}
|
||||
|
||||
public int execute() {
|
||||
if (server != null) {
|
||||
return server.execute(this);
|
||||
} else {
|
||||
// Hopefully this doesn't catch anyone out...
|
||||
return Ebean.execute(this);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAutoTableMod() {
|
||||
return isAutoTableMod;
|
||||
}
|
||||
|
||||
public SqlUpdate setAutoTableMod(boolean isAutoTableMod) {
|
||||
this.isAutoTableMod = isAutoTableMod;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public SqlUpdate setLabel(String label) {
|
||||
this.label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public SqlUpdate setTimeout(int secs) {
|
||||
this.timeout = secs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate addParameter(Object value) {
|
||||
return setParameter(++addPos, value);
|
||||
}
|
||||
|
||||
public SqlUpdate setParameter(int position, Object value) {
|
||||
bindParams.setParameter(position, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate setNull(int position, int jdbcType) {
|
||||
bindParams.setNullParameter(position, jdbcType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate setNullParameter(int position, int jdbcType) {
|
||||
bindParams.setNullParameter(position, jdbcType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate setParameter(String name, Object param) {
|
||||
bindParams.setParameter(name, param);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate setNull(String name, int jdbcType) {
|
||||
bindParams.setNullParameter(name, jdbcType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate setNullParameter(String name, int jdbcType) {
|
||||
bindParams.setNullParameter(name, jdbcType);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bind parameters.
|
||||
*/
|
||||
public BindParams getBindParams() {
|
||||
return bindParams;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.Update;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.api.SpiSqlUpdate;
|
||||
|
||||
/**
|
||||
* A SQL Update Delete or Insert statement that can be executed. For the times
|
||||
* when you want to use Sql DML rather than a ORM bean approach. Refer to the
|
||||
* Ebean execute() method.
|
||||
* <p>
|
||||
* There is also {@link Update} which is similar except should use logical bean and
|
||||
* property names rather than physical table and column names.
|
||||
* </p>
|
||||
* <p>
|
||||
* SqlUpdate is designed for general DML sql and CallableSql is
|
||||
* designed for use with stored procedures.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // String sql = "update f_topic set post_count = :count where id = :topicId";
|
||||
*
|
||||
* SqlUpdate update = new SqlUpdate(sql);
|
||||
* update.setParameter("count", 1);
|
||||
* update.setParameter("topicId", 50);
|
||||
*
|
||||
* int modifiedCount = Ebean.execute(update);
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Note that when the SqlUpdate is executed via Ebean.execute() the sql is
|
||||
* parsed to determine if it is an update, delete or insert. In addition the
|
||||
* table modified is deduced. If <em>isAutoTableMod()</em> is true, then this
|
||||
* is then added to the TransactionEvent and cache invalidation etc is
|
||||
* maintained. This means you don't need to use the Ebean.externalModification()
|
||||
* method as this has already been done.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can sql.setAutoTableMod(false); to stop the automatic table modification
|
||||
* </p>
|
||||
* <p>
|
||||
* EXAMPLE: Using JDBC batching with SqlUpdate
|
||||
* </p>
|
||||
* <pre class="code">
|
||||
*
|
||||
* String data = "This is a simple test of the batch processing"
|
||||
* + " mode and the transaction execute batch method";
|
||||
*
|
||||
* String[] da = data.split(" ");
|
||||
*
|
||||
* String sql = "insert into junk (word) values (?)";
|
||||
*
|
||||
* SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql);
|
||||
*
|
||||
* Transaction t = Ebean.beginTransaction();
|
||||
* t.setBatchMode(true);
|
||||
* t.setBatchSize(3);
|
||||
* try {
|
||||
* for (int i = 0; i < da.length; i++) {
|
||||
*
|
||||
* sqlUpdate.setParameter(1, da[i]);
|
||||
* sqlUpdate.execute();
|
||||
* }
|
||||
*
|
||||
* // NB: commit implicitly flushes the batch
|
||||
* Ebean.commitTransaction();
|
||||
*
|
||||
* } finally {
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* </pre>
|
||||
* @see com.avaje.ebean.CallableSql
|
||||
* @see com.avaje.ebean.Ebean#execute(SqlUpdate)
|
||||
*/
|
||||
public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
|
||||
|
||||
private static final long serialVersionUID = -6493829438421253102L;
|
||||
|
||||
private transient final EbeanServer server;
|
||||
|
||||
/**
|
||||
* The parameters used to bind to the sql.
|
||||
*/
|
||||
private final BindParams bindParams;
|
||||
|
||||
/**
|
||||
* The sql update or delete statement.
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
/**
|
||||
* Some descriptive text that can be put into the transaction log.
|
||||
*/
|
||||
private String label = "";
|
||||
|
||||
/**
|
||||
* The statement execution timeout.
|
||||
*/
|
||||
private int timeout;
|
||||
|
||||
/**
|
||||
* Automatically detect the table being modified by this sql. This will
|
||||
* register this information so that eBean invalidates cached objects if
|
||||
* required.
|
||||
*/
|
||||
private boolean isAutoTableMod = true;
|
||||
|
||||
/**
|
||||
* Helper to add positioned parameters in order.
|
||||
*/
|
||||
private int addPos;
|
||||
|
||||
/**
|
||||
* Create with server sql and bindParams object.
|
||||
* <p>
|
||||
* Useful if you are building the sql and binding parameters at the
|
||||
* same time.
|
||||
* </p>
|
||||
*/
|
||||
public DefaultSqlUpdate(EbeanServer server, String sql, BindParams bindParams) {
|
||||
this.server = server;
|
||||
this.sql = sql;
|
||||
this.bindParams = bindParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with a specific server. This means you can use the
|
||||
* SqlUpdate.execute() method.
|
||||
*/
|
||||
public DefaultSqlUpdate(EbeanServer server, String sql) {
|
||||
this(server, sql, new BindParams());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with some sql.
|
||||
*/
|
||||
public DefaultSqlUpdate(String sql) {
|
||||
this(null, sql, new BindParams());
|
||||
}
|
||||
|
||||
public int execute() {
|
||||
if (server != null) {
|
||||
return server.execute(this);
|
||||
} else {
|
||||
// Hopefully this doesn't catch anyone out...
|
||||
return Ebean.execute(this);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAutoTableMod() {
|
||||
return isAutoTableMod;
|
||||
}
|
||||
|
||||
public SqlUpdate setAutoTableMod(boolean isAutoTableMod) {
|
||||
this.isAutoTableMod = isAutoTableMod;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public SqlUpdate setLabel(String label) {
|
||||
this.label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public SqlUpdate setTimeout(int secs) {
|
||||
this.timeout = secs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate addParameter(Object value) {
|
||||
return setParameter(++addPos, value);
|
||||
}
|
||||
|
||||
public SqlUpdate setParameter(int position, Object value) {
|
||||
bindParams.setParameter(position, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate setNull(int position, int jdbcType) {
|
||||
bindParams.setNullParameter(position, jdbcType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate setNullParameter(int position, int jdbcType) {
|
||||
bindParams.setNullParameter(position, jdbcType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate setParameter(String name, Object param) {
|
||||
bindParams.setParameter(name, param);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate setNull(String name, int jdbcType) {
|
||||
bindParams.setNullParameter(name, jdbcType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlUpdate setNullParameter(String name, int jdbcType) {
|
||||
bindParams.setNullParameter(name, jdbcType);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bind parameters.
|
||||
*/
|
||||
public BindParams getBindParams() {
|
||||
return bindParams;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,177 +1,158 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.util.ValueUtil;
|
||||
|
||||
/**
|
||||
* Helper to perform a diff given two beans of the same type.
|
||||
* <p>
|
||||
* This intentionally does not include any OneToMany or ManyToMany properties.
|
||||
* </p>
|
||||
*/
|
||||
public class DiffHelp {
|
||||
|
||||
|
||||
/**
|
||||
* Return a map of the differences between a and b.
|
||||
* <p>
|
||||
* A and B must be of the same type. B can be null, in which case the
|
||||
* 'OldValues' of a is used to compare with (as B).
|
||||
* </p>
|
||||
* <p>
|
||||
* This intentionally does not include as OneToMany or ManyToMany
|
||||
* properties.
|
||||
* </p>
|
||||
*/
|
||||
public Map<String, ValuePair> diff(Object a, Object b, BeanDescriptor<?> desc) {
|
||||
|
||||
boolean oldValues = false;
|
||||
if (b == null) {
|
||||
// get the old values from a
|
||||
if (a instanceof EntityBean) {
|
||||
EntityBean eb = (EntityBean) a;
|
||||
b = eb._ebean_getIntercept().getOldValues();
|
||||
oldValues = true;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, ValuePair> map = new LinkedHashMap<String, ValuePair>();
|
||||
|
||||
if (b == null) {
|
||||
return map;
|
||||
}
|
||||
|
||||
// check the simple properties
|
||||
BeanProperty[] base = desc.propertiesBaseScalar();
|
||||
for (int i = 0; i < base.length; i++) {
|
||||
|
||||
Object aval = base[i].getValue(a);
|
||||
Object bval = base[i].getValue(b);
|
||||
if (!ValueUtil.areEqual(aval, bval)) {
|
||||
map.put(base[i].getName(), new ValuePair(aval, bval));
|
||||
}
|
||||
}
|
||||
|
||||
diffAssocOne(a, b, desc, map);
|
||||
diffEmbedded(a, b, desc, map, oldValues);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the Embedded bean properties for differences.
|
||||
* <p>
|
||||
* If ANY of the properties are different then the whole Embedded bean is
|
||||
* determined to be different as is added to the map.
|
||||
* </p>
|
||||
*/
|
||||
private void diffEmbedded(Object a, Object b, BeanDescriptor<?> desc, Map<String, ValuePair> map,
|
||||
boolean oldValues) {
|
||||
|
||||
BeanPropertyAssocOne<?>[] emb = desc.propertiesEmbedded();
|
||||
|
||||
for (int i = 0; i < emb.length; i++) {
|
||||
Object aval = emb[i].getValue(a);
|
||||
Object bval = emb[i].getValue(b);
|
||||
if (oldValues) {
|
||||
bval = ((EntityBean) bval)._ebean_getIntercept().getOldValues();
|
||||
if (bval == null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isBothNull(aval, bval)) {
|
||||
if (isDiffNull(aval, bval)) {
|
||||
// one of the embedded beans is null
|
||||
map.put(emb[i].getName(), new ValuePair(aval, bval));
|
||||
|
||||
} else {
|
||||
// if ANY of the properties in an Embedded bean is
|
||||
// different, treat the whole bean as being different
|
||||
BeanProperty[] props = emb[i].getProperties();
|
||||
for (int j = 0; j < props.length; j++) {
|
||||
Object aEmbPropVal = props[j].getValue(aval);
|
||||
Object bEmbPropVal = props[j].getValue(bval);
|
||||
if (!ValueUtil.areEqual(aEmbPropVal, bEmbPropVal)) {
|
||||
|
||||
// if one prop is different put the
|
||||
// embedded bean in the map
|
||||
map.put(emb[i].getName(), new ValuePair(aval, bval));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the properties are different by null OR if the id value is different,
|
||||
* then add the Assoc One bean to the map.
|
||||
*/
|
||||
private void diffAssocOne(Object a, Object b, BeanDescriptor<?> desc, Map<String, ValuePair> map) {
|
||||
|
||||
BeanPropertyAssocOne<?>[] ones = desc.propertiesOne();
|
||||
|
||||
for (int i = 0; i < ones.length; i++) {
|
||||
Object aval = ones[i].getValue(a);
|
||||
Object bval = ones[i].getValue(b);
|
||||
|
||||
if (!isBothNull(aval, bval)) {
|
||||
if (isDiffNull(aval, bval)) {
|
||||
// one of them is/was null
|
||||
map.put(ones[i].getName(), new ValuePair(aval, bval));
|
||||
|
||||
} else {
|
||||
// check to see if the Id properties
|
||||
// are different
|
||||
BeanDescriptor<?> oneDesc = ones[i].getTargetDescriptor();
|
||||
Object aOneId = oneDesc.getId(aval);
|
||||
Object bOneId = oneDesc.getId(bval);
|
||||
|
||||
if (!ValueUtil.areEqual(aOneId, bOneId)) {
|
||||
// the ids are different
|
||||
map.put(ones[i].getName(), new ValuePair(aval, bval));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBothNull(Object aval, Object bval) {
|
||||
return aval == null && bval == null;
|
||||
}
|
||||
|
||||
private boolean isDiffNull(Object aval, Object bval) {
|
||||
if (aval == null) {
|
||||
return bval != null;
|
||||
} else {
|
||||
return bval == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.util.ValueUtil;
|
||||
|
||||
/**
|
||||
* Helper to perform a diff given two beans of the same type.
|
||||
* <p>
|
||||
* This intentionally does not include any OneToMany or ManyToMany properties.
|
||||
* </p>
|
||||
*/
|
||||
public class DiffHelp {
|
||||
|
||||
|
||||
/**
|
||||
* Return a map of the differences between a and b.
|
||||
* <p>
|
||||
* A and B must be of the same type. B can be null, in which case the
|
||||
* 'OldValues' of a is used to compare with (as B).
|
||||
* </p>
|
||||
* <p>
|
||||
* This intentionally does not include as OneToMany or ManyToMany
|
||||
* properties.
|
||||
* </p>
|
||||
*/
|
||||
public Map<String, ValuePair> diff(Object a, Object b, BeanDescriptor<?> desc) {
|
||||
|
||||
boolean oldValues = false;
|
||||
if (b == null) {
|
||||
// get the old values from a
|
||||
if (a instanceof EntityBean) {
|
||||
EntityBean eb = (EntityBean) a;
|
||||
b = eb._ebean_getIntercept().getOldValues();
|
||||
oldValues = true;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, ValuePair> map = new LinkedHashMap<String, ValuePair>();
|
||||
|
||||
if (b == null) {
|
||||
return map;
|
||||
}
|
||||
|
||||
// check the simple properties
|
||||
BeanProperty[] base = desc.propertiesBaseScalar();
|
||||
for (int i = 0; i < base.length; i++) {
|
||||
|
||||
Object aval = base[i].getValue(a);
|
||||
Object bval = base[i].getValue(b);
|
||||
if (!ValueUtil.areEqual(aval, bval)) {
|
||||
map.put(base[i].getName(), new ValuePair(aval, bval));
|
||||
}
|
||||
}
|
||||
|
||||
diffAssocOne(a, b, desc, map);
|
||||
diffEmbedded(a, b, desc, map, oldValues);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the Embedded bean properties for differences.
|
||||
* <p>
|
||||
* If ANY of the properties are different then the whole Embedded bean is
|
||||
* determined to be different as is added to the map.
|
||||
* </p>
|
||||
*/
|
||||
private void diffEmbedded(Object a, Object b, BeanDescriptor<?> desc, Map<String, ValuePair> map,
|
||||
boolean oldValues) {
|
||||
|
||||
BeanPropertyAssocOne<?>[] emb = desc.propertiesEmbedded();
|
||||
|
||||
for (int i = 0; i < emb.length; i++) {
|
||||
Object aval = emb[i].getValue(a);
|
||||
Object bval = emb[i].getValue(b);
|
||||
if (oldValues) {
|
||||
bval = ((EntityBean) bval)._ebean_getIntercept().getOldValues();
|
||||
if (bval == null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isBothNull(aval, bval)) {
|
||||
if (isDiffNull(aval, bval)) {
|
||||
// one of the embedded beans is null
|
||||
map.put(emb[i].getName(), new ValuePair(aval, bval));
|
||||
|
||||
} else {
|
||||
// if ANY of the properties in an Embedded bean is
|
||||
// different, treat the whole bean as being different
|
||||
BeanProperty[] props = emb[i].getProperties();
|
||||
for (int j = 0; j < props.length; j++) {
|
||||
Object aEmbPropVal = props[j].getValue(aval);
|
||||
Object bEmbPropVal = props[j].getValue(bval);
|
||||
if (!ValueUtil.areEqual(aEmbPropVal, bEmbPropVal)) {
|
||||
|
||||
// if one prop is different put the
|
||||
// embedded bean in the map
|
||||
map.put(emb[i].getName(), new ValuePair(aval, bval));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the properties are different by null OR if the id value is different,
|
||||
* then add the Assoc One bean to the map.
|
||||
*/
|
||||
private void diffAssocOne(Object a, Object b, BeanDescriptor<?> desc, Map<String, ValuePair> map) {
|
||||
|
||||
BeanPropertyAssocOne<?>[] ones = desc.propertiesOne();
|
||||
|
||||
for (int i = 0; i < ones.length; i++) {
|
||||
Object aval = ones[i].getValue(a);
|
||||
Object bval = ones[i].getValue(b);
|
||||
|
||||
if (!isBothNull(aval, bval)) {
|
||||
if (isDiffNull(aval, bval)) {
|
||||
// one of them is/was null
|
||||
map.put(ones[i].getName(), new ValuePair(aval, bval));
|
||||
|
||||
} else {
|
||||
// check to see if the Id properties
|
||||
// are different
|
||||
BeanDescriptor<?> oneDesc = ones[i].getTargetDescriptor();
|
||||
Object aOneId = oneDesc.getId(aval);
|
||||
Object bOneId = oneDesc.getId(bval);
|
||||
|
||||
if (!ValueUtil.areEqual(aOneId, bOneId)) {
|
||||
// the ids are different
|
||||
map.put(ones[i].getName(), new ValuePair(aval, bval));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBothNull(Object aval, Object bval) {
|
||||
return aval == null && bval == null;
|
||||
}
|
||||
|
||||
private boolean isDiffNull(Object aval, Object bval) {
|
||||
if (aval == null) {
|
||||
return bval != null;
|
||||
} else {
|
||||
return bval == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,295 +1,276 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ExternalTransactionManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.ldap.LdapConfig;
|
||||
import com.avaje.ebean.config.ldap.LdapContextFactory;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import com.avaje.ebean.text.json.JsonValueAdapter;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployOrmXml;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil;
|
||||
import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory;
|
||||
import com.avaje.ebeaninternal.server.jmx.MAdminLogging;
|
||||
import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
import com.avaje.ebeaninternal.server.persist.DefaultPersister;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.DefaultOrmQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.DefaultRelationalQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManager;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.subclass.SubClassManager;
|
||||
import com.avaje.ebeaninternal.server.text.json.DJsonContext;
|
||||
import com.avaje.ebeaninternal.server.text.json.DefaultJsonValueAdapter;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.ExternalTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.JtaTransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.type.DefaultTypeManager;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
|
||||
/**
|
||||
* Used to extend the ServerConfig with additional objects used to configure and
|
||||
* construct an EbeanServer.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class InternalConfiguration {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(InternalConfiguration.class.getName());
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final BootupClasses bootupClasses;
|
||||
|
||||
private final SubClassManager subClassManager;
|
||||
|
||||
private final DeployInherit deployInherit;
|
||||
|
||||
private final ResourceManager resourceManager;
|
||||
|
||||
private final DeployOrmXml deployOrmXml;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
private final Binder binder;
|
||||
|
||||
private final DeployCreateProperties deployCreateProperties;
|
||||
|
||||
private final DeployUtil deployUtil;
|
||||
|
||||
private final BeanDescriptorManager beanDescriptorManager;
|
||||
|
||||
private final MAdminLogging logControl;
|
||||
|
||||
private final DebugLazyLoad debugLazyLoad;
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final TransactionScopeManager transactionScopeManager;
|
||||
|
||||
private final CQueryEngine cQueryEngine;
|
||||
|
||||
private final ClusterManager clusterManager;
|
||||
|
||||
private final ServerCacheManager cacheManager;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
|
||||
private final SpiBackgroundExecutor backgroundExecutor;
|
||||
|
||||
private final PstmtBatch pstmtBatch;
|
||||
|
||||
private final XmlConfig xmlConfig;
|
||||
|
||||
public InternalConfiguration(XmlConfig xmlConfig, ClusterManager clusterManager, ServerCacheManager cacheManager,
|
||||
SpiBackgroundExecutor backgroundExecutor, ServerConfig serverConfig, BootupClasses bootupClasses, PstmtBatch pstmtBatch) {
|
||||
|
||||
this.xmlConfig = xmlConfig;
|
||||
this.pstmtBatch = pstmtBatch;
|
||||
this.clusterManager = clusterManager;
|
||||
this.backgroundExecutor = backgroundExecutor;
|
||||
this.cacheManager = cacheManager;
|
||||
this.serverConfig = serverConfig;
|
||||
this.bootupClasses = bootupClasses;
|
||||
this.expressionFactory = new DefaultExpressionFactory();
|
||||
|
||||
this.subClassManager = new SubClassManager(serverConfig);
|
||||
|
||||
this.typeManager = new DefaultTypeManager(serverConfig, bootupClasses);
|
||||
this.binder = new Binder(typeManager);
|
||||
|
||||
this.resourceManager = ResourceManagerFactory.createResourceManager(serverConfig);
|
||||
this.deployOrmXml = new DeployOrmXml(resourceManager.getResourceSource());
|
||||
this.deployInherit = new DeployInherit(bootupClasses);
|
||||
|
||||
this.deployCreateProperties = new DeployCreateProperties(typeManager);
|
||||
this.deployUtil = new DeployUtil(typeManager, serverConfig);
|
||||
|
||||
this.beanDescriptorManager = new BeanDescriptorManager(this);
|
||||
beanDescriptorManager.deploy();
|
||||
|
||||
this.debugLazyLoad = new DebugLazyLoad(serverConfig.isDebugLazyLoad());
|
||||
|
||||
this.transactionManager = new TransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager,
|
||||
this.getBootupClasses());
|
||||
|
||||
this.logControl = new MAdminLogging(serverConfig, transactionManager);
|
||||
|
||||
this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), logControl, binder, backgroundExecutor);
|
||||
|
||||
ExternalTransactionManager externalTransactionManager = serverConfig.getExternalTransactionManager();
|
||||
if (externalTransactionManager == null && serverConfig.isUseJtaTransactionManager()) {
|
||||
externalTransactionManager = new JtaTransactionManager();
|
||||
}
|
||||
if (externalTransactionManager != null) {
|
||||
externalTransactionManager.setTransactionManager(transactionManager);
|
||||
this.transactionScopeManager = new ExternalTransactionScopeManager(transactionManager, externalTransactionManager);
|
||||
logger.info("Using Transaction Manager [" + externalTransactionManager.getClass() + "]");
|
||||
} else {
|
||||
this.transactionScopeManager = new DefaultTransactionScopeManager(transactionManager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public JsonContext createJsonContext(SpiEbeanServer server) {
|
||||
|
||||
String s = serverConfig.getProperty("json.pretty", "false");
|
||||
boolean dfltPretty = "true".equalsIgnoreCase(s);
|
||||
|
||||
s = serverConfig.getProperty("json.jsonValueAdapter", null);
|
||||
|
||||
JsonValueAdapter va = new DefaultJsonValueAdapter();
|
||||
if (s != null) {
|
||||
va = (JsonValueAdapter) ClassUtil.newInstance(s, this.getClass());
|
||||
}
|
||||
return new DJsonContext(server, va, dfltPretty);
|
||||
}
|
||||
|
||||
public XmlConfig getXmlConfig() {
|
||||
return xmlConfig;
|
||||
}
|
||||
|
||||
public AutoFetchManager createAutoFetchManager(SpiEbeanServer server) {
|
||||
return AutoFetchManagerFactory.create(server, serverConfig, resourceManager);
|
||||
}
|
||||
|
||||
public RelationalQueryEngine createRelationalQueryEngine() {
|
||||
return new DefaultRelationalQueryEngine(logControl, binder, serverConfig.getDatabaseBooleanTrue());
|
||||
}
|
||||
|
||||
public OrmQueryEngine createOrmQueryEngine() {
|
||||
return new DefaultOrmQueryEngine(beanDescriptorManager, cQueryEngine);
|
||||
}
|
||||
|
||||
public Persister createPersister(SpiEbeanServer server) {
|
||||
LdapContextFactory ldapCtxFactory = null;
|
||||
LdapConfig ldapConfig = serverConfig.getLdapConfig();
|
||||
if (ldapConfig != null) {
|
||||
ldapCtxFactory = ldapConfig.getContextFactory();
|
||||
}
|
||||
return new DefaultPersister(server, serverConfig.isValidateOnSave(), binder, beanDescriptorManager, pstmtBatch, ldapCtxFactory);
|
||||
}
|
||||
|
||||
public PstmtBatch getPstmtBatch() {
|
||||
return pstmtBatch;
|
||||
}
|
||||
|
||||
public ServerCacheManager getCacheManager() {
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
public BootupClasses getBootupClasses() {
|
||||
return bootupClasses;
|
||||
}
|
||||
|
||||
public DatabasePlatform getDatabasePlatform() {
|
||||
return serverConfig.getDatabasePlatform();
|
||||
}
|
||||
|
||||
public ServerConfig getServerConfig() {
|
||||
return serverConfig;
|
||||
}
|
||||
|
||||
public ExpressionFactory getExpressionFactory() {
|
||||
return expressionFactory;
|
||||
}
|
||||
|
||||
public TypeManager getTypeManager() {
|
||||
return typeManager;
|
||||
}
|
||||
|
||||
public Binder getBinder() {
|
||||
return binder;
|
||||
}
|
||||
|
||||
public BeanDescriptorManager getBeanDescriptorManager() {
|
||||
return beanDescriptorManager;
|
||||
}
|
||||
|
||||
public SubClassManager getSubClassManager() {
|
||||
return subClassManager;
|
||||
}
|
||||
|
||||
public DeployInherit getDeployInherit() {
|
||||
return deployInherit;
|
||||
}
|
||||
|
||||
public ResourceManager getResourceManager() {
|
||||
return resourceManager;
|
||||
}
|
||||
|
||||
public DeployOrmXml getDeployOrmXml() {
|
||||
return deployOrmXml;
|
||||
}
|
||||
|
||||
public DeployCreateProperties getDeployCreateProperties() {
|
||||
return deployCreateProperties;
|
||||
}
|
||||
|
||||
public DeployUtil getDeployUtil() {
|
||||
return deployUtil;
|
||||
}
|
||||
|
||||
public MAdminLogging getLogControl() {
|
||||
return logControl;
|
||||
}
|
||||
|
||||
public TransactionManager getTransactionManager() {
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
public TransactionScopeManager getTransactionScopeManager() {
|
||||
return transactionScopeManager;
|
||||
}
|
||||
|
||||
public CQueryEngine getCQueryEngine() {
|
||||
return cQueryEngine;
|
||||
}
|
||||
|
||||
public ClusterManager getClusterManager() {
|
||||
return clusterManager;
|
||||
}
|
||||
|
||||
public DebugLazyLoad getDebugLazyLoad() {
|
||||
return debugLazyLoad;
|
||||
}
|
||||
|
||||
public SpiBackgroundExecutor getBackgroundExecutor() {
|
||||
return backgroundExecutor;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ExternalTransactionManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.ldap.LdapConfig;
|
||||
import com.avaje.ebean.config.ldap.LdapContextFactory;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import com.avaje.ebean.text.json.JsonValueAdapter;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployOrmXml;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil;
|
||||
import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory;
|
||||
import com.avaje.ebeaninternal.server.jmx.MAdminLogging;
|
||||
import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
import com.avaje.ebeaninternal.server.persist.DefaultPersister;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.DefaultOrmQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.DefaultRelationalQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManager;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.subclass.SubClassManager;
|
||||
import com.avaje.ebeaninternal.server.text.json.DJsonContext;
|
||||
import com.avaje.ebeaninternal.server.text.json.DefaultJsonValueAdapter;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.ExternalTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.JtaTransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.type.DefaultTypeManager;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
|
||||
/**
|
||||
* Used to extend the ServerConfig with additional objects used to configure and
|
||||
* construct an EbeanServer.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class InternalConfiguration {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(InternalConfiguration.class.getName());
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final BootupClasses bootupClasses;
|
||||
|
||||
private final SubClassManager subClassManager;
|
||||
|
||||
private final DeployInherit deployInherit;
|
||||
|
||||
private final ResourceManager resourceManager;
|
||||
|
||||
private final DeployOrmXml deployOrmXml;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
private final Binder binder;
|
||||
|
||||
private final DeployCreateProperties deployCreateProperties;
|
||||
|
||||
private final DeployUtil deployUtil;
|
||||
|
||||
private final BeanDescriptorManager beanDescriptorManager;
|
||||
|
||||
private final MAdminLogging logControl;
|
||||
|
||||
private final DebugLazyLoad debugLazyLoad;
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final TransactionScopeManager transactionScopeManager;
|
||||
|
||||
private final CQueryEngine cQueryEngine;
|
||||
|
||||
private final ClusterManager clusterManager;
|
||||
|
||||
private final ServerCacheManager cacheManager;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
|
||||
private final SpiBackgroundExecutor backgroundExecutor;
|
||||
|
||||
private final PstmtBatch pstmtBatch;
|
||||
|
||||
private final XmlConfig xmlConfig;
|
||||
|
||||
public InternalConfiguration(XmlConfig xmlConfig, ClusterManager clusterManager, ServerCacheManager cacheManager,
|
||||
SpiBackgroundExecutor backgroundExecutor, ServerConfig serverConfig, BootupClasses bootupClasses, PstmtBatch pstmtBatch) {
|
||||
|
||||
this.xmlConfig = xmlConfig;
|
||||
this.pstmtBatch = pstmtBatch;
|
||||
this.clusterManager = clusterManager;
|
||||
this.backgroundExecutor = backgroundExecutor;
|
||||
this.cacheManager = cacheManager;
|
||||
this.serverConfig = serverConfig;
|
||||
this.bootupClasses = bootupClasses;
|
||||
this.expressionFactory = new DefaultExpressionFactory();
|
||||
|
||||
this.subClassManager = new SubClassManager(serverConfig);
|
||||
|
||||
this.typeManager = new DefaultTypeManager(serverConfig, bootupClasses);
|
||||
this.binder = new Binder(typeManager);
|
||||
|
||||
this.resourceManager = ResourceManagerFactory.createResourceManager(serverConfig);
|
||||
this.deployOrmXml = new DeployOrmXml(resourceManager.getResourceSource());
|
||||
this.deployInherit = new DeployInherit(bootupClasses);
|
||||
|
||||
this.deployCreateProperties = new DeployCreateProperties(typeManager);
|
||||
this.deployUtil = new DeployUtil(typeManager, serverConfig);
|
||||
|
||||
this.beanDescriptorManager = new BeanDescriptorManager(this);
|
||||
beanDescriptorManager.deploy();
|
||||
|
||||
this.debugLazyLoad = new DebugLazyLoad(serverConfig.isDebugLazyLoad());
|
||||
|
||||
this.transactionManager = new TransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager,
|
||||
this.getBootupClasses());
|
||||
|
||||
this.logControl = new MAdminLogging(serverConfig, transactionManager);
|
||||
|
||||
this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), logControl, binder, backgroundExecutor);
|
||||
|
||||
ExternalTransactionManager externalTransactionManager = serverConfig.getExternalTransactionManager();
|
||||
if (externalTransactionManager == null && serverConfig.isUseJtaTransactionManager()) {
|
||||
externalTransactionManager = new JtaTransactionManager();
|
||||
}
|
||||
if (externalTransactionManager != null) {
|
||||
externalTransactionManager.setTransactionManager(transactionManager);
|
||||
this.transactionScopeManager = new ExternalTransactionScopeManager(transactionManager, externalTransactionManager);
|
||||
logger.info("Using Transaction Manager [" + externalTransactionManager.getClass() + "]");
|
||||
} else {
|
||||
this.transactionScopeManager = new DefaultTransactionScopeManager(transactionManager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public JsonContext createJsonContext(SpiEbeanServer server) {
|
||||
|
||||
String s = serverConfig.getProperty("json.pretty", "false");
|
||||
boolean dfltPretty = "true".equalsIgnoreCase(s);
|
||||
|
||||
s = serverConfig.getProperty("json.jsonValueAdapter", null);
|
||||
|
||||
JsonValueAdapter va = new DefaultJsonValueAdapter();
|
||||
if (s != null) {
|
||||
va = (JsonValueAdapter) ClassUtil.newInstance(s, this.getClass());
|
||||
}
|
||||
return new DJsonContext(server, va, dfltPretty);
|
||||
}
|
||||
|
||||
public XmlConfig getXmlConfig() {
|
||||
return xmlConfig;
|
||||
}
|
||||
|
||||
public AutoFetchManager createAutoFetchManager(SpiEbeanServer server) {
|
||||
return AutoFetchManagerFactory.create(server, serverConfig, resourceManager);
|
||||
}
|
||||
|
||||
public RelationalQueryEngine createRelationalQueryEngine() {
|
||||
return new DefaultRelationalQueryEngine(logControl, binder, serverConfig.getDatabaseBooleanTrue());
|
||||
}
|
||||
|
||||
public OrmQueryEngine createOrmQueryEngine() {
|
||||
return new DefaultOrmQueryEngine(beanDescriptorManager, cQueryEngine);
|
||||
}
|
||||
|
||||
public Persister createPersister(SpiEbeanServer server) {
|
||||
LdapContextFactory ldapCtxFactory = null;
|
||||
LdapConfig ldapConfig = serverConfig.getLdapConfig();
|
||||
if (ldapConfig != null) {
|
||||
ldapCtxFactory = ldapConfig.getContextFactory();
|
||||
}
|
||||
return new DefaultPersister(server, serverConfig.isValidateOnSave(), binder, beanDescriptorManager, pstmtBatch, ldapCtxFactory);
|
||||
}
|
||||
|
||||
public PstmtBatch getPstmtBatch() {
|
||||
return pstmtBatch;
|
||||
}
|
||||
|
||||
public ServerCacheManager getCacheManager() {
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
public BootupClasses getBootupClasses() {
|
||||
return bootupClasses;
|
||||
}
|
||||
|
||||
public DatabasePlatform getDatabasePlatform() {
|
||||
return serverConfig.getDatabasePlatform();
|
||||
}
|
||||
|
||||
public ServerConfig getServerConfig() {
|
||||
return serverConfig;
|
||||
}
|
||||
|
||||
public ExpressionFactory getExpressionFactory() {
|
||||
return expressionFactory;
|
||||
}
|
||||
|
||||
public TypeManager getTypeManager() {
|
||||
return typeManager;
|
||||
}
|
||||
|
||||
public Binder getBinder() {
|
||||
return binder;
|
||||
}
|
||||
|
||||
public BeanDescriptorManager getBeanDescriptorManager() {
|
||||
return beanDescriptorManager;
|
||||
}
|
||||
|
||||
public SubClassManager getSubClassManager() {
|
||||
return subClassManager;
|
||||
}
|
||||
|
||||
public DeployInherit getDeployInherit() {
|
||||
return deployInherit;
|
||||
}
|
||||
|
||||
public ResourceManager getResourceManager() {
|
||||
return resourceManager;
|
||||
}
|
||||
|
||||
public DeployOrmXml getDeployOrmXml() {
|
||||
return deployOrmXml;
|
||||
}
|
||||
|
||||
public DeployCreateProperties getDeployCreateProperties() {
|
||||
return deployCreateProperties;
|
||||
}
|
||||
|
||||
public DeployUtil getDeployUtil() {
|
||||
return deployUtil;
|
||||
}
|
||||
|
||||
public MAdminLogging getLogControl() {
|
||||
return logControl;
|
||||
}
|
||||
|
||||
public TransactionManager getTransactionManager() {
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
public TransactionScopeManager getTransactionScopeManager() {
|
||||
return transactionScopeManager;
|
||||
}
|
||||
|
||||
public CQueryEngine getCQueryEngine() {
|
||||
return cQueryEngine;
|
||||
}
|
||||
|
||||
public ClusterManager getClusterManager() {
|
||||
return clusterManager;
|
||||
}
|
||||
|
||||
public DebugLazyLoad getDebugLazyLoad() {
|
||||
return debugLazyLoad;
|
||||
}
|
||||
|
||||
public SpiBackgroundExecutor getBackgroundExecutor() {
|
||||
return backgroundExecutor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,68 +1,49 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
|
||||
/**
|
||||
* Helper to lookup a DataSource from JNDI.
|
||||
*/
|
||||
public class JndiDataSourceLookup {
|
||||
|
||||
private static final String DEFAULT_PREFIX = "java:comp/env/jdbc/";
|
||||
|
||||
String jndiPrefix = GlobalProperties.get("ebean.datasource.jndi.prefix", DEFAULT_PREFIX);
|
||||
|
||||
public JndiDataSourceLookup() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataSource by JNDI lookup.
|
||||
* <p>
|
||||
* If name is null the 'default' dataSource is returned.
|
||||
* </p>
|
||||
*/
|
||||
public DataSource lookup(String jndiName) {
|
||||
|
||||
try {
|
||||
|
||||
if (!jndiName.startsWith("java:")){
|
||||
jndiName = jndiPrefix + jndiName;
|
||||
}
|
||||
|
||||
Context ctx = new InitialContext();
|
||||
DataSource ds = (DataSource) ctx.lookup(jndiName);
|
||||
if (ds == null) {
|
||||
throw new PersistenceException("JNDI DataSource [" + jndiName + "] not found?");
|
||||
}
|
||||
return ds;
|
||||
|
||||
} catch (NamingException ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
|
||||
/**
|
||||
* Helper to lookup a DataSource from JNDI.
|
||||
*/
|
||||
public class JndiDataSourceLookup {
|
||||
|
||||
private static final String DEFAULT_PREFIX = "java:comp/env/jdbc/";
|
||||
|
||||
String jndiPrefix = GlobalProperties.get("ebean.datasource.jndi.prefix", DEFAULT_PREFIX);
|
||||
|
||||
public JndiDataSourceLookup() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataSource by JNDI lookup.
|
||||
* <p>
|
||||
* If name is null the 'default' dataSource is returned.
|
||||
* </p>
|
||||
*/
|
||||
public DataSource lookup(String jndiName) {
|
||||
|
||||
try {
|
||||
|
||||
if (!jndiName.startsWith("java:")){
|
||||
jndiName = jndiPrefix + jndiName;
|
||||
}
|
||||
|
||||
Context ctx = new InitialContext();
|
||||
DataSource ds = (DataSource) ctx.lookup(jndiName);
|
||||
if (ds == null) {
|
||||
throw new PersistenceException("JNDI DataSource [" + jndiName + "] not found?");
|
||||
}
|
||||
return ds;
|
||||
|
||||
} catch (NamingException ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,83 +1,64 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Utility object used for internationalising log messages.
|
||||
*/
|
||||
public class Message {
|
||||
|
||||
private static final String bundle = "com.avaje.ebeaninternal.api.message";
|
||||
|
||||
/**
|
||||
* Return a message that has a single argument.
|
||||
*/
|
||||
public static String msg(String key, Object arg) {
|
||||
Object[] args = new Object[1];
|
||||
args[0] = arg;
|
||||
return MessageFormat.format(getPattern(key), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a message that has a two arguments.
|
||||
*/
|
||||
public static String msg(String key, Object arg, Object arg2) {
|
||||
Object[] args = new Object[2];
|
||||
args[0] = arg;
|
||||
args[1] = arg2;
|
||||
return MessageFormat.format(getPattern(key), args);
|
||||
}
|
||||
|
||||
public static String msg(String key, Object arg, Object arg2, Object arg3) {
|
||||
Object[] args = new Object[3];
|
||||
args[0] = arg;
|
||||
args[1] = arg2;
|
||||
args[2] = arg3;
|
||||
return MessageFormat.format(getPattern(key), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a message that has an array of arguments.
|
||||
*/
|
||||
public static String msg(String key, Object[] args) {
|
||||
return MessageFormat.format(getPattern(key), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a message that has a no arguments.
|
||||
*/
|
||||
public static String msg(String key) {
|
||||
return MessageFormat.format(getPattern(key), new Object[0]);
|
||||
}
|
||||
|
||||
private static String getPattern(String key) {
|
||||
try {
|
||||
ResourceBundle myResources = ResourceBundle.getBundle(bundle);
|
||||
return myResources.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
return "MissingResource " + bundle + ":" + key;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Utility object used for internationalising log messages.
|
||||
*/
|
||||
public class Message {
|
||||
|
||||
private static final String bundle = "com.avaje.ebeaninternal.api.message";
|
||||
|
||||
/**
|
||||
* Return a message that has a single argument.
|
||||
*/
|
||||
public static String msg(String key, Object arg) {
|
||||
Object[] args = new Object[1];
|
||||
args[0] = arg;
|
||||
return MessageFormat.format(getPattern(key), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a message that has a two arguments.
|
||||
*/
|
||||
public static String msg(String key, Object arg, Object arg2) {
|
||||
Object[] args = new Object[2];
|
||||
args[0] = arg;
|
||||
args[1] = arg2;
|
||||
return MessageFormat.format(getPattern(key), args);
|
||||
}
|
||||
|
||||
public static String msg(String key, Object arg, Object arg2, Object arg3) {
|
||||
Object[] args = new Object[3];
|
||||
args[0] = arg;
|
||||
args[1] = arg2;
|
||||
args[2] = arg3;
|
||||
return MessageFormat.format(getPattern(key), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a message that has an array of arguments.
|
||||
*/
|
||||
public static String msg(String key, Object[] args) {
|
||||
return MessageFormat.format(getPattern(key), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a message that has a no arguments.
|
||||
*/
|
||||
public static String msg(String key) {
|
||||
return MessageFormat.format(getPattern(key), new Object[0]);
|
||||
}
|
||||
|
||||
private static String getPattern(String key) {
|
||||
try {
|
||||
ResourceBundle myResources = ResourceBundle.getBundle(bundle);
|
||||
return myResources.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
return "MissingResource " + bundle + ":" + key;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,41 +1,22 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
|
||||
|
||||
/**
|
||||
* Matcher used for searching for Embeddable, Entity and ScalarTypes in the
|
||||
* class path.
|
||||
*/
|
||||
public class OnBootupClassSearchMatcher implements ClassPathSearchMatcher {
|
||||
|
||||
BootupClasses classes = new BootupClasses();
|
||||
|
||||
public boolean isMatch(Class<?> cls) {
|
||||
|
||||
return classes.isMatch(cls);
|
||||
}
|
||||
|
||||
public BootupClasses getOnBootupClasses() {
|
||||
return classes;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
|
||||
|
||||
/**
|
||||
* Matcher used for searching for Embeddable, Entity and ScalarTypes in the
|
||||
* class path.
|
||||
*/
|
||||
public class OnBootupClassSearchMatcher implements ClassPathSearchMatcher {
|
||||
|
||||
BootupClasses classes = new BootupClasses();
|
||||
|
||||
public boolean isMatch(Class<?> cls) {
|
||||
|
||||
return classes.isMatch(cls);
|
||||
}
|
||||
|
||||
public BootupClasses getOnBootupClasses() {
|
||||
return classes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,57 +1,38 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
|
||||
/**
|
||||
* The Object Relational query execution API.
|
||||
*/
|
||||
public interface OrmQueryEngine {
|
||||
|
||||
/**
|
||||
* Execute the 'find by id' query returning a single bean.
|
||||
*/
|
||||
public <T> T findId(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the findList, findSet, findMap query returning an appropriate BeanCollection.
|
||||
*/
|
||||
public <T> BeanCollection<T> findMany(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the query using a QueryIterator.
|
||||
*/
|
||||
public <T> QueryIterator<T> findIterate(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the row count query.
|
||||
*/
|
||||
public <T> int findRowCount(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the find id's query.
|
||||
*/
|
||||
public <T> BeanIdList findIds(OrmQueryRequest<T> request);
|
||||
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
|
||||
/**
|
||||
* The Object Relational query execution API.
|
||||
*/
|
||||
public interface OrmQueryEngine {
|
||||
|
||||
/**
|
||||
* Execute the 'find by id' query returning a single bean.
|
||||
*/
|
||||
public <T> T findId(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the findList, findSet, findMap query returning an appropriate BeanCollection.
|
||||
*/
|
||||
public <T> BeanCollection<T> findMany(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the query using a QueryIterator.
|
||||
*/
|
||||
public <T> QueryIterator<T> findIterate(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the row count query.
|
||||
*/
|
||||
public <T> int findRowCount(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the find id's query.
|
||||
*/
|
||||
public <T> BeanIdList findIds(OrmQueryRequest<T> request);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,429 +1,410 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
import com.avaje.ebeaninternal.api.LoadContext;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Type;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployParser;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployPropertyParserMap;
|
||||
import com.avaje.ebeaninternal.server.loadcontext.DLoadContext;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryPlan;
|
||||
import com.avaje.ebeaninternal.server.query.CancelableQuery;
|
||||
|
||||
/**
|
||||
* Wraps the objects involved in executing a Query.
|
||||
*/
|
||||
public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRequest<T>, SpiOrmQueryRequest<T> {
|
||||
|
||||
private final BeanDescriptor<T> beanDescriptor;
|
||||
|
||||
private final OrmQueryEngine queryEngine;
|
||||
|
||||
private final SpiQuery<T> query;
|
||||
|
||||
private final boolean vanillaMode;
|
||||
|
||||
private final BeanFinder<T> finder;
|
||||
|
||||
private final LoadContext graphContext;
|
||||
|
||||
private final Boolean readOnly;
|
||||
|
||||
private final RawSql rawSql;
|
||||
|
||||
private PersistenceContext persistenceContext;
|
||||
|
||||
private Integer cacheKey;
|
||||
|
||||
private int queryPlanHash;
|
||||
|
||||
/**
|
||||
* Flag set if background fetching taking place. In this case the transaction
|
||||
* is rolled back by the background fetching thread. Background fetching
|
||||
* always takes place in its own transaction.
|
||||
*/
|
||||
private boolean backgroundFetching;
|
||||
|
||||
/**
|
||||
* Create the InternalQueryRequest.
|
||||
*/
|
||||
public OrmQueryRequest(SpiEbeanServer server, OrmQueryEngine queryEngine, SpiQuery<T> query, BeanDescriptor<T> desc, SpiTransaction t) {
|
||||
|
||||
super(server, t);
|
||||
|
||||
this.beanDescriptor = desc;
|
||||
this.rawSql = query.getRawSql();
|
||||
this.finder = beanDescriptor.getBeanFinder();
|
||||
this.queryEngine = queryEngine;
|
||||
this.query = query;
|
||||
this.vanillaMode = query.isVanillaMode(server.isVanillaMode());
|
||||
this.readOnly = query.isReadOnly();
|
||||
|
||||
this.graphContext = new DLoadContext(ebeanServer, beanDescriptor, readOnly, query);
|
||||
graphContext.registerSecondaryQueries(query);
|
||||
}
|
||||
|
||||
public void setTotalHits(int totalHits) {
|
||||
query.setTotalHits(totalHits);
|
||||
}
|
||||
|
||||
public void executeSecondaryQueries(int defaultQueryBatch) {
|
||||
graphContext.executeSecondaryQueries(this, defaultQueryBatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* For use with QueryIterator and secondary queries this returns the minimum
|
||||
* batch size that should be loaded before executing the secondary queries.
|
||||
* <p>
|
||||
* If -1 is returned then NO secondary queries are registered and simple
|
||||
* iteration is fine.
|
||||
* </p>
|
||||
*/
|
||||
public int getSecondaryQueriesMinBatchSize(int defaultQueryBatch) {
|
||||
return graphContext.getSecondaryQueriesMinBatchSize(this, defaultQueryBatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Normal, sharedInstance, ReadOnly state of this query.
|
||||
*/
|
||||
public Boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for the associated bean.
|
||||
*/
|
||||
public BeanDescriptor<T> getBeanDescriptor() {
|
||||
return beanDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the graph context for this query.
|
||||
*/
|
||||
public LoadContext getGraphContext() {
|
||||
return graphContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the query plan hash AFTER any potential AutoFetch tuning.
|
||||
*/
|
||||
public void calculateQueryPlanHash() {
|
||||
this.queryPlanHash = query.queryPlanHash(this);
|
||||
}
|
||||
|
||||
public boolean isRawSql() {
|
||||
return rawSql != null;
|
||||
}
|
||||
|
||||
public DeployParser createDeployParser() {
|
||||
if (rawSql != null) {
|
||||
return new DeployPropertyParserMap(rawSql.getColumnMapping().getMapping());
|
||||
} else {
|
||||
return beanDescriptor.createDeployPropertyParser();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a query using generated sql. If false this query
|
||||
* will use raw sql (Entity bean based on raw sql select).
|
||||
*/
|
||||
public boolean isSqlSelect() {
|
||||
return query.isSqlSelect() && query.getRawSql() == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the PersistenceContext used for this request.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return persistenceContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will create a local (readOnly) transaction if no current transaction
|
||||
* exists.
|
||||
* <p>
|
||||
* A transaction may have been passed in explicitly or currently be active in
|
||||
* the thread local. If not, then a readOnly transaction is created to execute
|
||||
* this query.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void initTransIfRequired() {
|
||||
// first check if the query requires its own transaction
|
||||
if (query.createOwnTransaction()) {
|
||||
// using background fetch or query listener etc
|
||||
transaction = ebeanServer.createQueryTransaction();
|
||||
createdTransaction = true;
|
||||
|
||||
} else if (transaction == null) {
|
||||
// maybe a current one
|
||||
transaction = ebeanServer.getCurrentServerTransaction();
|
||||
if (transaction == null) {
|
||||
// create an implicit transaction to execute this query
|
||||
transaction = ebeanServer.createQueryTransaction();
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
this.persistenceContext = getPersistenceContext(query, transaction);
|
||||
this.graphContext.setPersistenceContext(persistenceContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TransactionContext either explicitly set on the query or
|
||||
* transaction scoped.
|
||||
*/
|
||||
private PersistenceContext getPersistenceContext(SpiQuery<?> query, SpiTransaction t) {
|
||||
|
||||
PersistenceContext ctx = query.getPersistenceContext();
|
||||
if (ctx == null) {
|
||||
ctx = t.getPersistenceContext();
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will end a locally created transaction.
|
||||
* <p>
|
||||
* It ends the transaction by using a rollback() as the transaction is known
|
||||
* to be readOnly.
|
||||
* </p>
|
||||
*/
|
||||
public void endTransIfRequired() {
|
||||
if (createdTransaction && !backgroundFetching) {
|
||||
// we can rollback as readOnly transaction
|
||||
transaction.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This query is using background fetching.
|
||||
*/
|
||||
public void setBackgroundFetching() {
|
||||
backgroundFetching = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a find by id (rather than List Set or Map).
|
||||
*/
|
||||
public boolean isFindById() {
|
||||
return query.getType() == Type.BEAN;
|
||||
}
|
||||
|
||||
public boolean isVanillaMode() {
|
||||
return vanillaMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query as findById.
|
||||
*/
|
||||
public Object findId() {
|
||||
return queryEngine.findId(this);
|
||||
}
|
||||
|
||||
public int findRowCount() {
|
||||
return queryEngine.findRowCount(this);
|
||||
}
|
||||
|
||||
public List<Object> findIds() {
|
||||
BeanIdList idList = queryEngine.findIds(this);
|
||||
return idList.getIdList();
|
||||
}
|
||||
|
||||
public void findVisit(QueryResultVisitor<T> visitor) {
|
||||
QueryIterator<T> it = queryEngine.findIterate(this);
|
||||
try {
|
||||
while (it.hasNext()) {
|
||||
if (!visitor.accept(it.next())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
it.close();
|
||||
}
|
||||
}
|
||||
|
||||
public QueryIterator<T> findIterate() {
|
||||
return queryEngine.findIterate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query as findList.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<T> findList() {
|
||||
BeanCollection<T> bc = queryEngine.findMany(this);
|
||||
return (List<T>) (vanillaMode ? bc.getActualCollection() : bc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query as findSet.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<?> findSet() {
|
||||
BeanCollection<T> bc = queryEngine.findMany(this);
|
||||
return (Set<T>) (vanillaMode ? bc.getActualCollection() : bc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query as findMap.
|
||||
*/
|
||||
public Map<?, ?> findMap() {
|
||||
String mapKey = query.getMapKey();
|
||||
if (mapKey == null) {
|
||||
BeanProperty[] ids = beanDescriptor.propertiesId();
|
||||
if (ids.length == 1) {
|
||||
query.setMapKey(ids[0].getName());
|
||||
} else {
|
||||
String msg = "No mapKey specified for query";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
}
|
||||
BeanCollection<T> bc = queryEngine.findMany(this);
|
||||
return (Map<?, ?>) (vanillaMode ? bc.getActualCollection() : bc);
|
||||
}
|
||||
|
||||
public SpiQuery.Type getQueryType() {
|
||||
return query.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a bean specific finder if one has been set.
|
||||
*/
|
||||
public BeanFinder<T> getBeanFinder() {
|
||||
return finder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the find that is to be performed.
|
||||
*/
|
||||
public SpiQuery<T> getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the many property that is fetched in the query or null if there is
|
||||
* not one.
|
||||
*/
|
||||
public BeanPropertyAssocMany<?> getManyProperty() {
|
||||
return beanDescriptor.getManyProperty(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a queryPlan for the current query if one exists. Returns null if no
|
||||
* query plan for this query exists.
|
||||
*/
|
||||
public CQueryPlan getQueryPlan() {
|
||||
return beanDescriptor.getQueryPlan(queryPlanHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the queryPlanHash.
|
||||
* <p>
|
||||
* This identifies the query plan for a given bean type. It effectively
|
||||
* matches a SQL statement with ? bind variables. A query plan can be reused
|
||||
* with just the bind variables changing.
|
||||
* </p>
|
||||
*/
|
||||
public int getQueryPlanHash() {
|
||||
return queryPlanHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the QueryPlan into the cache.
|
||||
*/
|
||||
public void putQueryPlan(CQueryPlan queryPlan) {
|
||||
beanDescriptor.putQueryPlan(queryPlanHash, queryPlan);
|
||||
}
|
||||
|
||||
public boolean isUseBeanCache() {
|
||||
return beanDescriptor.calculateUseCache(query.isUseBeanCache());
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get the query result from the query cache.
|
||||
*/
|
||||
public BeanCollection<T> getFromQueryCache() {
|
||||
|
||||
if (!query.isUseQueryCache()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (query.getType() == null) {
|
||||
// the query plan and bind values must be the same
|
||||
cacheKey = Integer.valueOf(query.queryHash());
|
||||
|
||||
} else {
|
||||
// additionally the return type (List/Set/Map) must be the same
|
||||
cacheKey = Integer.valueOf(31 * query.queryHash() + query.getType().hashCode());
|
||||
}
|
||||
|
||||
// TODO: Sort out returning BeanCollection from L2 cache
|
||||
return null;
|
||||
|
||||
// BeanCollection<T> bc = beanDescriptor.queryCacheGet(cacheKey);
|
||||
// if (bc != null && Boolean.FALSE.equals(query.isReadOnly())) {
|
||||
// // Explicit readOnly=false for query cache
|
||||
// CopyContext ctx = new CopyContext(vanillaMode, false);
|
||||
// return new CopyBeanCollection<T>(bc, beanDescriptor, ctx, 5).copy();
|
||||
// }
|
||||
// return bc;
|
||||
}
|
||||
|
||||
public void putToQueryCache(BeanCollection<T> queryResult) {
|
||||
beanDescriptor.queryCachePut(cacheKey, queryResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an Query object that owns the PreparedStatement that can be cancelled.
|
||||
*/
|
||||
public void setCancelableQuery(CancelableQuery cancelableQuery) {
|
||||
query.setCancelableQuery(cancelableQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the SQL if the logLevel is appropriate.
|
||||
*/
|
||||
public void logSql(String sql) {
|
||||
if (transaction.isLogSql()) {
|
||||
transaction.logInternal(sql);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
import com.avaje.ebeaninternal.api.LoadContext;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Type;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployParser;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployPropertyParserMap;
|
||||
import com.avaje.ebeaninternal.server.loadcontext.DLoadContext;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryPlan;
|
||||
import com.avaje.ebeaninternal.server.query.CancelableQuery;
|
||||
|
||||
/**
|
||||
* Wraps the objects involved in executing a Query.
|
||||
*/
|
||||
public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRequest<T>, SpiOrmQueryRequest<T> {
|
||||
|
||||
private final BeanDescriptor<T> beanDescriptor;
|
||||
|
||||
private final OrmQueryEngine queryEngine;
|
||||
|
||||
private final SpiQuery<T> query;
|
||||
|
||||
private final boolean vanillaMode;
|
||||
|
||||
private final BeanFinder<T> finder;
|
||||
|
||||
private final LoadContext graphContext;
|
||||
|
||||
private final Boolean readOnly;
|
||||
|
||||
private final RawSql rawSql;
|
||||
|
||||
private PersistenceContext persistenceContext;
|
||||
|
||||
private Integer cacheKey;
|
||||
|
||||
private int queryPlanHash;
|
||||
|
||||
/**
|
||||
* Flag set if background fetching taking place. In this case the transaction
|
||||
* is rolled back by the background fetching thread. Background fetching
|
||||
* always takes place in its own transaction.
|
||||
*/
|
||||
private boolean backgroundFetching;
|
||||
|
||||
/**
|
||||
* Create the InternalQueryRequest.
|
||||
*/
|
||||
public OrmQueryRequest(SpiEbeanServer server, OrmQueryEngine queryEngine, SpiQuery<T> query, BeanDescriptor<T> desc, SpiTransaction t) {
|
||||
|
||||
super(server, t);
|
||||
|
||||
this.beanDescriptor = desc;
|
||||
this.rawSql = query.getRawSql();
|
||||
this.finder = beanDescriptor.getBeanFinder();
|
||||
this.queryEngine = queryEngine;
|
||||
this.query = query;
|
||||
this.vanillaMode = query.isVanillaMode(server.isVanillaMode());
|
||||
this.readOnly = query.isReadOnly();
|
||||
|
||||
this.graphContext = new DLoadContext(ebeanServer, beanDescriptor, readOnly, query);
|
||||
graphContext.registerSecondaryQueries(query);
|
||||
}
|
||||
|
||||
public void setTotalHits(int totalHits) {
|
||||
query.setTotalHits(totalHits);
|
||||
}
|
||||
|
||||
public void executeSecondaryQueries(int defaultQueryBatch) {
|
||||
graphContext.executeSecondaryQueries(this, defaultQueryBatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* For use with QueryIterator and secondary queries this returns the minimum
|
||||
* batch size that should be loaded before executing the secondary queries.
|
||||
* <p>
|
||||
* If -1 is returned then NO secondary queries are registered and simple
|
||||
* iteration is fine.
|
||||
* </p>
|
||||
*/
|
||||
public int getSecondaryQueriesMinBatchSize(int defaultQueryBatch) {
|
||||
return graphContext.getSecondaryQueriesMinBatchSize(this, defaultQueryBatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Normal, sharedInstance, ReadOnly state of this query.
|
||||
*/
|
||||
public Boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for the associated bean.
|
||||
*/
|
||||
public BeanDescriptor<T> getBeanDescriptor() {
|
||||
return beanDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the graph context for this query.
|
||||
*/
|
||||
public LoadContext getGraphContext() {
|
||||
return graphContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the query plan hash AFTER any potential AutoFetch tuning.
|
||||
*/
|
||||
public void calculateQueryPlanHash() {
|
||||
this.queryPlanHash = query.queryPlanHash(this);
|
||||
}
|
||||
|
||||
public boolean isRawSql() {
|
||||
return rawSql != null;
|
||||
}
|
||||
|
||||
public DeployParser createDeployParser() {
|
||||
if (rawSql != null) {
|
||||
return new DeployPropertyParserMap(rawSql.getColumnMapping().getMapping());
|
||||
} else {
|
||||
return beanDescriptor.createDeployPropertyParser();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a query using generated sql. If false this query
|
||||
* will use raw sql (Entity bean based on raw sql select).
|
||||
*/
|
||||
public boolean isSqlSelect() {
|
||||
return query.isSqlSelect() && query.getRawSql() == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the PersistenceContext used for this request.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return persistenceContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will create a local (readOnly) transaction if no current transaction
|
||||
* exists.
|
||||
* <p>
|
||||
* A transaction may have been passed in explicitly or currently be active in
|
||||
* the thread local. If not, then a readOnly transaction is created to execute
|
||||
* this query.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void initTransIfRequired() {
|
||||
// first check if the query requires its own transaction
|
||||
if (query.createOwnTransaction()) {
|
||||
// using background fetch or query listener etc
|
||||
transaction = ebeanServer.createQueryTransaction();
|
||||
createdTransaction = true;
|
||||
|
||||
} else if (transaction == null) {
|
||||
// maybe a current one
|
||||
transaction = ebeanServer.getCurrentServerTransaction();
|
||||
if (transaction == null) {
|
||||
// create an implicit transaction to execute this query
|
||||
transaction = ebeanServer.createQueryTransaction();
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
this.persistenceContext = getPersistenceContext(query, transaction);
|
||||
this.graphContext.setPersistenceContext(persistenceContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TransactionContext either explicitly set on the query or
|
||||
* transaction scoped.
|
||||
*/
|
||||
private PersistenceContext getPersistenceContext(SpiQuery<?> query, SpiTransaction t) {
|
||||
|
||||
PersistenceContext ctx = query.getPersistenceContext();
|
||||
if (ctx == null) {
|
||||
ctx = t.getPersistenceContext();
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will end a locally created transaction.
|
||||
* <p>
|
||||
* It ends the transaction by using a rollback() as the transaction is known
|
||||
* to be readOnly.
|
||||
* </p>
|
||||
*/
|
||||
public void endTransIfRequired() {
|
||||
if (createdTransaction && !backgroundFetching) {
|
||||
// we can rollback as readOnly transaction
|
||||
transaction.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This query is using background fetching.
|
||||
*/
|
||||
public void setBackgroundFetching() {
|
||||
backgroundFetching = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a find by id (rather than List Set or Map).
|
||||
*/
|
||||
public boolean isFindById() {
|
||||
return query.getType() == Type.BEAN;
|
||||
}
|
||||
|
||||
public boolean isVanillaMode() {
|
||||
return vanillaMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query as findById.
|
||||
*/
|
||||
public Object findId() {
|
||||
return queryEngine.findId(this);
|
||||
}
|
||||
|
||||
public int findRowCount() {
|
||||
return queryEngine.findRowCount(this);
|
||||
}
|
||||
|
||||
public List<Object> findIds() {
|
||||
BeanIdList idList = queryEngine.findIds(this);
|
||||
return idList.getIdList();
|
||||
}
|
||||
|
||||
public void findVisit(QueryResultVisitor<T> visitor) {
|
||||
QueryIterator<T> it = queryEngine.findIterate(this);
|
||||
try {
|
||||
while (it.hasNext()) {
|
||||
if (!visitor.accept(it.next())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
it.close();
|
||||
}
|
||||
}
|
||||
|
||||
public QueryIterator<T> findIterate() {
|
||||
return queryEngine.findIterate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query as findList.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<T> findList() {
|
||||
BeanCollection<T> bc = queryEngine.findMany(this);
|
||||
return (List<T>) (vanillaMode ? bc.getActualCollection() : bc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query as findSet.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<?> findSet() {
|
||||
BeanCollection<T> bc = queryEngine.findMany(this);
|
||||
return (Set<T>) (vanillaMode ? bc.getActualCollection() : bc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query as findMap.
|
||||
*/
|
||||
public Map<?, ?> findMap() {
|
||||
String mapKey = query.getMapKey();
|
||||
if (mapKey == null) {
|
||||
BeanProperty[] ids = beanDescriptor.propertiesId();
|
||||
if (ids.length == 1) {
|
||||
query.setMapKey(ids[0].getName());
|
||||
} else {
|
||||
String msg = "No mapKey specified for query";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
}
|
||||
BeanCollection<T> bc = queryEngine.findMany(this);
|
||||
return (Map<?, ?>) (vanillaMode ? bc.getActualCollection() : bc);
|
||||
}
|
||||
|
||||
public SpiQuery.Type getQueryType() {
|
||||
return query.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a bean specific finder if one has been set.
|
||||
*/
|
||||
public BeanFinder<T> getBeanFinder() {
|
||||
return finder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the find that is to be performed.
|
||||
*/
|
||||
public SpiQuery<T> getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the many property that is fetched in the query or null if there is
|
||||
* not one.
|
||||
*/
|
||||
public BeanPropertyAssocMany<?> getManyProperty() {
|
||||
return beanDescriptor.getManyProperty(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a queryPlan for the current query if one exists. Returns null if no
|
||||
* query plan for this query exists.
|
||||
*/
|
||||
public CQueryPlan getQueryPlan() {
|
||||
return beanDescriptor.getQueryPlan(queryPlanHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the queryPlanHash.
|
||||
* <p>
|
||||
* This identifies the query plan for a given bean type. It effectively
|
||||
* matches a SQL statement with ? bind variables. A query plan can be reused
|
||||
* with just the bind variables changing.
|
||||
* </p>
|
||||
*/
|
||||
public int getQueryPlanHash() {
|
||||
return queryPlanHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the QueryPlan into the cache.
|
||||
*/
|
||||
public void putQueryPlan(CQueryPlan queryPlan) {
|
||||
beanDescriptor.putQueryPlan(queryPlanHash, queryPlan);
|
||||
}
|
||||
|
||||
public boolean isUseBeanCache() {
|
||||
return beanDescriptor.calculateUseCache(query.isUseBeanCache());
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get the query result from the query cache.
|
||||
*/
|
||||
public BeanCollection<T> getFromQueryCache() {
|
||||
|
||||
if (!query.isUseQueryCache()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (query.getType() == null) {
|
||||
// the query plan and bind values must be the same
|
||||
cacheKey = Integer.valueOf(query.queryHash());
|
||||
|
||||
} else {
|
||||
// additionally the return type (List/Set/Map) must be the same
|
||||
cacheKey = Integer.valueOf(31 * query.queryHash() + query.getType().hashCode());
|
||||
}
|
||||
|
||||
// TODO: Sort out returning BeanCollection from L2 cache
|
||||
return null;
|
||||
|
||||
// BeanCollection<T> bc = beanDescriptor.queryCacheGet(cacheKey);
|
||||
// if (bc != null && Boolean.FALSE.equals(query.isReadOnly())) {
|
||||
// // Explicit readOnly=false for query cache
|
||||
// CopyContext ctx = new CopyContext(vanillaMode, false);
|
||||
// return new CopyBeanCollection<T>(bc, beanDescriptor, ctx, 5).copy();
|
||||
// }
|
||||
// return bc;
|
||||
}
|
||||
|
||||
public void putToQueryCache(BeanCollection<T> queryResult) {
|
||||
beanDescriptor.queryCachePut(cacheKey, queryResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an Query object that owns the PreparedStatement that can be cancelled.
|
||||
*/
|
||||
public void setCancelableQuery(CancelableQuery cancelableQuery) {
|
||||
query.setCancelableQuery(cancelableQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the SQL if the logLevel is appropriate.
|
||||
*/
|
||||
public void logSql(String sql) {
|
||||
if (transaction.isLogSql()) {
|
||||
transaction.logInternal(sql);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,127 +1,108 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchPostExecute;
|
||||
import com.avaje.ebeaninternal.server.persist.PersistExecute;
|
||||
|
||||
/**
|
||||
* Wraps all the objects used to persist a bean.
|
||||
*/
|
||||
public abstract class PersistRequest extends BeanRequest implements BatchPostExecute {
|
||||
|
||||
public enum Type {
|
||||
INSERT, UPDATE, DELETE, ORMUPDATE, UPDATESQL, CALLABLESQL
|
||||
};
|
||||
|
||||
boolean persistCascade;
|
||||
|
||||
/**
|
||||
* One of INSERT, UPDATE, DELETE, UPDATESQL or CALLABLESQL.
|
||||
*/
|
||||
Type type;
|
||||
|
||||
final PersistExecute persistExecute;
|
||||
|
||||
/**
|
||||
* Used by CallableSqlRequest and UpdateSqlRequest.
|
||||
*/
|
||||
public PersistRequest(SpiEbeanServer server, SpiTransaction t, PersistExecute persistExecute) {
|
||||
super(server, t);
|
||||
this.persistExecute = persistExecute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a the request or queue/batch it for later execution.
|
||||
*/
|
||||
public abstract int executeOrQueue();
|
||||
|
||||
/**
|
||||
* Execute the request right now.
|
||||
*/
|
||||
public abstract int executeNow();
|
||||
|
||||
public PstmtBatch getPstmtBatch() {
|
||||
return ebeanServer.getPstmtBatch();
|
||||
}
|
||||
|
||||
public boolean isLogSql() {
|
||||
return transaction.isLogSql();
|
||||
}
|
||||
|
||||
public boolean isLogSummary() {
|
||||
return transaction.isLogSummary();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the Callable statement.
|
||||
*/
|
||||
public int executeStatement() {
|
||||
|
||||
boolean batch = transaction.isBatchThisRequest();
|
||||
|
||||
int rows;
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control != null) {
|
||||
rows = control.executeStatementOrBatch(this, batch);
|
||||
|
||||
} else if (batch) {
|
||||
// need to create the BatchControl
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
rows = control.executeStatementOrBatch(this, batch);
|
||||
} else {
|
||||
rows = executeNow();
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
public void initTransIfRequired() {
|
||||
createImplicitTransIfRequired(false);
|
||||
persistCascade = transaction.isPersistCascade();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of this request. One of INSERT, UPDATE, DELETE, UPDATESQL
|
||||
* or CALLABLESQL.
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of this request. One of INSERT, UPDATE, DELETE, UPDATESQL or
|
||||
* CALLABLESQL.
|
||||
*/
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if save and delete should cascade.
|
||||
*/
|
||||
public boolean isPersistCascade() {
|
||||
return persistCascade;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchPostExecute;
|
||||
import com.avaje.ebeaninternal.server.persist.PersistExecute;
|
||||
|
||||
/**
|
||||
* Wraps all the objects used to persist a bean.
|
||||
*/
|
||||
public abstract class PersistRequest extends BeanRequest implements BatchPostExecute {
|
||||
|
||||
public enum Type {
|
||||
INSERT, UPDATE, DELETE, ORMUPDATE, UPDATESQL, CALLABLESQL
|
||||
};
|
||||
|
||||
boolean persistCascade;
|
||||
|
||||
/**
|
||||
* One of INSERT, UPDATE, DELETE, UPDATESQL or CALLABLESQL.
|
||||
*/
|
||||
Type type;
|
||||
|
||||
final PersistExecute persistExecute;
|
||||
|
||||
/**
|
||||
* Used by CallableSqlRequest and UpdateSqlRequest.
|
||||
*/
|
||||
public PersistRequest(SpiEbeanServer server, SpiTransaction t, PersistExecute persistExecute) {
|
||||
super(server, t);
|
||||
this.persistExecute = persistExecute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a the request or queue/batch it for later execution.
|
||||
*/
|
||||
public abstract int executeOrQueue();
|
||||
|
||||
/**
|
||||
* Execute the request right now.
|
||||
*/
|
||||
public abstract int executeNow();
|
||||
|
||||
public PstmtBatch getPstmtBatch() {
|
||||
return ebeanServer.getPstmtBatch();
|
||||
}
|
||||
|
||||
public boolean isLogSql() {
|
||||
return transaction.isLogSql();
|
||||
}
|
||||
|
||||
public boolean isLogSummary() {
|
||||
return transaction.isLogSummary();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the Callable statement.
|
||||
*/
|
||||
public int executeStatement() {
|
||||
|
||||
boolean batch = transaction.isBatchThisRequest();
|
||||
|
||||
int rows;
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control != null) {
|
||||
rows = control.executeStatementOrBatch(this, batch);
|
||||
|
||||
} else if (batch) {
|
||||
// need to create the BatchControl
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
rows = control.executeStatementOrBatch(this, batch);
|
||||
} else {
|
||||
rows = executeNow();
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
public void initTransIfRequired() {
|
||||
createImplicitTransIfRequired(false);
|
||||
persistCascade = transaction.isPersistCascade();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of this request. One of INSERT, UPDATE, DELETE, UPDATESQL
|
||||
* or CALLABLESQL.
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of this request. One of INSERT, UPDATE, DELETE, UPDATESQL or
|
||||
* CALLABLESQL.
|
||||
*/
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if save and delete should cascade.
|
||||
*/
|
||||
public boolean isPersistCascade() {
|
||||
return persistCascade;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+152
-171
@@ -1,171 +1,152 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.CallableSql;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.api.SpiCallableSql;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable;
|
||||
import com.avaje.ebeaninternal.api.BindParams.Param;
|
||||
import com.avaje.ebeaninternal.server.persist.PersistExecute;
|
||||
|
||||
/**
|
||||
* Persist request specifically for CallableSql.
|
||||
*/
|
||||
public final class PersistRequestCallableSql extends PersistRequest {
|
||||
|
||||
private final SpiCallableSql callableSql;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private String bindLog;
|
||||
|
||||
private CallableStatement cstmt;
|
||||
|
||||
private BindParams bindParam;
|
||||
|
||||
/**
|
||||
* Create.
|
||||
*/
|
||||
public PersistRequestCallableSql(SpiEbeanServer server,
|
||||
CallableSql cs, SpiTransaction t, PersistExecute persistExecute) {
|
||||
|
||||
super(server, t, persistExecute);
|
||||
this.type = PersistRequest.Type.CALLABLESQL;
|
||||
this.callableSql = (SpiCallableSql)cs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeOrQueue() {
|
||||
return executeStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeNow() {
|
||||
return persistExecute.executeSqlCallable(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CallableSql.
|
||||
*/
|
||||
public SpiCallableSql getCallableSql() {
|
||||
return callableSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* The the log of bind values.
|
||||
*/
|
||||
public void setBindLog(String bindLog) {
|
||||
this.bindLog = bindLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note the rowCount of the execution.
|
||||
*/
|
||||
public void checkRowCount(int count) throws SQLException {
|
||||
this.rowCount = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only called for insert with generated keys.
|
||||
*/
|
||||
public void setGeneratedKey(Object idValue) {
|
||||
}
|
||||
|
||||
/**
|
||||
* False for CallableSql.
|
||||
*/
|
||||
public boolean useGeneratedKeys() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform post execute processing for the CallableSql.
|
||||
*/
|
||||
public void postExecute() throws SQLException {
|
||||
|
||||
if (transaction.isLogSummary()) {
|
||||
String m = "CallableSql label[" + callableSql.getLabel() + "]" + " rows[" + rowCount+ "]" + " bind[" + bindLog + "]";
|
||||
transaction.logInternal(m);
|
||||
}
|
||||
|
||||
// register table modifications with the transaction event
|
||||
TransactionEventTable tableEvents = callableSql.getTransactionEventTable();
|
||||
|
||||
if (tableEvents != null && !tableEvents.isEmpty()) {
|
||||
transaction.getEvent().add(tableEvents);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* These need to be set for use with Non-batch execution. Specifically to
|
||||
* read registered out parameters and potentially handle the
|
||||
* executeOverride() method.
|
||||
*/
|
||||
public void setBound(BindParams bindParam, CallableStatement cstmt) {
|
||||
this.bindParam = bindParam;
|
||||
this.cstmt = cstmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the statement in normal non batch mode.
|
||||
*/
|
||||
public int executeUpdate() throws SQLException {
|
||||
|
||||
// check to see if the execution has been overridden
|
||||
// only works in non-batch mode
|
||||
if (callableSql.executeOverride(cstmt)) {
|
||||
return -1;
|
||||
// // been overridden so just return the rowCount
|
||||
// rowCount = callableSql.getRowCount();
|
||||
// return rowCount;
|
||||
}
|
||||
|
||||
rowCount = cstmt.executeUpdate();
|
||||
|
||||
// only read in non-batch mode
|
||||
readOutParams();
|
||||
|
||||
return rowCount;
|
||||
}
|
||||
|
||||
private void readOutParams() throws SQLException {
|
||||
|
||||
List<Param> list = bindParam.positionedParameters();
|
||||
int pos = 0;
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
pos++;
|
||||
BindParams.Param param = (BindParams.Param) list.get(i);
|
||||
if (param.isOutParam()) {
|
||||
Object outValue = cstmt.getObject(pos);
|
||||
param.setOutValue(outValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.CallableSql;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.api.SpiCallableSql;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable;
|
||||
import com.avaje.ebeaninternal.api.BindParams.Param;
|
||||
import com.avaje.ebeaninternal.server.persist.PersistExecute;
|
||||
|
||||
/**
|
||||
* Persist request specifically for CallableSql.
|
||||
*/
|
||||
public final class PersistRequestCallableSql extends PersistRequest {
|
||||
|
||||
private final SpiCallableSql callableSql;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private String bindLog;
|
||||
|
||||
private CallableStatement cstmt;
|
||||
|
||||
private BindParams bindParam;
|
||||
|
||||
/**
|
||||
* Create.
|
||||
*/
|
||||
public PersistRequestCallableSql(SpiEbeanServer server,
|
||||
CallableSql cs, SpiTransaction t, PersistExecute persistExecute) {
|
||||
|
||||
super(server, t, persistExecute);
|
||||
this.type = PersistRequest.Type.CALLABLESQL;
|
||||
this.callableSql = (SpiCallableSql)cs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeOrQueue() {
|
||||
return executeStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeNow() {
|
||||
return persistExecute.executeSqlCallable(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CallableSql.
|
||||
*/
|
||||
public SpiCallableSql getCallableSql() {
|
||||
return callableSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* The the log of bind values.
|
||||
*/
|
||||
public void setBindLog(String bindLog) {
|
||||
this.bindLog = bindLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note the rowCount of the execution.
|
||||
*/
|
||||
public void checkRowCount(int count) throws SQLException {
|
||||
this.rowCount = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only called for insert with generated keys.
|
||||
*/
|
||||
public void setGeneratedKey(Object idValue) {
|
||||
}
|
||||
|
||||
/**
|
||||
* False for CallableSql.
|
||||
*/
|
||||
public boolean useGeneratedKeys() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform post execute processing for the CallableSql.
|
||||
*/
|
||||
public void postExecute() throws SQLException {
|
||||
|
||||
if (transaction.isLogSummary()) {
|
||||
String m = "CallableSql label[" + callableSql.getLabel() + "]" + " rows[" + rowCount+ "]" + " bind[" + bindLog + "]";
|
||||
transaction.logInternal(m);
|
||||
}
|
||||
|
||||
// register table modifications with the transaction event
|
||||
TransactionEventTable tableEvents = callableSql.getTransactionEventTable();
|
||||
|
||||
if (tableEvents != null && !tableEvents.isEmpty()) {
|
||||
transaction.getEvent().add(tableEvents);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* These need to be set for use with Non-batch execution. Specifically to
|
||||
* read registered out parameters and potentially handle the
|
||||
* executeOverride() method.
|
||||
*/
|
||||
public void setBound(BindParams bindParam, CallableStatement cstmt) {
|
||||
this.bindParam = bindParam;
|
||||
this.cstmt = cstmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the statement in normal non batch mode.
|
||||
*/
|
||||
public int executeUpdate() throws SQLException {
|
||||
|
||||
// check to see if the execution has been overridden
|
||||
// only works in non-batch mode
|
||||
if (callableSql.executeOverride(cstmt)) {
|
||||
return -1;
|
||||
// // been overridden so just return the rowCount
|
||||
// rowCount = callableSql.getRowCount();
|
||||
// return rowCount;
|
||||
}
|
||||
|
||||
rowCount = cstmt.executeUpdate();
|
||||
|
||||
// only read in non-batch mode
|
||||
readOutParams();
|
||||
|
||||
return rowCount;
|
||||
}
|
||||
|
||||
private void readOutParams() throws SQLException {
|
||||
|
||||
List<Param> list = bindParam.positionedParameters();
|
||||
int pos = 0;
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
pos++;
|
||||
BindParams.Param param = (BindParams.Param) list.get(i);
|
||||
if (param.isOutParam()) {
|
||||
Object outValue = cstmt.getObject(pos);
|
||||
param.setOutValue(outValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,138 +1,119 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.api.SpiUpdate;
|
||||
import com.avaje.ebeaninternal.api.SpiUpdate.OrmUpdateType;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanManager;
|
||||
import com.avaje.ebeaninternal.server.persist.PersistExecute;
|
||||
|
||||
/**
|
||||
* Persist request specifically for CallableSql.
|
||||
*/
|
||||
public final class PersistRequestOrmUpdate extends PersistRequest {
|
||||
|
||||
private final BeanDescriptor<?> beanDescriptor;
|
||||
|
||||
private SpiUpdate<?> ormUpdate;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private String bindLog;
|
||||
|
||||
/**
|
||||
* Create.
|
||||
*/
|
||||
public PersistRequestOrmUpdate(SpiEbeanServer server, BeanManager<?> mgr, SpiUpdate<?> ormUpdate,
|
||||
SpiTransaction t, PersistExecute persistExecute) {
|
||||
|
||||
super(server, t, persistExecute);
|
||||
this.beanDescriptor = mgr.getBeanDescriptor();
|
||||
this.ormUpdate = ormUpdate;
|
||||
}
|
||||
|
||||
public BeanDescriptor<?> getBeanDescriptor() {
|
||||
return beanDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeNow() {
|
||||
return persistExecute.executeOrmUpdate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeOrQueue() {
|
||||
return executeStatement();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the UpdateSql.
|
||||
*/
|
||||
public SpiUpdate<?> getOrmUpdate() {
|
||||
return ormUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* No concurrency checking so just note the rowCount.
|
||||
*/
|
||||
public void checkRowCount(int count) throws SQLException {
|
||||
this.rowCount = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always false.
|
||||
*/
|
||||
public boolean useGeneratedKeys() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not called for this type of request.
|
||||
*/
|
||||
public void setGeneratedKey(Object idValue) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bound values.
|
||||
*/
|
||||
public void setBindLog(String bindLog) {
|
||||
this.bindLog = bindLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform post execute processing.
|
||||
*/
|
||||
public void postExecute() throws SQLException {
|
||||
|
||||
OrmUpdateType ormUpdateType = ormUpdate.getOrmUpdateType();
|
||||
String tableName = ormUpdate.getBaseTable();
|
||||
|
||||
if (transaction.isLogSummary()) {
|
||||
String m = ormUpdateType + " table[" + tableName + "] rows["+ rowCount + "] bind[" + bindLog + "]";
|
||||
transaction.logInternal(m);
|
||||
}
|
||||
|
||||
if (ormUpdate.isNotifyCache()) {
|
||||
|
||||
// add the modification info to the TransactionEvent
|
||||
// this is used to invalidate cached objects etc
|
||||
switch (ormUpdateType) {
|
||||
case INSERT:
|
||||
transaction.getEvent().add(tableName, true, false, false);
|
||||
break;
|
||||
case UPDATE:
|
||||
transaction.getEvent().add(tableName, false, true, false);
|
||||
break;
|
||||
case DELETE:
|
||||
transaction.getEvent().add(tableName, false, false, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.api.SpiUpdate;
|
||||
import com.avaje.ebeaninternal.api.SpiUpdate.OrmUpdateType;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanManager;
|
||||
import com.avaje.ebeaninternal.server.persist.PersistExecute;
|
||||
|
||||
/**
|
||||
* Persist request specifically for CallableSql.
|
||||
*/
|
||||
public final class PersistRequestOrmUpdate extends PersistRequest {
|
||||
|
||||
private final BeanDescriptor<?> beanDescriptor;
|
||||
|
||||
private SpiUpdate<?> ormUpdate;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private String bindLog;
|
||||
|
||||
/**
|
||||
* Create.
|
||||
*/
|
||||
public PersistRequestOrmUpdate(SpiEbeanServer server, BeanManager<?> mgr, SpiUpdate<?> ormUpdate,
|
||||
SpiTransaction t, PersistExecute persistExecute) {
|
||||
|
||||
super(server, t, persistExecute);
|
||||
this.beanDescriptor = mgr.getBeanDescriptor();
|
||||
this.ormUpdate = ormUpdate;
|
||||
}
|
||||
|
||||
public BeanDescriptor<?> getBeanDescriptor() {
|
||||
return beanDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeNow() {
|
||||
return persistExecute.executeOrmUpdate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeOrQueue() {
|
||||
return executeStatement();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the UpdateSql.
|
||||
*/
|
||||
public SpiUpdate<?> getOrmUpdate() {
|
||||
return ormUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* No concurrency checking so just note the rowCount.
|
||||
*/
|
||||
public void checkRowCount(int count) throws SQLException {
|
||||
this.rowCount = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always false.
|
||||
*/
|
||||
public boolean useGeneratedKeys() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not called for this type of request.
|
||||
*/
|
||||
public void setGeneratedKey(Object idValue) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bound values.
|
||||
*/
|
||||
public void setBindLog(String bindLog) {
|
||||
this.bindLog = bindLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform post execute processing.
|
||||
*/
|
||||
public void postExecute() throws SQLException {
|
||||
|
||||
OrmUpdateType ormUpdateType = ormUpdate.getOrmUpdateType();
|
||||
String tableName = ormUpdate.getBaseTable();
|
||||
|
||||
if (transaction.isLogSummary()) {
|
||||
String m = ormUpdateType + " table[" + tableName + "] rows["+ rowCount + "] bind[" + bindLog + "]";
|
||||
transaction.logInternal(m);
|
||||
}
|
||||
|
||||
if (ormUpdate.isNotifyCache()) {
|
||||
|
||||
// add the modification info to the TransactionEvent
|
||||
// this is used to invalidate cached objects etc
|
||||
switch (ormUpdateType) {
|
||||
case INSERT:
|
||||
transaction.getEvent().add(tableName, true, false, false);
|
||||
break;
|
||||
case UPDATE:
|
||||
transaction.getEvent().add(tableName, false, true, false);
|
||||
break;
|
||||
case DELETE:
|
||||
transaction.getEvent().add(tableName, false, false, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,145 +1,126 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiSqlUpdate;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.persist.PersistExecute;
|
||||
|
||||
/**
|
||||
* Persist request specifically for CallableSql.
|
||||
*/
|
||||
public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
|
||||
public enum SqlType {
|
||||
SQL_UPDATE, SQL_DELETE, SQL_INSERT, SQL_UNKNOWN
|
||||
};
|
||||
|
||||
private final SpiSqlUpdate updateSql;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private String bindLog;
|
||||
|
||||
private SqlType sqlType;
|
||||
|
||||
private String tableName;
|
||||
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Create.
|
||||
*/
|
||||
public PersistRequestUpdateSql(SpiEbeanServer server, SqlUpdate updateSql,
|
||||
SpiTransaction t, PersistExecute persistExecute) {
|
||||
super(server, t, persistExecute);
|
||||
this.type = Type.UPDATESQL;
|
||||
this.updateSql = (SpiSqlUpdate)updateSql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeNow() {
|
||||
return persistExecute.executeSqlUpdate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeOrQueue() {
|
||||
return executeStatement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the UpdateSql.
|
||||
*/
|
||||
public SpiSqlUpdate getUpdateSql() {
|
||||
return updateSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* No concurrency checking so just note the rowCount.
|
||||
*/
|
||||
public void checkRowCount(int count) throws SQLException {
|
||||
this.rowCount = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always false.
|
||||
*/
|
||||
public boolean useGeneratedKeys() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not called for this type of request.
|
||||
*/
|
||||
public void setGeneratedKey(Object idValue) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the type of statement executed. Used to automatically register
|
||||
* with the transaction event.
|
||||
*/
|
||||
public void setType(SqlType sqlType, String tableName, String description) {
|
||||
this.sqlType = sqlType;
|
||||
this.tableName = tableName;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bound values.
|
||||
*/
|
||||
public void setBindLog(String bindLog) {
|
||||
this.bindLog = bindLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform post execute processing.
|
||||
*/
|
||||
public void postExecute() throws SQLException {
|
||||
|
||||
if (transaction.isLogSummary()) {
|
||||
String m = description + " table[" + tableName + "] rows["+ rowCount + "] bind[" + bindLog + "]";
|
||||
transaction.logInternal(m);
|
||||
}
|
||||
|
||||
if (updateSql.isAutoTableMod()) {
|
||||
// add the modification info to the TransactionEvent
|
||||
// this is used to invalidate cached objects etc
|
||||
switch (sqlType) {
|
||||
case SQL_INSERT:
|
||||
transaction.getEvent().add(tableName, true, false, false);
|
||||
break;
|
||||
case SQL_UPDATE:
|
||||
transaction.getEvent().add(tableName, false, true, false);
|
||||
break;
|
||||
case SQL_DELETE:
|
||||
transaction.getEvent().add(tableName, false, false, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiSqlUpdate;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.persist.PersistExecute;
|
||||
|
||||
/**
|
||||
* Persist request specifically for CallableSql.
|
||||
*/
|
||||
public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
|
||||
public enum SqlType {
|
||||
SQL_UPDATE, SQL_DELETE, SQL_INSERT, SQL_UNKNOWN
|
||||
};
|
||||
|
||||
private final SpiSqlUpdate updateSql;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private String bindLog;
|
||||
|
||||
private SqlType sqlType;
|
||||
|
||||
private String tableName;
|
||||
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Create.
|
||||
*/
|
||||
public PersistRequestUpdateSql(SpiEbeanServer server, SqlUpdate updateSql,
|
||||
SpiTransaction t, PersistExecute persistExecute) {
|
||||
super(server, t, persistExecute);
|
||||
this.type = Type.UPDATESQL;
|
||||
this.updateSql = (SpiSqlUpdate)updateSql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeNow() {
|
||||
return persistExecute.executeSqlUpdate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeOrQueue() {
|
||||
return executeStatement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the UpdateSql.
|
||||
*/
|
||||
public SpiSqlUpdate getUpdateSql() {
|
||||
return updateSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* No concurrency checking so just note the rowCount.
|
||||
*/
|
||||
public void checkRowCount(int count) throws SQLException {
|
||||
this.rowCount = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always false.
|
||||
*/
|
||||
public boolean useGeneratedKeys() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not called for this type of request.
|
||||
*/
|
||||
public void setGeneratedKey(Object idValue) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the type of statement executed. Used to automatically register
|
||||
* with the transaction event.
|
||||
*/
|
||||
public void setType(SqlType sqlType, String tableName, String description) {
|
||||
this.sqlType = sqlType;
|
||||
this.tableName = tableName;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bound values.
|
||||
*/
|
||||
public void setBindLog(String bindLog) {
|
||||
this.bindLog = bindLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform post execute processing.
|
||||
*/
|
||||
public void postExecute() throws SQLException {
|
||||
|
||||
if (transaction.isLogSummary()) {
|
||||
String m = description + " table[" + tableName + "] rows["+ rowCount + "] bind[" + bindLog + "]";
|
||||
transaction.logInternal(m);
|
||||
}
|
||||
|
||||
if (updateSql.isAutoTableMod()) {
|
||||
// add the modification info to the TransactionEvent
|
||||
// this is used to invalidate cached objects etc
|
||||
switch (sqlType) {
|
||||
case SQL_INSERT:
|
||||
transaction.getEvent().add(tableName, true, false, false);
|
||||
break;
|
||||
case SQL_UPDATE:
|
||||
transaction.getEvent().add(tableName, false, true, false);
|
||||
break;
|
||||
case SQL_DELETE:
|
||||
transaction.getEvent().add(tableName, false, false, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,107 +1,88 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.CallableSql;
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.Update;
|
||||
|
||||
|
||||
/**
|
||||
* API for persisting a bean.
|
||||
*/
|
||||
public interface Persister {
|
||||
|
||||
/**
|
||||
* Force an Update using the given bean.
|
||||
*/
|
||||
public void forceUpdate(Object entityBean, Set<String> updateProps, Transaction t, boolean deleteMissingChildren, boolean updateNullProperties);
|
||||
|
||||
/**
|
||||
* Force an Insert using the given bean.
|
||||
*/
|
||||
public void forceInsert(Object entityBean, Transaction t);
|
||||
|
||||
/**
|
||||
* Insert or update the bean depending on its state.
|
||||
*/
|
||||
public void save(Object entityBean, Transaction t);
|
||||
|
||||
/**
|
||||
* Save the associations of a ManyToMany given the owner bean and the
|
||||
* propertyName of the ManyToMany collection.
|
||||
*/
|
||||
public void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
|
||||
|
||||
/**
|
||||
* Save an association (OneToMany, ManyToOne, OneToOne or ManyToMany).
|
||||
*
|
||||
* @param parentBean
|
||||
* the bean that owns the association.
|
||||
* @param propertyName
|
||||
* the name of the property to save.
|
||||
* @param t
|
||||
* the transaction to use.
|
||||
*/
|
||||
public void saveAssociation(Object parentBean, String propertyName, Transaction t);
|
||||
|
||||
/**
|
||||
* Delete the associations of a ManyToMany given the owner bean and the property name of the ManyToMany.
|
||||
*/
|
||||
public int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
|
||||
|
||||
/**
|
||||
* Delete a bean given it's type and id value.
|
||||
* <p>
|
||||
* This will also cascade delete one level of children.
|
||||
* </p>
|
||||
*/
|
||||
public int delete(Class<?> beanType, Object id, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Delete the bean.
|
||||
*/
|
||||
public void delete(Object entityBean, Transaction t);
|
||||
|
||||
/**
|
||||
* Delete multiple beans given a collection of Id values.
|
||||
*/
|
||||
public void deleteMany(Class<?> beanType, Collection<?> ids, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the Update.
|
||||
*/
|
||||
public int executeOrmUpdate(Update<?> update, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the UpdateSql.
|
||||
*/
|
||||
public int executeSqlUpdate(SqlUpdate update, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the CallableSql.
|
||||
*/
|
||||
public int executeCallable(CallableSql callable, Transaction t);
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.CallableSql;
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.Update;
|
||||
|
||||
|
||||
/**
|
||||
* API for persisting a bean.
|
||||
*/
|
||||
public interface Persister {
|
||||
|
||||
/**
|
||||
* Force an Update using the given bean.
|
||||
*/
|
||||
public void forceUpdate(Object entityBean, Set<String> updateProps, Transaction t, boolean deleteMissingChildren, boolean updateNullProperties);
|
||||
|
||||
/**
|
||||
* Force an Insert using the given bean.
|
||||
*/
|
||||
public void forceInsert(Object entityBean, Transaction t);
|
||||
|
||||
/**
|
||||
* Insert or update the bean depending on its state.
|
||||
*/
|
||||
public void save(Object entityBean, Transaction t);
|
||||
|
||||
/**
|
||||
* Save the associations of a ManyToMany given the owner bean and the
|
||||
* propertyName of the ManyToMany collection.
|
||||
*/
|
||||
public void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
|
||||
|
||||
/**
|
||||
* Save an association (OneToMany, ManyToOne, OneToOne or ManyToMany).
|
||||
*
|
||||
* @param parentBean
|
||||
* the bean that owns the association.
|
||||
* @param propertyName
|
||||
* the name of the property to save.
|
||||
* @param t
|
||||
* the transaction to use.
|
||||
*/
|
||||
public void saveAssociation(Object parentBean, String propertyName, Transaction t);
|
||||
|
||||
/**
|
||||
* Delete the associations of a ManyToMany given the owner bean and the property name of the ManyToMany.
|
||||
*/
|
||||
public int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
|
||||
|
||||
/**
|
||||
* Delete a bean given it's type and id value.
|
||||
* <p>
|
||||
* This will also cascade delete one level of children.
|
||||
* </p>
|
||||
*/
|
||||
public int delete(Class<?> beanType, Object id, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Delete the bean.
|
||||
*/
|
||||
public void delete(Object entityBean, Transaction t);
|
||||
|
||||
/**
|
||||
* Delete multiple beans given a collection of Id values.
|
||||
*/
|
||||
public void deleteMany(Class<?> beanType, Collection<?> ids, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the Update.
|
||||
*/
|
||||
public int executeOrmUpdate(Update<?> update, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the UpdateSql.
|
||||
*/
|
||||
public int executeSqlUpdate(SqlUpdate update, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the CallableSql.
|
||||
*/
|
||||
public int executeCallable(CallableSql callable, Transaction t);
|
||||
|
||||
}
|
||||
|
||||
+92
-111
@@ -1,111 +1,92 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.bean.SerializeControl;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.subclass.SubClassUtil;
|
||||
|
||||
/**
|
||||
* Read an ObjectInputStream potentially containing "proxy" / "subclassed"
|
||||
* entity objects.
|
||||
* <p>
|
||||
* This does not need to be used for "Enhanced" beans... but if you want to
|
||||
* deserialise "proxy" / "subclassed" beans you need to use this
|
||||
* ProxyBeanObjectInputStream. The reason is because it is required to resolve
|
||||
* the class (The class with the $$EntityBean suffix). As this class is in
|
||||
* another class loader typically as plain ObjectInputStream is unable to resolve
|
||||
* the class - and hence we need to use this ProxyBeanObjectInputStream.
|
||||
* </p>
|
||||
*/
|
||||
public class ProxyBeanObjectInputStream extends ObjectInputStream {
|
||||
|
||||
private final SpiEbeanServer ebeanServer;
|
||||
|
||||
/**
|
||||
* Create with a given InputStream and EbeanServer.
|
||||
* <p>
|
||||
* The EbeanServer should be the one that created the 'proxy' classes that
|
||||
* were serialised.
|
||||
* </p>
|
||||
*/
|
||||
public ProxyBeanObjectInputStream(InputStream in, EbeanServer ebeanServer)
|
||||
throws IOException {
|
||||
|
||||
super(in);
|
||||
this.ebeanServer = (SpiEbeanServer) ebeanServer;
|
||||
SerializeControl.setVanilla(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* close and reset the serialization mode.
|
||||
* <p>
|
||||
* uses SerializeControl.resetToDefault().
|
||||
* </p>
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
SerializeControl.resetToDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the generated Class potentially using reading the embedded
|
||||
* MethodInfo.
|
||||
*/
|
||||
protected Class<?> resolveGenerated(ObjectStreamClass desc)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
String className = desc.getName();
|
||||
|
||||
String vanillaClassName = SubClassUtil.getSuperClassName(className);
|
||||
Class<?> vanillaClass = ClassUtil.forName(vanillaClassName, this.getClass());
|
||||
|
||||
BeanDescriptor<?> d = ebeanServer.getBeanDescriptor(vanillaClass);
|
||||
if (d == null) {
|
||||
String msg = "Could not find BeanDescriptor for "+ vanillaClassName;
|
||||
throw new IOException(msg);
|
||||
} else {
|
||||
return d.getFactoryType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks for generated subclasses and handles them appropriately.
|
||||
*/
|
||||
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException,
|
||||
ClassNotFoundException {
|
||||
|
||||
String className = desc.getName();
|
||||
if (SubClassUtil.isSubClass(className)) {
|
||||
return resolveGenerated(desc);
|
||||
}
|
||||
|
||||
return super.resolveClass(desc);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.bean.SerializeControl;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.subclass.SubClassUtil;
|
||||
|
||||
/**
|
||||
* Read an ObjectInputStream potentially containing "proxy" / "subclassed"
|
||||
* entity objects.
|
||||
* <p>
|
||||
* This does not need to be used for "Enhanced" beans... but if you want to
|
||||
* deserialise "proxy" / "subclassed" beans you need to use this
|
||||
* ProxyBeanObjectInputStream. The reason is because it is required to resolve
|
||||
* the class (The class with the $$EntityBean suffix). As this class is in
|
||||
* another class loader typically as plain ObjectInputStream is unable to resolve
|
||||
* the class - and hence we need to use this ProxyBeanObjectInputStream.
|
||||
* </p>
|
||||
*/
|
||||
public class ProxyBeanObjectInputStream extends ObjectInputStream {
|
||||
|
||||
private final SpiEbeanServer ebeanServer;
|
||||
|
||||
/**
|
||||
* Create with a given InputStream and EbeanServer.
|
||||
* <p>
|
||||
* The EbeanServer should be the one that created the 'proxy' classes that
|
||||
* were serialised.
|
||||
* </p>
|
||||
*/
|
||||
public ProxyBeanObjectInputStream(InputStream in, EbeanServer ebeanServer)
|
||||
throws IOException {
|
||||
|
||||
super(in);
|
||||
this.ebeanServer = (SpiEbeanServer) ebeanServer;
|
||||
SerializeControl.setVanilla(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* close and reset the serialization mode.
|
||||
* <p>
|
||||
* uses SerializeControl.resetToDefault().
|
||||
* </p>
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
SerializeControl.resetToDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the generated Class potentially using reading the embedded
|
||||
* MethodInfo.
|
||||
*/
|
||||
protected Class<?> resolveGenerated(ObjectStreamClass desc)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
String className = desc.getName();
|
||||
|
||||
String vanillaClassName = SubClassUtil.getSuperClassName(className);
|
||||
Class<?> vanillaClass = ClassUtil.forName(vanillaClassName, this.getClass());
|
||||
|
||||
BeanDescriptor<?> d = ebeanServer.getBeanDescriptor(vanillaClass);
|
||||
if (d == null) {
|
||||
String msg = "Could not find BeanDescriptor for "+ vanillaClassName;
|
||||
throw new IOException(msg);
|
||||
} else {
|
||||
return d.getFactoryType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks for generated subclasses and handles them appropriately.
|
||||
*/
|
||||
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException,
|
||||
ClassNotFoundException {
|
||||
|
||||
String className = desc.getName();
|
||||
if (SubClassUtil.isSubClass(className)) {
|
||||
return resolveGenerated(desc);
|
||||
}
|
||||
|
||||
return super.resolveClass(desc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,36 +1,17 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* If Oracle supported the JDBC api fully this would not be required.
|
||||
*/
|
||||
public interface PstmtBatch {
|
||||
|
||||
public void setBatchSize(PreparedStatement pstmt, int batchSize);
|
||||
|
||||
public void addBatch(PreparedStatement pstmt) throws SQLException;
|
||||
|
||||
public int executeBatch(PreparedStatement pstmt, int expectedRows, String sql, boolean occCheck) throws SQLException;
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* If Oracle supported the JDBC api fully this would not be required.
|
||||
*/
|
||||
public interface PstmtBatch {
|
||||
|
||||
public void setBatchSize(PreparedStatement pstmt, int batchSize);
|
||||
|
||||
public void addBatch(PreparedStatement pstmt) throws SQLException;
|
||||
|
||||
public int executeBatch(PreparedStatement pstmt, int expectedRows, String sql, boolean occCheck) throws SQLException;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,234 +1,215 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
|
||||
/**
|
||||
* Helper for performing a 'refresh' on an Entity bean.
|
||||
* <p>
|
||||
* Note that this does not 'refresh' any OnetoMany or ManyToMany properties. It
|
||||
* refreshes all the other properties though.
|
||||
* </p>
|
||||
*/
|
||||
public class RefreshHelp {
|
||||
//
|
||||
// /**
|
||||
// * Helper for debug of lazy loading.
|
||||
// */
|
||||
// private final DebugLazyLoad debugLazyLoad;
|
||||
//
|
||||
// private final MAdminLoggingMBean logControl;
|
||||
//
|
||||
// public RefreshHelp(MAdminLoggingMBean logControl, boolean debugLazyLoad){
|
||||
// this.logControl = logControl;
|
||||
// this.debugLazyLoad = new DebugLazyLoad(debugLazyLoad);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Refresh the bean from property values in dbBean.
|
||||
// */
|
||||
// public void refresh(Object o, Object dbBean, BeanDescriptor<?> desc, EntityBeanIntercept ebi, Object id, boolean isLazyLoad) {
|
||||
//
|
||||
// Object originalOldValues = null;
|
||||
// boolean setOriginalOldValues = false;
|
||||
//
|
||||
// // set of properties to exclude from the refresh because it is
|
||||
// // not a refresh but rather a lazyLoading event.
|
||||
// Set<String> excludes = null;
|
||||
//
|
||||
// // turn off intercepting so lazy loading is
|
||||
// // not invoked when populating the bean
|
||||
// // with PropertyChangeSupport
|
||||
// ebi.setIntercepting(false);
|
||||
//
|
||||
// boolean readOnly = ebi.isReadOnly();
|
||||
// boolean sharedInstance = ebi.isSharedInstance();
|
||||
//
|
||||
// if (isLazyLoad){
|
||||
// excludes = ebi.getLoadedProps();
|
||||
// if (excludes != null){
|
||||
// // lazy loading a "Partial Object"... which already
|
||||
// // contains some properties and perhaps some oldValues
|
||||
// // and these will need to be maintained...
|
||||
// originalOldValues = ebi.getOldValues();
|
||||
// setOriginalOldValues = originalOldValues != null;
|
||||
// }
|
||||
//
|
||||
// if (logControl.isDebugLazyLoad()){
|
||||
// debug(desc, ebi, id, excludes);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// BeanProperty[] props = desc.propertiesBaseScalar();
|
||||
// for (int i = 0; i < props.length; i++) {
|
||||
// BeanProperty prop = props[i];
|
||||
// if (excludes != null && excludes.contains(prop.getName())){
|
||||
// // ignore this property (partial bean lazy loading)
|
||||
//
|
||||
// } else {
|
||||
// Object dbVal = prop.getValue(dbBean);
|
||||
// if (isLazyLoad) {
|
||||
// prop.setValue(o, dbVal);
|
||||
// } else {
|
||||
// prop.setValueIntercept(o, dbVal);
|
||||
// }
|
||||
// if (setOriginalOldValues){
|
||||
// // maintain original oldValues for partially loaded bean
|
||||
// prop.setValue(originalOldValues, dbVal);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// BeanPropertyAssocOne<?>[] ones = desc.propertiesOne();
|
||||
// for (int i = 0; i < ones.length; i++) {
|
||||
// BeanProperty prop = ones[i];
|
||||
// if (excludes != null && excludes.contains(prop.getName())){
|
||||
// // ignore this property (partial bean lazy loading)
|
||||
//
|
||||
// } else {
|
||||
// Object dbVal = prop.getValue(dbBean);
|
||||
// if (isLazyLoad){
|
||||
// prop.setValue(o, dbVal);
|
||||
// } else {
|
||||
// prop.setValueIntercept(o, dbVal);
|
||||
// }
|
||||
// if (setOriginalOldValues){
|
||||
// // maintain original oldValues for partially loaded bean
|
||||
// prop.setValue(originalOldValues, dbVal);
|
||||
// }
|
||||
// if (dbVal != null){
|
||||
// if (sharedInstance){
|
||||
// // propagate sharedInstance status to associated beans
|
||||
// ((EntityBean)dbVal)._ebean_getIntercept().setSharedInstance();
|
||||
// } else if (readOnly) {
|
||||
// // propagate readOnly status to associated beans
|
||||
// ((EntityBean)dbVal)._ebean_getIntercept().setReadOnly(true);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// refreshEmbedded(o, dbBean, desc, excludes, readOnly);
|
||||
//
|
||||
// // set a lazy loading many proxy if required
|
||||
// BeanPropertyAssocMany<?>[] manys = desc.propertiesMany();
|
||||
// for (int i = 0; i < manys.length; i++) {
|
||||
// BeanPropertyAssocMany<?> prop = manys[i];
|
||||
// if (excludes != null && excludes.contains(prop.getName())){
|
||||
// // the many already existed on the bean
|
||||
//
|
||||
// } else {
|
||||
// // set a lazy loading proxy
|
||||
// prop.createReference(o, null, readOnly, sharedInstance);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // the refreshed/lazy loaded bean is always fully
|
||||
// // populated so set loadedProps to null
|
||||
// ebi.setLoadedProps(null);
|
||||
//
|
||||
//
|
||||
// // reset the loaded status
|
||||
// ebi.setLoaded();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Refresh the Embedded beans.
|
||||
// */
|
||||
// private void refreshEmbedded(Object o, Object dbBean, BeanDescriptor<?> desc, Set<String> excludes, boolean propagateReadOnly) {
|
||||
//
|
||||
// BeanPropertyAssocOne<?>[] embeds = desc.propertiesEmbedded();
|
||||
// for (int i = 0; i < embeds.length; i++) {
|
||||
// BeanPropertyAssocOne<?> prop = embeds[i];
|
||||
// if (excludes != null && excludes.contains(prop.getName())){
|
||||
// // ignore this property
|
||||
// } else {
|
||||
// // the original embedded bean
|
||||
// Object oEmb = prop.getValue(o);
|
||||
//
|
||||
// // the new one from the database
|
||||
// Object dbEmb = prop.getValue(dbBean);
|
||||
//
|
||||
// if (oEmb == null){
|
||||
// // original embedded bean was null
|
||||
// // so just replace the entire embedded bean
|
||||
// prop.setValueIntercept(o, dbEmb);
|
||||
// if (propagateReadOnly && dbEmb != null){
|
||||
// // propagate readOnly status to embedded beans
|
||||
// ((EntityBean)dbEmb)._ebean_getIntercept().setReadOnly(true);
|
||||
// }
|
||||
//
|
||||
// } else {
|
||||
// // refresh each property of the original
|
||||
// // embedded bean
|
||||
// if (oEmb instanceof EntityBean){
|
||||
// // turn off interception to stop invoking lazy loading
|
||||
// // but allow PropertyChangeSupport
|
||||
// ((EntityBean) oEmb)._ebean_getIntercept().setIntercepting(false);
|
||||
// }
|
||||
//
|
||||
// BeanProperty[] props = prop.getProperties();
|
||||
// for (int j = 0; j < props.length; j++) {
|
||||
// Object v = props[j].getValue(dbEmb);
|
||||
// props[j].setValueIntercept(oEmb, v);
|
||||
// }
|
||||
//
|
||||
// // No longer calling setLoaded() on embedded bean
|
||||
// // as the EntityBean itself
|
||||
// // .. calls setEmbeddedLoaded() on each of
|
||||
// // .. its embedded beans itself.
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * Output some debug to describe the lazy loading event.
|
||||
// */
|
||||
// private void debug(BeanDescriptor<?> desc, EntityBeanIntercept ebi, Object id, Set<String> excludes) {
|
||||
//
|
||||
//
|
||||
// Class<?> beanType = desc.getBeanType();
|
||||
//
|
||||
// StackTraceElement cause = debugLazyLoad.getStackTraceElement(beanType);
|
||||
//
|
||||
// String lazyLoadProperty = ebi.getLazyLoadProperty();
|
||||
// String msg = "debug.lazyLoad ["+desc+"] id["+id+"] lazyLoadProperty["+lazyLoadProperty+"]";
|
||||
// if (excludes != null){
|
||||
// msg += " partialProps"+excludes;
|
||||
// }
|
||||
// if (cause != null){
|
||||
// String causeLine = cause.toString();
|
||||
// if (causeLine.indexOf(".groovy:") > -1){
|
||||
// // eclipse console does not like finding groovy source at the moment
|
||||
// causeLine = StringHelper.replaceString(causeLine, ".groovy:", ".groovy :");
|
||||
// }
|
||||
// msg += " at: "+causeLine;
|
||||
// }
|
||||
// System.err.println(msg);
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
|
||||
/**
|
||||
* Helper for performing a 'refresh' on an Entity bean.
|
||||
* <p>
|
||||
* Note that this does not 'refresh' any OnetoMany or ManyToMany properties. It
|
||||
* refreshes all the other properties though.
|
||||
* </p>
|
||||
*/
|
||||
public class RefreshHelp {
|
||||
//
|
||||
// /**
|
||||
// * Helper for debug of lazy loading.
|
||||
// */
|
||||
// private final DebugLazyLoad debugLazyLoad;
|
||||
//
|
||||
// private final MAdminLoggingMBean logControl;
|
||||
//
|
||||
// public RefreshHelp(MAdminLoggingMBean logControl, boolean debugLazyLoad){
|
||||
// this.logControl = logControl;
|
||||
// this.debugLazyLoad = new DebugLazyLoad(debugLazyLoad);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Refresh the bean from property values in dbBean.
|
||||
// */
|
||||
// public void refresh(Object o, Object dbBean, BeanDescriptor<?> desc, EntityBeanIntercept ebi, Object id, boolean isLazyLoad) {
|
||||
//
|
||||
// Object originalOldValues = null;
|
||||
// boolean setOriginalOldValues = false;
|
||||
//
|
||||
// // set of properties to exclude from the refresh because it is
|
||||
// // not a refresh but rather a lazyLoading event.
|
||||
// Set<String> excludes = null;
|
||||
//
|
||||
// // turn off intercepting so lazy loading is
|
||||
// // not invoked when populating the bean
|
||||
// // with PropertyChangeSupport
|
||||
// ebi.setIntercepting(false);
|
||||
//
|
||||
// boolean readOnly = ebi.isReadOnly();
|
||||
// boolean sharedInstance = ebi.isSharedInstance();
|
||||
//
|
||||
// if (isLazyLoad){
|
||||
// excludes = ebi.getLoadedProps();
|
||||
// if (excludes != null){
|
||||
// // lazy loading a "Partial Object"... which already
|
||||
// // contains some properties and perhaps some oldValues
|
||||
// // and these will need to be maintained...
|
||||
// originalOldValues = ebi.getOldValues();
|
||||
// setOriginalOldValues = originalOldValues != null;
|
||||
// }
|
||||
//
|
||||
// if (logControl.isDebugLazyLoad()){
|
||||
// debug(desc, ebi, id, excludes);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// BeanProperty[] props = desc.propertiesBaseScalar();
|
||||
// for (int i = 0; i < props.length; i++) {
|
||||
// BeanProperty prop = props[i];
|
||||
// if (excludes != null && excludes.contains(prop.getName())){
|
||||
// // ignore this property (partial bean lazy loading)
|
||||
//
|
||||
// } else {
|
||||
// Object dbVal = prop.getValue(dbBean);
|
||||
// if (isLazyLoad) {
|
||||
// prop.setValue(o, dbVal);
|
||||
// } else {
|
||||
// prop.setValueIntercept(o, dbVal);
|
||||
// }
|
||||
// if (setOriginalOldValues){
|
||||
// // maintain original oldValues for partially loaded bean
|
||||
// prop.setValue(originalOldValues, dbVal);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// BeanPropertyAssocOne<?>[] ones = desc.propertiesOne();
|
||||
// for (int i = 0; i < ones.length; i++) {
|
||||
// BeanProperty prop = ones[i];
|
||||
// if (excludes != null && excludes.contains(prop.getName())){
|
||||
// // ignore this property (partial bean lazy loading)
|
||||
//
|
||||
// } else {
|
||||
// Object dbVal = prop.getValue(dbBean);
|
||||
// if (isLazyLoad){
|
||||
// prop.setValue(o, dbVal);
|
||||
// } else {
|
||||
// prop.setValueIntercept(o, dbVal);
|
||||
// }
|
||||
// if (setOriginalOldValues){
|
||||
// // maintain original oldValues for partially loaded bean
|
||||
// prop.setValue(originalOldValues, dbVal);
|
||||
// }
|
||||
// if (dbVal != null){
|
||||
// if (sharedInstance){
|
||||
// // propagate sharedInstance status to associated beans
|
||||
// ((EntityBean)dbVal)._ebean_getIntercept().setSharedInstance();
|
||||
// } else if (readOnly) {
|
||||
// // propagate readOnly status to associated beans
|
||||
// ((EntityBean)dbVal)._ebean_getIntercept().setReadOnly(true);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// refreshEmbedded(o, dbBean, desc, excludes, readOnly);
|
||||
//
|
||||
// // set a lazy loading many proxy if required
|
||||
// BeanPropertyAssocMany<?>[] manys = desc.propertiesMany();
|
||||
// for (int i = 0; i < manys.length; i++) {
|
||||
// BeanPropertyAssocMany<?> prop = manys[i];
|
||||
// if (excludes != null && excludes.contains(prop.getName())){
|
||||
// // the many already existed on the bean
|
||||
//
|
||||
// } else {
|
||||
// // set a lazy loading proxy
|
||||
// prop.createReference(o, null, readOnly, sharedInstance);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // the refreshed/lazy loaded bean is always fully
|
||||
// // populated so set loadedProps to null
|
||||
// ebi.setLoadedProps(null);
|
||||
//
|
||||
//
|
||||
// // reset the loaded status
|
||||
// ebi.setLoaded();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Refresh the Embedded beans.
|
||||
// */
|
||||
// private void refreshEmbedded(Object o, Object dbBean, BeanDescriptor<?> desc, Set<String> excludes, boolean propagateReadOnly) {
|
||||
//
|
||||
// BeanPropertyAssocOne<?>[] embeds = desc.propertiesEmbedded();
|
||||
// for (int i = 0; i < embeds.length; i++) {
|
||||
// BeanPropertyAssocOne<?> prop = embeds[i];
|
||||
// if (excludes != null && excludes.contains(prop.getName())){
|
||||
// // ignore this property
|
||||
// } else {
|
||||
// // the original embedded bean
|
||||
// Object oEmb = prop.getValue(o);
|
||||
//
|
||||
// // the new one from the database
|
||||
// Object dbEmb = prop.getValue(dbBean);
|
||||
//
|
||||
// if (oEmb == null){
|
||||
// // original embedded bean was null
|
||||
// // so just replace the entire embedded bean
|
||||
// prop.setValueIntercept(o, dbEmb);
|
||||
// if (propagateReadOnly && dbEmb != null){
|
||||
// // propagate readOnly status to embedded beans
|
||||
// ((EntityBean)dbEmb)._ebean_getIntercept().setReadOnly(true);
|
||||
// }
|
||||
//
|
||||
// } else {
|
||||
// // refresh each property of the original
|
||||
// // embedded bean
|
||||
// if (oEmb instanceof EntityBean){
|
||||
// // turn off interception to stop invoking lazy loading
|
||||
// // but allow PropertyChangeSupport
|
||||
// ((EntityBean) oEmb)._ebean_getIntercept().setIntercepting(false);
|
||||
// }
|
||||
//
|
||||
// BeanProperty[] props = prop.getProperties();
|
||||
// for (int j = 0; j < props.length; j++) {
|
||||
// Object v = props[j].getValue(dbEmb);
|
||||
// props[j].setValueIntercept(oEmb, v);
|
||||
// }
|
||||
//
|
||||
// // No longer calling setLoaded() on embedded bean
|
||||
// // as the EntityBean itself
|
||||
// // .. calls setEmbeddedLoaded() on each of
|
||||
// // .. its embedded beans itself.
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * Output some debug to describe the lazy loading event.
|
||||
// */
|
||||
// private void debug(BeanDescriptor<?> desc, EntityBeanIntercept ebi, Object id, Set<String> excludes) {
|
||||
//
|
||||
//
|
||||
// Class<?> beanType = desc.getBeanType();
|
||||
//
|
||||
// StackTraceElement cause = debugLazyLoad.getStackTraceElement(beanType);
|
||||
//
|
||||
// String lazyLoadProperty = ebi.getLazyLoadProperty();
|
||||
// String msg = "debug.lazyLoad ["+desc+"] id["+id+"] lazyLoadProperty["+lazyLoadProperty+"]";
|
||||
// if (excludes != null){
|
||||
// msg += " partialProps"+excludes;
|
||||
// }
|
||||
// if (cause != null){
|
||||
// String causeLine = cause.toString();
|
||||
// if (causeLine.indexOf(".groovy:") > -1){
|
||||
// // eclipse console does not like finding groovy source at the moment
|
||||
// causeLine = StringHelper.replaceString(causeLine, ".groovy:", ".groovy :");
|
||||
// }
|
||||
// msg += " at: "+causeLine;
|
||||
// }
|
||||
// System.err.println(msg);
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
@@ -1,147 +1,128 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.SqlQuery;
|
||||
import com.avaje.ebean.SqlRow;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiSqlQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
|
||||
/**
|
||||
* Wraps the objects involved in executing a SqlQuery.
|
||||
*/
|
||||
public final class RelationalQueryRequest {
|
||||
|
||||
private final SpiSqlQuery query;
|
||||
|
||||
private final RelationalQueryEngine queryEngine;
|
||||
|
||||
private final SpiEbeanServer ebeanServer;
|
||||
|
||||
private SpiTransaction trans;
|
||||
|
||||
private boolean createdTransaction;
|
||||
|
||||
private SpiQuery.Type queryType;
|
||||
|
||||
/**
|
||||
* Create the BeanFindRequest.
|
||||
*/
|
||||
public RelationalQueryRequest(SpiEbeanServer server, RelationalQueryEngine engine, SqlQuery q, Transaction t) {
|
||||
this.ebeanServer = server;
|
||||
this.queryEngine = engine;
|
||||
this.query = (SpiSqlQuery) q;
|
||||
this.trans = (SpiTransaction) t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if it was created for this request.
|
||||
*/
|
||||
public void rollbackTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
trans.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction if none currently exists.
|
||||
*/
|
||||
public void initTransIfRequired() {
|
||||
if (trans == null) {
|
||||
trans = ebeanServer.getCurrentServerTransaction();
|
||||
if (trans == null || !trans.isActive()) {
|
||||
// create a local readOnly transaction
|
||||
trans = ebeanServer.createServerTransaction(false, -1);
|
||||
|
||||
// commented out for performance reasons...
|
||||
// TODO: review performance of trans.setReadOnly(true)
|
||||
// trans.setReadOnly(true);
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* End the transaction if it was locally created.
|
||||
*/
|
||||
public void endTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
// we can rollback as a readOnly transaction.
|
||||
trans.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<SqlRow> findList() {
|
||||
queryType = SpiQuery.Type.LIST;
|
||||
return (List<SqlRow>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<SqlRow> findSet() {
|
||||
queryType = SpiQuery.Type.SET;
|
||||
return (Set<SqlRow>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<?, SqlRow> findMap() {
|
||||
queryType = SpiQuery.Type.MAP;
|
||||
return (Map<?, SqlRow>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the find that is to be performed.
|
||||
*/
|
||||
public SpiSqlQuery getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type (List, Set or Map) that this fetch returns.
|
||||
*/
|
||||
public SpiQuery.Type getQueryType() {
|
||||
return queryType;
|
||||
}
|
||||
|
||||
public EbeanServer getEbeanServer() {
|
||||
return ebeanServer;
|
||||
}
|
||||
|
||||
public SpiTransaction getTransaction() {
|
||||
return trans;
|
||||
}
|
||||
|
||||
public boolean isLogSql() {
|
||||
return trans.isLogSql();
|
||||
}
|
||||
|
||||
public boolean isLogSummary() {
|
||||
return trans.isLogSummary();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.SqlQuery;
|
||||
import com.avaje.ebean.SqlRow;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiSqlQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
|
||||
/**
|
||||
* Wraps the objects involved in executing a SqlQuery.
|
||||
*/
|
||||
public final class RelationalQueryRequest {
|
||||
|
||||
private final SpiSqlQuery query;
|
||||
|
||||
private final RelationalQueryEngine queryEngine;
|
||||
|
||||
private final SpiEbeanServer ebeanServer;
|
||||
|
||||
private SpiTransaction trans;
|
||||
|
||||
private boolean createdTransaction;
|
||||
|
||||
private SpiQuery.Type queryType;
|
||||
|
||||
/**
|
||||
* Create the BeanFindRequest.
|
||||
*/
|
||||
public RelationalQueryRequest(SpiEbeanServer server, RelationalQueryEngine engine, SqlQuery q, Transaction t) {
|
||||
this.ebeanServer = server;
|
||||
this.queryEngine = engine;
|
||||
this.query = (SpiSqlQuery) q;
|
||||
this.trans = (SpiTransaction) t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if it was created for this request.
|
||||
*/
|
||||
public void rollbackTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
trans.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction if none currently exists.
|
||||
*/
|
||||
public void initTransIfRequired() {
|
||||
if (trans == null) {
|
||||
trans = ebeanServer.getCurrentServerTransaction();
|
||||
if (trans == null || !trans.isActive()) {
|
||||
// create a local readOnly transaction
|
||||
trans = ebeanServer.createServerTransaction(false, -1);
|
||||
|
||||
// commented out for performance reasons...
|
||||
// TODO: review performance of trans.setReadOnly(true)
|
||||
// trans.setReadOnly(true);
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* End the transaction if it was locally created.
|
||||
*/
|
||||
public void endTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
// we can rollback as a readOnly transaction.
|
||||
trans.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<SqlRow> findList() {
|
||||
queryType = SpiQuery.Type.LIST;
|
||||
return (List<SqlRow>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<SqlRow> findSet() {
|
||||
queryType = SpiQuery.Type.SET;
|
||||
return (Set<SqlRow>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<?, SqlRow> findMap() {
|
||||
queryType = SpiQuery.Type.MAP;
|
||||
return (Map<?, SqlRow>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the find that is to be performed.
|
||||
*/
|
||||
public SpiSqlQuery getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type (List, Set or Map) that this fetch returns.
|
||||
*/
|
||||
public SpiQuery.Type getQueryType() {
|
||||
return queryType;
|
||||
}
|
||||
|
||||
public EbeanServer getEbeanServer() {
|
||||
return ebeanServer;
|
||||
}
|
||||
|
||||
public SpiTransaction getTransaction() {
|
||||
return trans;
|
||||
}
|
||||
|
||||
public boolean isLogSql() {
|
||||
return trans.isLogSql();
|
||||
}
|
||||
|
||||
public boolean isLogSummary() {
|
||||
return trans.isLogSummary();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,76 +1,57 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
|
||||
|
||||
/**
|
||||
* Listens for webserver server starting and stopping events.
|
||||
*
|
||||
* <p>
|
||||
* Register this listener in the web.xml configuration file. This will listen
|
||||
* for startup and shutdown events.
|
||||
* </p>
|
||||
*/
|
||||
public class ServletContextListener implements javax.servlet.ServletContextListener {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ServletContextListener.class.getName());
|
||||
|
||||
/**
|
||||
* The servlet container is stopping.
|
||||
*/
|
||||
public void contextDestroyed(ServletContextEvent event) {
|
||||
ShutdownManager.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* The servlet container is starting.
|
||||
* <p>
|
||||
* Initialise the properties file using SystemProperties.initWebapp();
|
||||
* and start Ebean.
|
||||
* </p>
|
||||
*/
|
||||
public void contextInitialized(ServletContextEvent event) {
|
||||
|
||||
try {
|
||||
ServletContext servletContext = event.getServletContext();
|
||||
GlobalProperties.setServletContext(servletContext);
|
||||
|
||||
if (servletContext != null) {
|
||||
String servletRealPath = servletContext.getRealPath("");
|
||||
GlobalProperties.put("servlet.realpath", servletRealPath);
|
||||
logger.info("servlet.realpath=[" + servletRealPath + "]");
|
||||
}
|
||||
|
||||
Ebean.getServer(null);
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
|
||||
|
||||
/**
|
||||
* Listens for webserver server starting and stopping events.
|
||||
*
|
||||
* <p>
|
||||
* Register this listener in the web.xml configuration file. This will listen
|
||||
* for startup and shutdown events.
|
||||
* </p>
|
||||
*/
|
||||
public class ServletContextListener implements javax.servlet.ServletContextListener {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ServletContextListener.class.getName());
|
||||
|
||||
/**
|
||||
* The servlet container is stopping.
|
||||
*/
|
||||
public void contextDestroyed(ServletContextEvent event) {
|
||||
ShutdownManager.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* The servlet container is starting.
|
||||
* <p>
|
||||
* Initialise the properties file using SystemProperties.initWebapp();
|
||||
* and start Ebean.
|
||||
* </p>
|
||||
*/
|
||||
public void contextInitialized(ServletContextEvent event) {
|
||||
|
||||
try {
|
||||
ServletContext servletContext = event.getServletContext();
|
||||
GlobalProperties.setServletContext(servletContext);
|
||||
|
||||
if (servletContext != null) {
|
||||
String servletRealPath = servletContext.getRealPath("");
|
||||
GlobalProperties.put("servlet.realpath", servletRealPath);
|
||||
logger.info("servlet.realpath=[" + servletRealPath + "]");
|
||||
}
|
||||
|
||||
Ebean.getServer(null);
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,119 +1,100 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
/**
|
||||
* Defines the ORM query request api.
|
||||
*/
|
||||
public interface SpiOrmQueryRequest<T> {
|
||||
|
||||
/**
|
||||
* Return the query.
|
||||
*/
|
||||
public SpiQuery<T> getQuery();
|
||||
|
||||
/**
|
||||
* Return the associated BeanDescriptor.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
/**
|
||||
* This will create a local (readOnly) transaction if no current transaction
|
||||
* exists.
|
||||
* <p>
|
||||
* A transaction may have been passed in explicitly or currently be active
|
||||
* in the thread local. If not, then a readOnly transaction is created to
|
||||
* execute this query.
|
||||
* </p>
|
||||
*/
|
||||
public void initTransIfRequired();
|
||||
|
||||
/**
|
||||
* Will end a locally created transaction.
|
||||
* <p>
|
||||
* It ends the transaction by using a rollback() as the transaction is known
|
||||
* to be readOnly.
|
||||
* </p>
|
||||
*/
|
||||
public void endTransIfRequired();
|
||||
|
||||
public void rollbackTransIfRequired();
|
||||
|
||||
/**
|
||||
* Execute the query as findById.
|
||||
*/
|
||||
public Object findId();
|
||||
|
||||
/**
|
||||
* Execute the find row count query.
|
||||
*/
|
||||
public int findRowCount();
|
||||
|
||||
/**
|
||||
* Execute the find ids query.
|
||||
*/
|
||||
public List<Object> findIds();
|
||||
|
||||
/**
|
||||
* Execute the find returning a QueryIterator and visitor pattern.
|
||||
*/
|
||||
public void findVisit(QueryResultVisitor<T> visitor);
|
||||
|
||||
/**
|
||||
* Execute the find returning a QueryIterator.
|
||||
*/
|
||||
public QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* Execute the query as findList.
|
||||
*/
|
||||
public List<T> findList();
|
||||
|
||||
/**
|
||||
* Execute the query as findSet.
|
||||
*/
|
||||
public Set<?> findSet();
|
||||
|
||||
/**
|
||||
* Execute the query as findMap.
|
||||
*/
|
||||
public Map<?, ?> findMap();
|
||||
|
||||
/**
|
||||
* Try to get the object out of the persistence context.
|
||||
*/
|
||||
//public T getFromPersistenceContextOrCache();
|
||||
|
||||
/**
|
||||
* Try to get the query result from the query cache.
|
||||
*/
|
||||
public BeanCollection<T> getFromQueryCache();
|
||||
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
/**
|
||||
* Defines the ORM query request api.
|
||||
*/
|
||||
public interface SpiOrmQueryRequest<T> {
|
||||
|
||||
/**
|
||||
* Return the query.
|
||||
*/
|
||||
public SpiQuery<T> getQuery();
|
||||
|
||||
/**
|
||||
* Return the associated BeanDescriptor.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
/**
|
||||
* This will create a local (readOnly) transaction if no current transaction
|
||||
* exists.
|
||||
* <p>
|
||||
* A transaction may have been passed in explicitly or currently be active
|
||||
* in the thread local. If not, then a readOnly transaction is created to
|
||||
* execute this query.
|
||||
* </p>
|
||||
*/
|
||||
public void initTransIfRequired();
|
||||
|
||||
/**
|
||||
* Will end a locally created transaction.
|
||||
* <p>
|
||||
* It ends the transaction by using a rollback() as the transaction is known
|
||||
* to be readOnly.
|
||||
* </p>
|
||||
*/
|
||||
public void endTransIfRequired();
|
||||
|
||||
public void rollbackTransIfRequired();
|
||||
|
||||
/**
|
||||
* Execute the query as findById.
|
||||
*/
|
||||
public Object findId();
|
||||
|
||||
/**
|
||||
* Execute the find row count query.
|
||||
*/
|
||||
public int findRowCount();
|
||||
|
||||
/**
|
||||
* Execute the find ids query.
|
||||
*/
|
||||
public List<Object> findIds();
|
||||
|
||||
/**
|
||||
* Execute the find returning a QueryIterator and visitor pattern.
|
||||
*/
|
||||
public void findVisit(QueryResultVisitor<T> visitor);
|
||||
|
||||
/**
|
||||
* Execute the find returning a QueryIterator.
|
||||
*/
|
||||
public QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* Execute the query as findList.
|
||||
*/
|
||||
public List<T> findList();
|
||||
|
||||
/**
|
||||
* Execute the query as findSet.
|
||||
*/
|
||||
public Set<?> findSet();
|
||||
|
||||
/**
|
||||
* Execute the query as findMap.
|
||||
*/
|
||||
public Map<?, ?> findMap();
|
||||
|
||||
/**
|
||||
* Try to get the object out of the persistence context.
|
||||
*/
|
||||
//public T getFromPersistenceContextOrCache();
|
||||
|
||||
/**
|
||||
* Try to get the query result from the query cache.
|
||||
*/
|
||||
public BeanCollection<T> getFromQueryCache();
|
||||
|
||||
}
|
||||
+44
-63
@@ -1,63 +1,44 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonScheduleThreadPool;
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
|
||||
/**
|
||||
* BackgroundExecutor using my traditional ThreadPool that will grow and trim.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class TraditionalBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final ThreadPool pool;
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*/
|
||||
public TraditionalBackgroundExecutor(ThreadPool pool, int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = pool;
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix+"-periodic-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Runnable using a background thread.
|
||||
*/
|
||||
public void execute(Runnable r) {
|
||||
pool.assign(r, true);
|
||||
}
|
||||
|
||||
public void executePeriodically(Runnable r, long delay, TimeUnit unit) {
|
||||
schedulePool.scheduleWithFixedDelay(r, delay, delay, unit);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
// the pool is shutdown automatically by the ThreadPoolManager
|
||||
schedulePool.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonScheduleThreadPool;
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
|
||||
/**
|
||||
* BackgroundExecutor using my traditional ThreadPool that will grow and trim.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class TraditionalBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final ThreadPool pool;
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*/
|
||||
public TraditionalBackgroundExecutor(ThreadPool pool, int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = pool;
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix+"-periodic-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Runnable using a background thread.
|
||||
*/
|
||||
public void execute(Runnable r) {
|
||||
pool.assign(r, true);
|
||||
}
|
||||
|
||||
public void executePeriodically(Runnable r, long delay, TimeUnit unit) {
|
||||
schedulePool.scheduleWithFixedDelay(r, delay, delay, unit);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
// the pool is shutdown automatically by the ThreadPoolManager
|
||||
schedulePool.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,83 +1,64 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.util.Dnode;
|
||||
|
||||
/**
|
||||
* Holds the orm.xml and ebean-orm.xml deployment information.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class XmlConfig {
|
||||
|
||||
private final List<Dnode> ebeanOrmXml;
|
||||
private final List<Dnode> ormXml;
|
||||
private final List<Dnode> allXml;
|
||||
|
||||
public XmlConfig(List<Dnode> ormXml, List<Dnode> ebeanOrmXml){
|
||||
this.ormXml = ormXml;
|
||||
this.ebeanOrmXml = ebeanOrmXml;
|
||||
this.allXml = new ArrayList<Dnode>(ormXml.size() + ebeanOrmXml.size());
|
||||
allXml.addAll(ormXml);
|
||||
allXml.addAll(ebeanOrmXml);
|
||||
}
|
||||
|
||||
public List<Dnode> getEbeanOrmXml() {
|
||||
return ebeanOrmXml;
|
||||
}
|
||||
|
||||
public List<Dnode> getOrmXml() {
|
||||
return ormXml;
|
||||
}
|
||||
|
||||
public List<Dnode> find(List<Dnode> entityXml, String element) {
|
||||
ArrayList<Dnode> hits = new ArrayList<Dnode>();
|
||||
for (int i = 0; i < entityXml.size(); i++) {
|
||||
hits.addAll(entityXml.get(i).findAll(element, 1));
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the deployment xml for a given entity.
|
||||
* <p>
|
||||
* This searches all the orm.xml and ebean-orm.xml files.
|
||||
* </p>
|
||||
*/
|
||||
public List<Dnode> findEntityXml(String className) {
|
||||
|
||||
ArrayList<Dnode> hits = new ArrayList<Dnode>(2);
|
||||
|
||||
for (Dnode ormXml : allXml) {
|
||||
Dnode entityMappings = ormXml.find("entity-mappings");
|
||||
|
||||
List<Dnode> entities = entityMappings.findAll("entity", "class", className, 1);
|
||||
if (entities.size() == 1) {
|
||||
hits.add(entities.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
return hits;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.util.Dnode;
|
||||
|
||||
/**
|
||||
* Holds the orm.xml and ebean-orm.xml deployment information.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class XmlConfig {
|
||||
|
||||
private final List<Dnode> ebeanOrmXml;
|
||||
private final List<Dnode> ormXml;
|
||||
private final List<Dnode> allXml;
|
||||
|
||||
public XmlConfig(List<Dnode> ormXml, List<Dnode> ebeanOrmXml){
|
||||
this.ormXml = ormXml;
|
||||
this.ebeanOrmXml = ebeanOrmXml;
|
||||
this.allXml = new ArrayList<Dnode>(ormXml.size() + ebeanOrmXml.size());
|
||||
allXml.addAll(ormXml);
|
||||
allXml.addAll(ebeanOrmXml);
|
||||
}
|
||||
|
||||
public List<Dnode> getEbeanOrmXml() {
|
||||
return ebeanOrmXml;
|
||||
}
|
||||
|
||||
public List<Dnode> getOrmXml() {
|
||||
return ormXml;
|
||||
}
|
||||
|
||||
public List<Dnode> find(List<Dnode> entityXml, String element) {
|
||||
ArrayList<Dnode> hits = new ArrayList<Dnode>();
|
||||
for (int i = 0; i < entityXml.size(); i++) {
|
||||
hits.addAll(entityXml.get(i).findAll(element, 1));
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the deployment xml for a given entity.
|
||||
* <p>
|
||||
* This searches all the orm.xml and ebean-orm.xml files.
|
||||
* </p>
|
||||
*/
|
||||
public List<Dnode> findEntityXml(String className) {
|
||||
|
||||
ArrayList<Dnode> hits = new ArrayList<Dnode>(2);
|
||||
|
||||
for (Dnode ormXml : allXml) {
|
||||
Dnode entityMappings = ormXml.find("entity-mappings");
|
||||
|
||||
List<Dnode> entities = entityMappings.findAll("entity", "class", className, 1);
|
||||
if (entities.size() == 1) {
|
||||
hits.add(entities.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
return hits;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,192 +1,173 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.server.lib.util.Dnode;
|
||||
import com.avaje.ebeaninternal.server.lib.util.DnodeReader;
|
||||
import com.avaje.ebeaninternal.server.util.ClassPathReader;
|
||||
import com.avaje.ebeaninternal.server.util.DefaultClassPathReader;
|
||||
|
||||
/**
|
||||
* Used to read the orm.xml and ebean-orm.xml configuration files.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class XmlConfigLoader {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(XmlConfigLoader.class.getName());
|
||||
|
||||
private final ClassPathReader classPathReader;
|
||||
|
||||
private final Object[] classPaths;
|
||||
|
||||
|
||||
public XmlConfigLoader(ClassLoader classLoader){
|
||||
|
||||
if (classLoader == null) {
|
||||
classLoader = getClass().getClassLoader();
|
||||
}
|
||||
|
||||
String cn = GlobalProperties.get("ebean.classpathreader", null);
|
||||
if (cn != null){
|
||||
// use a user defined classPathReader
|
||||
logger.info("Using ["+cn+"] to read the searchable class path");
|
||||
this.classPathReader = (ClassPathReader)ClassUtil.newInstance(cn, this.getClass());
|
||||
} else {
|
||||
this.classPathReader = new DefaultClassPathReader();
|
||||
}
|
||||
|
||||
this.classPaths = classPathReader.readPath(classLoader);
|
||||
}
|
||||
|
||||
public XmlConfig load() {
|
||||
List<Dnode> ormXml = search("META-INF/orm.xml");
|
||||
List<Dnode> ebeanOrmXml = search("META-INF/ebean-orm.xml");
|
||||
|
||||
return new XmlConfig(ormXml, ebeanOrmXml);
|
||||
}
|
||||
|
||||
public List<Dnode> search(String searchFor) {
|
||||
|
||||
ArrayList<Dnode> xmlList = new ArrayList<Dnode>();
|
||||
|
||||
String charsetName = Charset.defaultCharset().name();
|
||||
|
||||
for (int h = 0; h < classPaths.length; h++) {
|
||||
|
||||
try {
|
||||
// for each class path ...
|
||||
File classPath;
|
||||
if (URL.class.isInstance(classPaths[h])) {
|
||||
classPath = new File(((URL) classPaths[h]).getFile());
|
||||
} else {
|
||||
classPath = new File(classPaths[h].toString());
|
||||
}
|
||||
|
||||
// URL Decode the path replacing %20 to space characters.
|
||||
String path = URLDecoder.decode(classPath.getAbsolutePath(), charsetName);
|
||||
|
||||
classPath = new File(path);
|
||||
|
||||
if (classPath.isDirectory()) {
|
||||
checkDir(searchFor, xmlList, classPath);
|
||||
|
||||
} else if (classPath.getName().endsWith(".jar")) {
|
||||
checkJar(searchFor, xmlList, classPath);
|
||||
|
||||
} else {
|
||||
// this is not expected
|
||||
String msg = "Not a Jar or Directory? " + classPath.getAbsolutePath();
|
||||
logger.log(Level.SEVERE, msg);
|
||||
}
|
||||
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return xmlList;
|
||||
|
||||
}
|
||||
|
||||
private void processInputStream(ArrayList<Dnode> xmlList, InputStream is) throws IOException {
|
||||
|
||||
DnodeReader reader = new DnodeReader();
|
||||
Dnode xmlDoc = reader.parseXml(is);
|
||||
is.close();
|
||||
|
||||
xmlList.add(xmlDoc);
|
||||
}
|
||||
|
||||
private void checkFile(String searchFor, ArrayList<Dnode> xmlList, File dir) throws IOException {
|
||||
|
||||
File f = new File(dir, searchFor);
|
||||
if (f.exists()){
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
BufferedInputStream is = new BufferedInputStream(fis);
|
||||
processInputStream(xmlList, is);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDir(String searchFor, ArrayList<Dnode> xmlList, File dir) throws IOException {
|
||||
|
||||
checkFile(searchFor, xmlList, dir);
|
||||
|
||||
if (dir.getPath().endsWith("classes")) {
|
||||
// see if this is part of webapp and look for META-INF/searchFor
|
||||
// relative to the WEB-INF/classes directory
|
||||
File parent = dir.getParentFile();
|
||||
if (parent != null && parent.getPath().endsWith("WEB-INF")){
|
||||
parent = parent.getParentFile();
|
||||
if (parent != null){
|
||||
File metaInf = new File(parent, "META-INF");
|
||||
if (metaInf.exists()){
|
||||
checkFile(searchFor, xmlList, metaInf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkJar(String searchFor, ArrayList<Dnode> xmlList, File classPath) throws IOException {
|
||||
|
||||
String fileName = classPath.getName();
|
||||
if (fileName.toLowerCase().startsWith("surefire")){
|
||||
return;
|
||||
}
|
||||
JarFile module = null;
|
||||
try {
|
||||
module = new JarFile(classPath);
|
||||
ZipEntry entry = module.getEntry(searchFor);
|
||||
if (entry != null){
|
||||
InputStream is = module.getInputStream(entry);
|
||||
processInputStream(xmlList, is);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.info("Unable to check jar file "+fileName+" for ebean-orm.xml");
|
||||
} finally {
|
||||
if (module != null){
|
||||
module.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.server.lib.util.Dnode;
|
||||
import com.avaje.ebeaninternal.server.lib.util.DnodeReader;
|
||||
import com.avaje.ebeaninternal.server.util.ClassPathReader;
|
||||
import com.avaje.ebeaninternal.server.util.DefaultClassPathReader;
|
||||
|
||||
/**
|
||||
* Used to read the orm.xml and ebean-orm.xml configuration files.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class XmlConfigLoader {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(XmlConfigLoader.class.getName());
|
||||
|
||||
private final ClassPathReader classPathReader;
|
||||
|
||||
private final Object[] classPaths;
|
||||
|
||||
|
||||
public XmlConfigLoader(ClassLoader classLoader){
|
||||
|
||||
if (classLoader == null) {
|
||||
classLoader = getClass().getClassLoader();
|
||||
}
|
||||
|
||||
String cn = GlobalProperties.get("ebean.classpathreader", null);
|
||||
if (cn != null){
|
||||
// use a user defined classPathReader
|
||||
logger.info("Using ["+cn+"] to read the searchable class path");
|
||||
this.classPathReader = (ClassPathReader)ClassUtil.newInstance(cn, this.getClass());
|
||||
} else {
|
||||
this.classPathReader = new DefaultClassPathReader();
|
||||
}
|
||||
|
||||
this.classPaths = classPathReader.readPath(classLoader);
|
||||
}
|
||||
|
||||
public XmlConfig load() {
|
||||
List<Dnode> ormXml = search("META-INF/orm.xml");
|
||||
List<Dnode> ebeanOrmXml = search("META-INF/ebean-orm.xml");
|
||||
|
||||
return new XmlConfig(ormXml, ebeanOrmXml);
|
||||
}
|
||||
|
||||
public List<Dnode> search(String searchFor) {
|
||||
|
||||
ArrayList<Dnode> xmlList = new ArrayList<Dnode>();
|
||||
|
||||
String charsetName = Charset.defaultCharset().name();
|
||||
|
||||
for (int h = 0; h < classPaths.length; h++) {
|
||||
|
||||
try {
|
||||
// for each class path ...
|
||||
File classPath;
|
||||
if (URL.class.isInstance(classPaths[h])) {
|
||||
classPath = new File(((URL) classPaths[h]).getFile());
|
||||
} else {
|
||||
classPath = new File(classPaths[h].toString());
|
||||
}
|
||||
|
||||
// URL Decode the path replacing %20 to space characters.
|
||||
String path = URLDecoder.decode(classPath.getAbsolutePath(), charsetName);
|
||||
|
||||
classPath = new File(path);
|
||||
|
||||
if (classPath.isDirectory()) {
|
||||
checkDir(searchFor, xmlList, classPath);
|
||||
|
||||
} else if (classPath.getName().endsWith(".jar")) {
|
||||
checkJar(searchFor, xmlList, classPath);
|
||||
|
||||
} else {
|
||||
// this is not expected
|
||||
String msg = "Not a Jar or Directory? " + classPath.getAbsolutePath();
|
||||
logger.log(Level.SEVERE, msg);
|
||||
}
|
||||
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return xmlList;
|
||||
|
||||
}
|
||||
|
||||
private void processInputStream(ArrayList<Dnode> xmlList, InputStream is) throws IOException {
|
||||
|
||||
DnodeReader reader = new DnodeReader();
|
||||
Dnode xmlDoc = reader.parseXml(is);
|
||||
is.close();
|
||||
|
||||
xmlList.add(xmlDoc);
|
||||
}
|
||||
|
||||
private void checkFile(String searchFor, ArrayList<Dnode> xmlList, File dir) throws IOException {
|
||||
|
||||
File f = new File(dir, searchFor);
|
||||
if (f.exists()){
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
BufferedInputStream is = new BufferedInputStream(fis);
|
||||
processInputStream(xmlList, is);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDir(String searchFor, ArrayList<Dnode> xmlList, File dir) throws IOException {
|
||||
|
||||
checkFile(searchFor, xmlList, dir);
|
||||
|
||||
if (dir.getPath().endsWith("classes")) {
|
||||
// see if this is part of webapp and look for META-INF/searchFor
|
||||
// relative to the WEB-INF/classes directory
|
||||
File parent = dir.getParentFile();
|
||||
if (parent != null && parent.getPath().endsWith("WEB-INF")){
|
||||
parent = parent.getParentFile();
|
||||
if (parent != null){
|
||||
File metaInf = new File(parent, "META-INF");
|
||||
if (metaInf.exists()){
|
||||
checkFile(searchFor, xmlList, metaInf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkJar(String searchFor, ArrayList<Dnode> xmlList, File classPath) throws IOException {
|
||||
|
||||
String fileName = classPath.getName();
|
||||
if (fileName.toLowerCase().startsWith("surefire")){
|
||||
return;
|
||||
}
|
||||
JarFile module = null;
|
||||
try {
|
||||
module = new JarFile(classPath);
|
||||
ZipEntry entry = module.getEntry(searchFor);
|
||||
if (entry != null){
|
||||
InputStream is = module.getInputStream(entry);
|
||||
processInputStream(xmlList, is);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.info("Unable to check jar file "+fileName+" for ebean-orm.xml");
|
||||
} finally {
|
||||
if (module != null){
|
||||
module.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,65 +1,46 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.ddl;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfoVisitor;
|
||||
|
||||
/**
|
||||
* Base BeanVisitor that can help visiting inherited properties.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public abstract class AbstractBeanVisitor implements BeanVisitor {
|
||||
|
||||
/**
|
||||
* Visit all the other inheritance properties that are not on the root.
|
||||
*/
|
||||
public void visitInheritanceProperties(BeanDescriptor<?> descriptor, PropertyVisitor pv) {
|
||||
|
||||
InheritInfo inheritInfo = descriptor.getInheritInfo();
|
||||
if (inheritInfo != null && inheritInfo.isRoot()){
|
||||
// add all properties on the children objects
|
||||
InheritChildVisitor childVisitor = new InheritChildVisitor(pv);
|
||||
inheritInfo.visitChildren(childVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper used to visit all the inheritInfo/BeanDescriptor in
|
||||
* the inheritance hierarchy (to add their 'local' properties).
|
||||
*/
|
||||
protected static class InheritChildVisitor implements InheritInfoVisitor {
|
||||
|
||||
final PropertyVisitor pv;
|
||||
|
||||
protected InheritChildVisitor(PropertyVisitor pv) {
|
||||
this.pv = pv;
|
||||
}
|
||||
|
||||
public void visit(InheritInfo inheritInfo) {
|
||||
BeanProperty[] propertiesLocal = inheritInfo.getBeanDescriptor().propertiesLocal();
|
||||
VisitorUtil.visit(propertiesLocal, pv);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.ddl;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfoVisitor;
|
||||
|
||||
/**
|
||||
* Base BeanVisitor that can help visiting inherited properties.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public abstract class AbstractBeanVisitor implements BeanVisitor {
|
||||
|
||||
/**
|
||||
* Visit all the other inheritance properties that are not on the root.
|
||||
*/
|
||||
public void visitInheritanceProperties(BeanDescriptor<?> descriptor, PropertyVisitor pv) {
|
||||
|
||||
InheritInfo inheritInfo = descriptor.getInheritInfo();
|
||||
if (inheritInfo != null && inheritInfo.isRoot()){
|
||||
// add all properties on the children objects
|
||||
InheritChildVisitor childVisitor = new InheritChildVisitor(pv);
|
||||
inheritInfo.visitChildren(childVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper used to visit all the inheritInfo/BeanDescriptor in
|
||||
* the inheritance hierarchy (to add their 'local' properties).
|
||||
*/
|
||||
protected static class InheritChildVisitor implements InheritInfoVisitor {
|
||||
|
||||
final PropertyVisitor pv;
|
||||
|
||||
protected InheritChildVisitor(PropertyVisitor pv) {
|
||||
this.pv = pv;
|
||||
}
|
||||
|
||||
public void visit(InheritInfo inheritInfo) {
|
||||
BeanProperty[] propertiesLocal = inheritInfo.getBeanDescriptor().propertiesLocal();
|
||||
VisitorUtil.visit(propertiesLocal, pv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,259 +1,252 @@
|
||||
/**
|
||||
* Imilia Interactive Mobile Applications GmbH
|
||||
* Copyright (c) 2009 - all rights reserved
|
||||
*
|
||||
* Created on: Jun 29, 2009
|
||||
* Created by: emcgreal
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.ddl;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DbDdlSyntax;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
/**
|
||||
* The context used during DDL generation.
|
||||
*/
|
||||
public class DdlGenContext {
|
||||
|
||||
private final StringWriter stringWriter = new StringWriter();
|
||||
|
||||
/**
|
||||
* Used to map bean types to DB specific types.
|
||||
*/
|
||||
private final DbTypeMap dbTypeMap;
|
||||
|
||||
/**
|
||||
* Handles DB specific DDL syntax.
|
||||
*/
|
||||
private final DbDdlSyntax ddlSyntax;
|
||||
|
||||
/**
|
||||
* The new line character that is used.
|
||||
*/
|
||||
private final String newLine;
|
||||
|
||||
/**
|
||||
* Last content written (used with removeLast())
|
||||
*/
|
||||
private final List<String> contentBuffer = new ArrayList<String>();
|
||||
|
||||
private Set<String> intersectionTables = new HashSet<String>();
|
||||
|
||||
private List<String> intersectionTablesCreateDdl = new ArrayList<String>();
|
||||
private List<String> intersectionTablesFkDdl = new ArrayList<String>();
|
||||
|
||||
private final DatabasePlatform dbPlatform;
|
||||
|
||||
/** The Naming convention used to define FK an IX names */
|
||||
private final NamingConvention namingConvention;
|
||||
|
||||
/** The global fk count used to keep FK names unique */
|
||||
private int fkCount;
|
||||
|
||||
/** The ix count. */
|
||||
private int ixCount;
|
||||
|
||||
public DdlGenContext(DatabasePlatform dbPlatform, NamingConvention namingConvention){
|
||||
this.dbPlatform = dbPlatform;
|
||||
this.dbTypeMap = dbPlatform.getDbTypeMap();
|
||||
this.ddlSyntax = dbPlatform.getDbDdlSyntax();
|
||||
this.newLine = ddlSyntax.getNewLine();
|
||||
this.namingConvention = namingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the dbPlatform.
|
||||
*/
|
||||
public DatabasePlatform getDbPlatform() {
|
||||
return dbPlatform;
|
||||
}
|
||||
|
||||
public boolean isProcessIntersectionTable(String tableName){
|
||||
return intersectionTables.add(tableName);
|
||||
}
|
||||
|
||||
public void addCreateIntersectionTable(String createTableDdl){
|
||||
intersectionTablesCreateDdl.add(createTableDdl);
|
||||
}
|
||||
|
||||
public void addIntersectionTableFk(String intTableFk){
|
||||
intersectionTablesFkDdl.add(intTableFk);
|
||||
}
|
||||
|
||||
public void addIntersectionCreateTables() {
|
||||
for (String intTableCreate : intersectionTablesCreateDdl) {
|
||||
write(newLine);
|
||||
write(intTableCreate);
|
||||
}
|
||||
}
|
||||
|
||||
public void addIntersectionFkeys() {
|
||||
write(newLine);
|
||||
write(newLine);
|
||||
for (String intTableFk : intersectionTablesFkDdl) {
|
||||
write(newLine);
|
||||
write(intTableFk);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generated content (DDL script).
|
||||
*/
|
||||
public String getContent(){
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the map used to determine the DB specific type
|
||||
* for a given bean property.
|
||||
*/
|
||||
public DbTypeMap getDbTypeMap() {
|
||||
return dbTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return object to handle DB specific DDL syntax.
|
||||
*/
|
||||
public DbDdlSyntax getDdlSyntax() {
|
||||
return ddlSyntax;
|
||||
}
|
||||
|
||||
public String getColumnDefn(BeanProperty p) {
|
||||
DbType dbType = getDbType(p);
|
||||
return p.renderDbType(dbType);
|
||||
}
|
||||
|
||||
private DbType getDbType(BeanProperty p) {
|
||||
|
||||
ScalarType<?> scalarType = p.getScalarType();
|
||||
if (scalarType == null) {
|
||||
throw new RuntimeException("No scalarType for " + p.getFullBeanName());
|
||||
}
|
||||
|
||||
if (p.isDbEncrypted()){
|
||||
return dbTypeMap.get(p.getDbEncryptedType());
|
||||
}
|
||||
|
||||
int jdbcType = scalarType.getJdbcType();
|
||||
if (p.isLob() && jdbcType == Types.VARCHAR){
|
||||
// workaround for Postgres TEXT type which is
|
||||
// VARCHAR in jdbc API but TEXT in ddl
|
||||
jdbcType = Types.CLOB;
|
||||
}
|
||||
return dbTypeMap.get(jdbcType);
|
||||
}
|
||||
/**
|
||||
* Write content to the buffer.
|
||||
*/
|
||||
public DdlGenContext write(String content, int minWidth){
|
||||
|
||||
content = pad(content, minWidth);
|
||||
|
||||
contentBuffer.add(content);
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write content to the buffer.
|
||||
*/
|
||||
public DdlGenContext write(String content){
|
||||
return write(content, 0);
|
||||
}
|
||||
|
||||
public DdlGenContext writeNewLine() {
|
||||
write(newLine);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the last content that was written.
|
||||
*/
|
||||
public DdlGenContext removeLast() {
|
||||
if (!contentBuffer.isEmpty()){
|
||||
contentBuffer.remove(contentBuffer.size()-1);
|
||||
} else {
|
||||
throw new RuntimeException("No lastContent to remove?");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the content to the buffer.
|
||||
*/
|
||||
public DdlGenContext flush() {
|
||||
if (!contentBuffer.isEmpty()){
|
||||
for (String s:contentBuffer){
|
||||
|
||||
if (s != null){
|
||||
stringWriter.write(s);
|
||||
}
|
||||
}
|
||||
contentBuffer.clear();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private String padding(int length){
|
||||
|
||||
StringBuffer sb = new StringBuffer(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
sb.append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String pad(String content, int minWidth){
|
||||
if (minWidth > 0 && content.length() < minWidth){
|
||||
int padding = minWidth - content.length();
|
||||
return content + padding(padding);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the namingConvention
|
||||
*/
|
||||
public NamingConvention getNamingConvention() {
|
||||
return namingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the incremented fkCount
|
||||
*/
|
||||
public int incrementFkCount() {
|
||||
return ++fkCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the incremented ixCount
|
||||
*/
|
||||
public int incrementIxCount() {
|
||||
return ++ixCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips off the Database Platform specific quoted identifier characters.
|
||||
*/
|
||||
public String removeQuotes(String dbColumn) {
|
||||
|
||||
dbColumn = StringHelper.replaceString(dbColumn, dbPlatform.getOpenQuote(), "");
|
||||
dbColumn = StringHelper.replaceString(dbColumn, dbPlatform.getCloseQuote(), "");
|
||||
|
||||
return dbColumn;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.ddl;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DbDdlSyntax;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
/**
|
||||
* The context used during DDL generation.
|
||||
*/
|
||||
public class DdlGenContext {
|
||||
|
||||
private final StringWriter stringWriter = new StringWriter();
|
||||
|
||||
/**
|
||||
* Used to map bean types to DB specific types.
|
||||
*/
|
||||
private final DbTypeMap dbTypeMap;
|
||||
|
||||
/**
|
||||
* Handles DB specific DDL syntax.
|
||||
*/
|
||||
private final DbDdlSyntax ddlSyntax;
|
||||
|
||||
/**
|
||||
* The new line character that is used.
|
||||
*/
|
||||
private final String newLine;
|
||||
|
||||
/**
|
||||
* Last content written (used with removeLast())
|
||||
*/
|
||||
private final List<String> contentBuffer = new ArrayList<String>();
|
||||
|
||||
private Set<String> intersectionTables = new HashSet<String>();
|
||||
|
||||
private List<String> intersectionTablesCreateDdl = new ArrayList<String>();
|
||||
private List<String> intersectionTablesFkDdl = new ArrayList<String>();
|
||||
|
||||
private final DatabasePlatform dbPlatform;
|
||||
|
||||
/** The Naming convention used to define FK an IX names */
|
||||
private final NamingConvention namingConvention;
|
||||
|
||||
/** The global fk count used to keep FK names unique */
|
||||
private int fkCount;
|
||||
|
||||
/** The ix count. */
|
||||
private int ixCount;
|
||||
|
||||
public DdlGenContext(DatabasePlatform dbPlatform, NamingConvention namingConvention){
|
||||
this.dbPlatform = dbPlatform;
|
||||
this.dbTypeMap = dbPlatform.getDbTypeMap();
|
||||
this.ddlSyntax = dbPlatform.getDbDdlSyntax();
|
||||
this.newLine = ddlSyntax.getNewLine();
|
||||
this.namingConvention = namingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the dbPlatform.
|
||||
*/
|
||||
public DatabasePlatform getDbPlatform() {
|
||||
return dbPlatform;
|
||||
}
|
||||
|
||||
public boolean isProcessIntersectionTable(String tableName){
|
||||
return intersectionTables.add(tableName);
|
||||
}
|
||||
|
||||
public void addCreateIntersectionTable(String createTableDdl){
|
||||
intersectionTablesCreateDdl.add(createTableDdl);
|
||||
}
|
||||
|
||||
public void addIntersectionTableFk(String intTableFk){
|
||||
intersectionTablesFkDdl.add(intTableFk);
|
||||
}
|
||||
|
||||
public void addIntersectionCreateTables() {
|
||||
for (String intTableCreate : intersectionTablesCreateDdl) {
|
||||
write(newLine);
|
||||
write(intTableCreate);
|
||||
}
|
||||
}
|
||||
|
||||
public void addIntersectionFkeys() {
|
||||
write(newLine);
|
||||
write(newLine);
|
||||
for (String intTableFk : intersectionTablesFkDdl) {
|
||||
write(newLine);
|
||||
write(intTableFk);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generated content (DDL script).
|
||||
*/
|
||||
public String getContent(){
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the map used to determine the DB specific type
|
||||
* for a given bean property.
|
||||
*/
|
||||
public DbTypeMap getDbTypeMap() {
|
||||
return dbTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return object to handle DB specific DDL syntax.
|
||||
*/
|
||||
public DbDdlSyntax getDdlSyntax() {
|
||||
return ddlSyntax;
|
||||
}
|
||||
|
||||
public String getColumnDefn(BeanProperty p) {
|
||||
DbType dbType = getDbType(p);
|
||||
return p.renderDbType(dbType);
|
||||
}
|
||||
|
||||
private DbType getDbType(BeanProperty p) {
|
||||
|
||||
ScalarType<?> scalarType = p.getScalarType();
|
||||
if (scalarType == null) {
|
||||
throw new RuntimeException("No scalarType for " + p.getFullBeanName());
|
||||
}
|
||||
|
||||
if (p.isDbEncrypted()){
|
||||
return dbTypeMap.get(p.getDbEncryptedType());
|
||||
}
|
||||
|
||||
int jdbcType = scalarType.getJdbcType();
|
||||
if (p.isLob() && jdbcType == Types.VARCHAR){
|
||||
// workaround for Postgres TEXT type which is
|
||||
// VARCHAR in jdbc API but TEXT in ddl
|
||||
jdbcType = Types.CLOB;
|
||||
}
|
||||
return dbTypeMap.get(jdbcType);
|
||||
}
|
||||
/**
|
||||
* Write content to the buffer.
|
||||
*/
|
||||
public DdlGenContext write(String content, int minWidth){
|
||||
|
||||
content = pad(content, minWidth);
|
||||
|
||||
contentBuffer.add(content);
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write content to the buffer.
|
||||
*/
|
||||
public DdlGenContext write(String content){
|
||||
return write(content, 0);
|
||||
}
|
||||
|
||||
public DdlGenContext writeNewLine() {
|
||||
write(newLine);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the last content that was written.
|
||||
*/
|
||||
public DdlGenContext removeLast() {
|
||||
if (!contentBuffer.isEmpty()){
|
||||
contentBuffer.remove(contentBuffer.size()-1);
|
||||
} else {
|
||||
throw new RuntimeException("No lastContent to remove?");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the content to the buffer.
|
||||
*/
|
||||
public DdlGenContext flush() {
|
||||
if (!contentBuffer.isEmpty()){
|
||||
for (String s:contentBuffer){
|
||||
|
||||
if (s != null){
|
||||
stringWriter.write(s);
|
||||
}
|
||||
}
|
||||
contentBuffer.clear();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private String padding(int length){
|
||||
|
||||
StringBuffer sb = new StringBuffer(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
sb.append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String pad(String content, int minWidth){
|
||||
if (minWidth > 0 && content.length() < minWidth){
|
||||
int padding = minWidth - content.length();
|
||||
return content + padding(padding);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the namingConvention
|
||||
*/
|
||||
public NamingConvention getNamingConvention() {
|
||||
return namingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the incremented fkCount
|
||||
*/
|
||||
public int incrementFkCount() {
|
||||
return ++fkCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the incremented ixCount
|
||||
*/
|
||||
public int incrementIxCount() {
|
||||
return ++ixCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips off the Database Platform specific quoted identifier characters.
|
||||
*/
|
||||
public String removeQuotes(String dbColumn) {
|
||||
|
||||
dbColumn = StringHelper.replaceString(dbColumn, dbPlatform.getOpenQuote(), "");
|
||||
dbColumn = StringHelper.replaceString(dbColumn, dbPlatform.getCloseQuote(), "");
|
||||
|
||||
return dbColumn;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
/**
|
||||
* DDL generation.
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.ddl;
|
||||
@@ -1,141 +1,122 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean 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.
|
||||
*
|
||||
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
|
||||
/**
|
||||
* Persist info for determining if save or delete should be performed.
|
||||
* <p>
|
||||
* This is set to associated Beans, Table joins and List.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanCascadeInfo {
|
||||
|
||||
/**
|
||||
* should delete cascade.
|
||||
*/
|
||||
boolean delete;
|
||||
|
||||
/**
|
||||
* Should save cascade.
|
||||
*/
|
||||
boolean save;
|
||||
|
||||
/**
|
||||
* Should validate cascade.
|
||||
*/
|
||||
boolean validate;
|
||||
|
||||
/**
|
||||
* Set the raw deployment attribute.
|
||||
*/
|
||||
public void setAttribute(String attr) {
|
||||
if (attr == null){
|
||||
return;
|
||||
}
|
||||
attr = attr.toLowerCase();
|
||||
delete = (attr.indexOf("delete")>-1);
|
||||
if (!delete){
|
||||
// same as EJB3 remove
|
||||
delete = (attr.indexOf("remove")>-1);
|
||||
}
|
||||
save = (attr.indexOf("save")>-1);
|
||||
if (!save){
|
||||
// same as EJB3 persist
|
||||
save = (attr.indexOf("persist")>-1);
|
||||
}
|
||||
if (attr.indexOf("validate")>-1){
|
||||
validate = true;
|
||||
}
|
||||
|
||||
if (attr.indexOf("all")>-1){
|
||||
delete = true;
|
||||
save = true;
|
||||
validate = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTypes(CascadeType[] types) {
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
setType(types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void setType(CascadeType type) {
|
||||
if (type.equals(CascadeType.ALL)){
|
||||
save = true;
|
||||
delete = true;
|
||||
}
|
||||
if (type.equals(CascadeType.REMOVE)){
|
||||
delete = true;
|
||||
}
|
||||
if (type.equals(CascadeType.PERSIST)){
|
||||
save = true;
|
||||
}
|
||||
if (type.equals(CascadeType.MERGE)){
|
||||
save = true;
|
||||
}
|
||||
if (save || delete){
|
||||
validate = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if delete should cascade.
|
||||
*/
|
||||
public boolean isDelete() {
|
||||
return delete;
|
||||
}
|
||||
/**
|
||||
* Set to true if delete should cascade.
|
||||
*/
|
||||
public void setDelete(boolean isDelete) {
|
||||
this.delete = isDelete;
|
||||
}
|
||||
/**
|
||||
* Return true if save should cascade.
|
||||
*/
|
||||
public boolean isSave() {
|
||||
return save;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if save should cascade.
|
||||
*/
|
||||
public void setSave(boolean isUpdate) {
|
||||
this.save = isUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if validate should be cascaded.
|
||||
*/
|
||||
public boolean isValidate() {
|
||||
return validate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set validate to cascade or not.
|
||||
*/
|
||||
public void setValidate(boolean isValidate) {
|
||||
this.validate = isValidate;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
|
||||
/**
|
||||
* Persist info for determining if save or delete should be performed.
|
||||
* <p>
|
||||
* This is set to associated Beans, Table joins and List.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanCascadeInfo {
|
||||
|
||||
/**
|
||||
* should delete cascade.
|
||||
*/
|
||||
boolean delete;
|
||||
|
||||
/**
|
||||
* Should save cascade.
|
||||
*/
|
||||
boolean save;
|
||||
|
||||
/**
|
||||
* Should validate cascade.
|
||||
*/
|
||||
boolean validate;
|
||||
|
||||
/**
|
||||
* Set the raw deployment attribute.
|
||||
*/
|
||||
public void setAttribute(String attr) {
|
||||
if (attr == null){
|
||||
return;
|
||||
}
|
||||
attr = attr.toLowerCase();
|
||||
delete = (attr.indexOf("delete")>-1);
|
||||
if (!delete){
|
||||
// same as EJB3 remove
|
||||
delete = (attr.indexOf("remove")>-1);
|
||||
}
|
||||
save = (attr.indexOf("save")>-1);
|
||||
if (!save){
|
||||
// same as EJB3 persist
|
||||
save = (attr.indexOf("persist")>-1);
|
||||
}
|
||||
if (attr.indexOf("validate")>-1){
|
||||
validate = true;
|
||||
}
|
||||
|
||||
if (attr.indexOf("all")>-1){
|
||||
delete = true;
|
||||
save = true;
|
||||
validate = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTypes(CascadeType[] types) {
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
setType(types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void setType(CascadeType type) {
|
||||
if (type.equals(CascadeType.ALL)){
|
||||
save = true;
|
||||
delete = true;
|
||||
}
|
||||
if (type.equals(CascadeType.REMOVE)){
|
||||
delete = true;
|
||||
}
|
||||
if (type.equals(CascadeType.PERSIST)){
|
||||
save = true;
|
||||
}
|
||||
if (type.equals(CascadeType.MERGE)){
|
||||
save = true;
|
||||
}
|
||||
if (save || delete){
|
||||
validate = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if delete should cascade.
|
||||
*/
|
||||
public boolean isDelete() {
|
||||
return delete;
|
||||
}
|
||||
/**
|
||||
* Set to true if delete should cascade.
|
||||
*/
|
||||
public void setDelete(boolean isDelete) {
|
||||
this.delete = isDelete;
|
||||
}
|
||||
/**
|
||||
* Return true if save should cascade.
|
||||
*/
|
||||
public boolean isSave() {
|
||||
return save;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if save should cascade.
|
||||
*/
|
||||
public void setSave(boolean isUpdate) {
|
||||
this.save = isUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if validate should be cascaded.
|
||||
*/
|
||||
public boolean isValidate() {
|
||||
return validate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set validate to cascade or not.
|
||||
*/
|
||||
public void setValidate(boolean isValidate) {
|
||||
this.validate = isValidate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+1547
-1566
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user