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,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
@@ -1,56 +1,37 @@
|
||||
/**
|
||||
* 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 com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.EncryptKey;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
|
||||
/**
|
||||
* Provides a method to find a BeanDescriptor.
|
||||
* <p>
|
||||
* Used during deployment of to resolve relationships between beans.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanDescriptorMap {
|
||||
|
||||
/**
|
||||
* Return the name of the server/database.
|
||||
*/
|
||||
public String getServerName();
|
||||
|
||||
/**
|
||||
* Return the Cache Manager.
|
||||
*/
|
||||
public ServerCacheManager getCacheManager();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for a given class.
|
||||
*/
|
||||
public <T> BeanDescriptor<T> getBeanDescriptor(Class<T> entityType);
|
||||
|
||||
/**
|
||||
* Return the Encrypt key given the table and column name.
|
||||
*/
|
||||
public EncryptKey getEncryptKey(String tableName, String columnName);
|
||||
|
||||
public IdBinder createIdBinder(BeanProperty[] uids);
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.EncryptKey;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
|
||||
/**
|
||||
* Provides a method to find a BeanDescriptor.
|
||||
* <p>
|
||||
* Used during deployment of to resolve relationships between beans.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanDescriptorMap {
|
||||
|
||||
/**
|
||||
* Return the name of the server/database.
|
||||
*/
|
||||
public String getServerName();
|
||||
|
||||
/**
|
||||
* Return the Cache Manager.
|
||||
*/
|
||||
public ServerCacheManager getCacheManager();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for a given class.
|
||||
*/
|
||||
public <T> BeanDescriptor<T> getBeanDescriptor(Class<T> entityType);
|
||||
|
||||
/**
|
||||
* Return the Encrypt key given the table and column name.
|
||||
*/
|
||||
public EncryptKey getEncryptKey(String tableName, String columnName);
|
||||
|
||||
public IdBinder createIdBinder(BeanProperty[] uids);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,50 +1,31 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
public class BeanEmbeddedMeta {
|
||||
|
||||
|
||||
final BeanProperty[] properties;
|
||||
|
||||
public BeanEmbeddedMeta(BeanProperty[] properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties with over ridden mapping information.
|
||||
*/
|
||||
public BeanProperty[] getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if at least one property is a version property.
|
||||
*/
|
||||
public boolean isEmbeddedVersion() {
|
||||
for (int i = 0; i < properties.length; i++) {
|
||||
if (properties[i].isVersion()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
public class BeanEmbeddedMeta {
|
||||
|
||||
|
||||
final BeanProperty[] properties;
|
||||
|
||||
public BeanEmbeddedMeta(BeanProperty[] properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties with over ridden mapping information.
|
||||
*/
|
||||
public BeanProperty[] getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if at least one property is a version property.
|
||||
*/
|
||||
public boolean isEmbeddedVersion() {
|
||||
for (int i = 0; i < properties.length; i++) {
|
||||
if (properties[i].isVersion()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,72 +1,53 @@
|
||||
/**
|
||||
* 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 java.util.Map;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Creates BeanProperties for Embedded beans that have deployment information
|
||||
* such as the actual DB column name and table alias.
|
||||
*/
|
||||
public class BeanEmbeddedMetaFactory {
|
||||
|
||||
/**
|
||||
* Create BeanProperties for embedded beans using the deployment specific DB column name and table alias.
|
||||
*/
|
||||
public static BeanEmbeddedMeta create(BeanDescriptorMap owner, DeployBeanPropertyAssocOne<?> prop,
|
||||
BeanDescriptor<?> descriptor) {
|
||||
|
||||
// we can get a BeanDescriptor for an Embedded bean
|
||||
// and know that it is NOT recursive, as Embedded beans are
|
||||
// only allow to hold simple scalar types...
|
||||
BeanDescriptor<?> targetDesc = owner.getBeanDescriptor(prop.getTargetType());
|
||||
if (targetDesc == null){
|
||||
String msg = "Could not find BeanDescriptor for "+prop.getTargetType()
|
||||
+". Perhaps the EmbeddedId class is not registered?";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
|
||||
// deployment override information (column names)
|
||||
Map<String, String> propColMap = prop.getDeployEmbedded().getPropertyColumnMap();
|
||||
|
||||
BeanProperty[] sourceProperties = targetDesc.propertiesBaseScalar();
|
||||
|
||||
BeanProperty[] embeddedProperties = new BeanProperty[sourceProperties.length];
|
||||
|
||||
for (int i = 0; i < sourceProperties.length; i++) {
|
||||
|
||||
String propertyName = sourceProperties[i].getName();
|
||||
String dbColumn = propColMap.get(propertyName);
|
||||
if (dbColumn == null) {
|
||||
// dbColumn not overridden so take original
|
||||
dbColumn = sourceProperties[i].getDbColumn();
|
||||
}
|
||||
|
||||
BeanPropertyOverride overrides = new BeanPropertyOverride(dbColumn);
|
||||
embeddedProperties[i] = new BeanProperty(sourceProperties[i], overrides);
|
||||
}
|
||||
|
||||
return new BeanEmbeddedMeta(embeddedProperties);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Creates BeanProperties for Embedded beans that have deployment information
|
||||
* such as the actual DB column name and table alias.
|
||||
*/
|
||||
public class BeanEmbeddedMetaFactory {
|
||||
|
||||
/**
|
||||
* Create BeanProperties for embedded beans using the deployment specific DB column name and table alias.
|
||||
*/
|
||||
public static BeanEmbeddedMeta create(BeanDescriptorMap owner, DeployBeanPropertyAssocOne<?> prop,
|
||||
BeanDescriptor<?> descriptor) {
|
||||
|
||||
// we can get a BeanDescriptor for an Embedded bean
|
||||
// and know that it is NOT recursive, as Embedded beans are
|
||||
// only allow to hold simple scalar types...
|
||||
BeanDescriptor<?> targetDesc = owner.getBeanDescriptor(prop.getTargetType());
|
||||
if (targetDesc == null){
|
||||
String msg = "Could not find BeanDescriptor for "+prop.getTargetType()
|
||||
+". Perhaps the EmbeddedId class is not registered?";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
|
||||
// deployment override information (column names)
|
||||
Map<String, String> propColMap = prop.getDeployEmbedded().getPropertyColumnMap();
|
||||
|
||||
BeanProperty[] sourceProperties = targetDesc.propertiesBaseScalar();
|
||||
|
||||
BeanProperty[] embeddedProperties = new BeanProperty[sourceProperties.length];
|
||||
|
||||
for (int i = 0; i < sourceProperties.length; i++) {
|
||||
|
||||
String propertyName = sourceProperties[i].getName();
|
||||
String dbColumn = propColMap.get(propertyName);
|
||||
if (dbColumn == null) {
|
||||
// dbColumn not overridden so take original
|
||||
dbColumn = sourceProperties[i].getDbColumn();
|
||||
}
|
||||
|
||||
BeanPropertyOverride overrides = new BeanPropertyOverride(dbColumn);
|
||||
embeddedProperties[i] = new BeanProperty(sourceProperties[i], overrides);
|
||||
}
|
||||
|
||||
return new BeanEmbeddedMeta(embeddedProperties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +1,26 @@
|
||||
/**
|
||||
* 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 java.util.List;
|
||||
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
|
||||
/**
|
||||
* Factory for controlling the construction of BeanFinders.
|
||||
*/
|
||||
public interface BeanFinderManager {
|
||||
|
||||
/**
|
||||
* Return the number of beans with a registered finder.
|
||||
*/
|
||||
public int getRegisterCount();
|
||||
|
||||
/**
|
||||
* Create the appropriate BeanController.
|
||||
*/
|
||||
public int createBeanFinders(List<Class<?>> finderClassList);
|
||||
|
||||
/**
|
||||
* Return the BeanController for a given entity type.
|
||||
*/
|
||||
public <T> BeanFinder<T> getBeanFinder(Class<T> entityType);
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
|
||||
/**
|
||||
* Factory for controlling the construction of BeanFinders.
|
||||
*/
|
||||
public interface BeanFinderManager {
|
||||
|
||||
/**
|
||||
* Return the number of beans with a registered finder.
|
||||
*/
|
||||
public int getRegisterCount();
|
||||
|
||||
/**
|
||||
* Create the appropriate BeanController.
|
||||
*/
|
||||
public int createBeanFinders(List<Class<?>> finderClassList);
|
||||
|
||||
/**
|
||||
* Return the BeanController for a given entity type.
|
||||
*/
|
||||
public <T> BeanFinder<T> getBeanFinder(Class<T> entityType);
|
||||
}
|
||||
|
||||
@@ -1,75 +1,56 @@
|
||||
/**
|
||||
* 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 com.avaje.ebeaninternal.server.core.InternString;
|
||||
|
||||
/**
|
||||
* Represents a database foreign key which can map to an object relationship.
|
||||
*/
|
||||
public class BeanForeignKey {
|
||||
|
||||
private final String dbColumn;
|
||||
|
||||
private final int dbType;
|
||||
|
||||
/**
|
||||
* Construct the BeanForeignKey.
|
||||
*/
|
||||
public BeanForeignKey(String dbColumn, int dbType) {
|
||||
this.dbColumn = InternString.intern(dbColumn);
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database column.
|
||||
*/
|
||||
public String getDbColumn() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JDBC datatype of the database column.
|
||||
*/
|
||||
public int getDbType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj instanceof BeanForeignKey) {
|
||||
return obj.hashCode() == hashCode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = getClass().hashCode();
|
||||
hc = hc * 31 + (dbColumn != null ? dbColumn.hashCode() : 0);
|
||||
return hc;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
|
||||
/**
|
||||
* Represents a database foreign key which can map to an object relationship.
|
||||
*/
|
||||
public class BeanForeignKey {
|
||||
|
||||
private final String dbColumn;
|
||||
|
||||
private final int dbType;
|
||||
|
||||
/**
|
||||
* Construct the BeanForeignKey.
|
||||
*/
|
||||
public BeanForeignKey(String dbColumn, int dbType) {
|
||||
this.dbColumn = InternString.intern(dbColumn);
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database column.
|
||||
*/
|
||||
public String getDbColumn() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JDBC datatype of the database column.
|
||||
*/
|
||||
public int getDbType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj instanceof BeanForeignKey) {
|
||||
return obj.hashCode() == hashCode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = getClass().hashCode();
|
||||
hc = hc * 31 + (dbColumn != null ? dbColumn.hashCode() : 0);
|
||||
return hc;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user