001// 002// Name 003// $RCSfile: Extent.java,v $ 004// 005// Copyright 006// Copyright 2014 Cloud Software Group, Inc. ALL RIGHTS RESERVED. 007// Cloud Software Group, Inc. Confidential Information 008// 009// History 010// $Revision: 1.1.2.7 $ $Date: 2014/11/26 22:22:11 $ 011// 012package com.kabira.store; 013 014import com.kabira.platform.annotation.Managed; 015import com.kabira.platform.LockMode; 016import com.kabira.platform.ManagedClassError; 017import com.kabira.platform.ManagedObject; 018import com.kabira.platform.Transaction; 019 020import java.util.HashSet; 021 022/** 023 * Class for receiving notifications of 024 * {@link com.kabira.platform.ManagedObject#extent} calls. 025 * <p> 026 * An <code>Extent</code> notifier does not directly return results. 027 * The notification provides an opportunity to change the contents of 028 * a Managed object extent (creating or deleting Managed objects) 029 * before the extent iteration is done. 030 * For example, it could be used for creating Managed objects from data 031 * in a database. 032 * 033 * @param <T> Managed type parameter 034 */ 035@Managed 036public abstract class Extent<T> extends ExtentBase 037{ 038 // force usage of protected ctor 039 private Extent() 040 { 041 } 042 043 /** Constructor. 044 * <p> 045 * Creating an instance automatically installs it 046 * as the extent notifier for Managed class <code>T</code>. 047 * <p> 048 * If a notifier is already installed for the class, 049 * the new instance replaces the previous instance. 050 * <p> 051 * Deleting a notifier automatically uninstalls it. 052 * <p> 053 * Notifiers are automatically deleted when the JVM shuts down. 054 * Notifiers created in other JVMs are not affected. 055 * <p> 056 * A separate notifier may be set for each class in a hierarchy. 057 * <p> 058 * If no notifier is installed for a class, 059 * it inherits the notifier of its parent. 060 * <p> 061 * When a {@link ManagedObject#extent} result set is iterated, 062 * the installed notifier for its type and subtypes are called 063 * before executing the extent call. 064 * 065 * The notifiers are called starting at the most extended 066 * subtype up through the type hierarchy ending on the class 067 * passed to the extent call. 068 * The order of notifier invocation for multiple types at the 069 * same level of the type hierarchy is undefined. 070 * 071 * @param klass The Managed class base to receive 072 * ManagedObject.extent() notifications for. 073 * @throws ManagedClassError <code>klass</code> is not managed. 074 */ 075 protected Extent(final Class<T> klass) 076 throws ManagedClassError 077 { 078 audit(klass); 079 080 m_className = klass.getName(); 081 install(); 082 NotifierHash.addToHash(this); 083 } 084 085 private static void audit(final Class<?> klass) 086 { 087 if (! ManagedObject.isManagedClass(klass)) 088 { 089 throw new ManagedClassError( 090 klass.getName() + " is not @Managed"); 091 } 092 } 093 094 /** 095 * Return the currently installed notifier for a Managed class. 096 * Inheritance is not considered. 097 * <p> 098 * If there is no notifier for the Managed class null is returned. 099 * 100 * @param klass The class to search. 101 * @return Extent or null. 102 * @throws com.kabira.platform.ManagedClassError If 103 * <code>klass</code> is not managed. 104 */ 105 public static Extent<?> getNotifier(final Class<?> klass) 106 { 107 audit(klass); 108 return (Extent)StoreUtil.getExtentNotifier(klass.getName()); 109 } 110 111 /** 112 * Notifier method for 113 * {@link com.kabira.platform.ManagedObject#extent(Class)} calls. 114 * May be used to create (or delete) objects in the extent before 115 * the extent is iterated. 116 * <p> 117 * Called by the system when a {@link ManagedObject#extent} result set is 118 * iterated, before executing the extent call. 119 * <p> 120 * Called on each of the nodes in the 121 * {@link com.kabira.platform.QueryScope} of the extent call. 122 * <p> 123 * Called before the ManagedObject.extent() is performed. 124 * <p> 125 * Work done within Extent.extent() will not 126 * generate calls to com.kabira.store notifiers on the local node. 127 * <p> 128 * <b>Note:</b> work done within Extent.extent() will generate 129 * calls to com.kabira.store notifiers on remote nodes. 130 * 131 * @param klass The Managed class for the extent() call. 132 * This may be a subtype of the notifier's managed 133 * class type. 134 * 135 * @param lockMode The lock mode for the extent call. The notifier 136 * implementation should attempt to honor this lock mode, 137 * but there is no enforcement. 138 */ 139 public abstract void extent( 140 final Class<? extends T> klass, 141 final LockMode lockMode); 142 143 private void extentInternal( 144 final Class<? extends T> klass, 145 final int lockMode) 146 { 147 extent(klass, LockMode.values()[lockMode]); 148 } 149 150 static 151 { 152 Runtime.getRuntime().addShutdownHook(new Thread() 153 { 154 @Override 155 public void run() 156 { 157 new Transaction("Extent notifier shutdown") 158 { 159 @Override 160 protected void run() 161 { 162 NotifierHash.clearNotifiers(); 163 } 164 }.execute(); 165 } 166 }); 167 } 168 169 private static class NotifierHash 170 { 171 static final HashSet<Extent<?>> m_installedNotifiers 172 = new HashSet<Extent<?>>(); 173 174 static void addToHash(final Extent<?> notifier) 175 { 176 m_installedNotifiers.add(notifier); 177 } 178 179 static void clearNotifiers() 180 { 181 for (Extent<?> extent : m_installedNotifiers) 182 { 183 if (! ManagedObject.isEmpty(extent)) 184 { 185 ManagedObject.delete(extent); 186 } 187 } 188 } 189 } 190}