Liran Zelkha has uploaded a new change for review. Change subject: core: support materialized views in Java ......................................................................
core: support materialized views in Java Add update listeners to any Dao implementation, and a MaterializedView listener that can call relevant materialized views stored procedures to recreate them. Change-Id: I745e934fde341bd1264e5e5fedaf59fc64ad4ad8 Signed-off-by: [email protected] <[email protected]> --- M backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/DbFacade.java A backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MaterializedView.java A backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MatrializedViewListener.java A backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/DaoDynamicWrapper.java A backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/UpdateListener.java A backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/UpdateMethod.java M backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/DaoFactory.java A backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MatrializedViewListenerTest.java 8 files changed, 170 insertions(+), 2 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/05/16305/1 diff --git a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/DbFacade.java b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/DbFacade.java index 5e09d79..80c6fb7 100644 --- a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/DbFacade.java +++ b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/DbFacade.java @@ -41,6 +41,7 @@ import org.ovirt.engine.core.common.businessentities.network.VmNetworkInterface; import org.ovirt.engine.core.common.businessentities.network.VmNetworkStatistics; import org.ovirt.engine.core.compat.Guid; +import org.ovirt.engine.core.dal.dbbroker.updateListeners.UpdateListener; import org.ovirt.engine.core.dao.ActionGroupDAO; import org.ovirt.engine.core.dao.AdGroupDAO; import org.ovirt.engine.core.dao.AsyncTaskDAO; @@ -164,6 +165,8 @@ private int onStartConnectionTimeout; private int connectionCheckInterval; + + private List<UpdateListener> updateListeners = new ArrayList<>(); public void setDbEngineDialect(DbEngineDialect dbEngineDialect) { this.dbEngineDialect = dbEngineDialect; @@ -963,4 +966,22 @@ public VmGuestAgentInterfaceDao getVmGuestAgentInterfaceDao() { return getDao(VmGuestAgentInterfaceDao.class); } + + public void informUpdate(DAO originatingDao, String method, Object[] args) { + // TODO: Implement a queue + // TODO: Run all in seperate thread + // TODO: Eliminate queue duplicates + + for (UpdateListener listener : updateListeners) { + listener.updateOccured(originatingDao, method, args); + } + } + + public void registerListener(UpdateListener listener) { + updateListeners.add(listener); + } + + public void removeListener(UpdateListener listener) { + updateListeners.remove(listener); + } } diff --git a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MaterializedView.java b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MaterializedView.java new file mode 100644 index 0000000..2c7f512 --- /dev/null +++ b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MaterializedView.java @@ -0,0 +1,16 @@ +package org.ovirt.engine.core.dal.dbbroker.materializedviews; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation is used to mark Dao's that are based on Materialized Views + * @author lzelkha + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface MaterializedView { + +} diff --git a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MatrializedViewListener.java b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MatrializedViewListener.java new file mode 100644 index 0000000..1d088be --- /dev/null +++ b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MatrializedViewListener.java @@ -0,0 +1,51 @@ +package org.ovirt.engine.core.dal.dbbroker.materializedviews; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +import org.ovirt.engine.core.dal.dbbroker.updateListeners.UpdateListener; +import org.ovirt.engine.core.dao.DAO; +import org.ovirt.engine.core.utils.log.Log; +import org.ovirt.engine.core.utils.log.LogFactory; + +public class MatrializedViewListener implements UpdateListener { + private static final Log log = LogFactory.getLog(MatrializedViewListener.class); + + public MatrializedViewListener() { + } + + @Override + public void updateOccured(DAO dao, String methodName, Object[] args) { + if (dao == null || !dao.getClass().isAnnotationPresent(MaterializedView.class)) { + return; + } + + String entityName = null; + + for (Class<?> clz : dao.getClass().getInterfaces()) { + + if (DAO.class.isAssignableFrom(clz)) { + for (Type t : clz.getGenericInterfaces()) { + if (t instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) t; + if (pt.getActualTypeArguments().length > 0) { + Type actualParameter = pt.getActualTypeArguments()[0]; + if (actualParameter instanceof Class) { + Class<?> entityClass = (Class<?>) actualParameter; + entityName = entityClass.getSimpleName(); + } + } + } + } + } + } + + if (entityName == null) { + log.error("MaterializedViewListener could not discover activated entity for DAO " + dao + + " . Data inconsistency might occur."); + } else { + System.out.println(entityName); + // DbFacade.getInstance().getCallsHandler().executeModification("test", null); + } + } +} diff --git a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/DaoDynamicWrapper.java b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/DaoDynamicWrapper.java new file mode 100644 index 0000000..65161ea --- /dev/null +++ b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/DaoDynamicWrapper.java @@ -0,0 +1,35 @@ +package org.ovirt.engine.core.dal.dbbroker.updateListeners; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +import org.ovirt.engine.core.dal.dbbroker.DbFacade; +import org.ovirt.engine.core.dal.dbbroker.materializedviews.MaterializedView; +import org.ovirt.engine.core.dao.DAO; + +/** + * This dynamic proxy is used to inform update listeners on update methods called on entities + * @author lzelkha + */ +public class DaoDynamicWrapper<T extends DAO> implements InvocationHandler { + + private T originalDao; + + public DaoDynamicWrapper(T originalDao) { + this.originalDao = originalDao; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (proxy != null && proxy instanceof DAO) { + if (proxy.getClass().isAnnotationPresent(MaterializedView.class)) { + if (method.getName().startsWith("update") || method.getName().startsWith("save") + || method.isAnnotationPresent(UpdateMethod.class)) { + DbFacade.getInstance().informUpdate((DAO) proxy, method.getName(), args); + } + } + } + return method.invoke(originalDao, args); + } + +} diff --git a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/UpdateListener.java b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/UpdateListener.java new file mode 100644 index 0000000..ff5eb31 --- /dev/null +++ b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/UpdateListener.java @@ -0,0 +1,7 @@ +package org.ovirt.engine.core.dal.dbbroker.updateListeners; + +import org.ovirt.engine.core.dao.DAO; + +public interface UpdateListener { + public void updateOccured(DAO dao, String methodName, Object[] args); +} diff --git a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/UpdateMethod.java b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/UpdateMethod.java new file mode 100644 index 0000000..e8fb770 --- /dev/null +++ b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/updateListeners/UpdateMethod.java @@ -0,0 +1,17 @@ +package org.ovirt.engine.core.dal.dbbroker.updateListeners; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation is used to mark methods that update the database, and will require an update to depending + * materialized view objects + * @author lzelkha + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface UpdateMethod { + +} diff --git a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/DaoFactory.java b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/DaoFactory.java index 3f4a5fe..07e919b 100644 --- a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/DaoFactory.java +++ b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/DaoFactory.java @@ -1,9 +1,11 @@ package org.ovirt.engine.core.dao; +import java.lang.reflect.Proxy; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.ovirt.engine.core.dal.dbbroker.updateListeners.DaoDynamicWrapper; import org.ovirt.engine.core.utils.ResourceUtils; public class DaoFactory { @@ -19,10 +21,13 @@ return daoType.cast(daos.get(daoType)); } + @SuppressWarnings("unchecked") private static <T extends DAO> T createDAO(Class<T> daoType) { try { - return newInstance(daoType, - ResourceUtils.loadProperties(DaoFactory.class, ENGINE_DAOS_CONFIGURATION_FILE)); + return (T) Proxy.newProxyInstance(DaoFactory.class.getClassLoader(), + new Class[] { daoType }, + new DaoDynamicWrapper<T>(newInstance(daoType, + ResourceUtils.loadProperties(DaoFactory.class, ENGINE_DAOS_CONFIGURATION_FILE)))); } catch (Exception e) { throw new DaoFactoryException(daoType, ENGINE_DAOS_CONFIGURATION_FILE, e); } diff --git a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MatrializedViewListenerTest.java b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MatrializedViewListenerTest.java new file mode 100644 index 0000000..fc2c53a --- /dev/null +++ b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/materializedviews/MatrializedViewListenerTest.java @@ -0,0 +1,16 @@ +package org.ovirt.engine.core.dal.dbbroker.materializedviews; + +import org.junit.Test; +import org.ovirt.engine.core.dao.AuditLogDAO; +import org.ovirt.engine.core.dao.AuditLogDAODbFacadeImpl; + +public class MatrializedViewListenerTest { + + @Test + public void testUpdateOccured() { + MatrializedViewListener listener = new MatrializedViewListener(); + AuditLogDAO dao = new AuditLogDAODbFacadeImpl(); + listener.updateOccured(dao, "save", null); + } + +} -- To view, visit http://gerrit.ovirt.org/16305 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I745e934fde341bd1264e5e5fedaf59fc64ad4ad8 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Liran Zelkha <[email protected]> _______________________________________________ Engine-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/engine-patches
