00001 /******************************************************************************* 00002 00003 @file PickleRegistry.d 00004 00005 Copyright (C) 2004 Kris Bell 00006 00007 This software is provided 'as-is', without any express or implied 00008 warranty. In no event will the authors be held liable for damages 00009 of any kind arising from the use of this software. 00010 00011 Permission is hereby granted to anyone to use this software for any 00012 purpose, including commercial applications, and to alter it and/or 00013 redistribute it freely, subject to the following restrictions: 00014 00015 1. The origin of this software must not be misrepresented; you must 00016 not claim that you wrote the original software. If you use this 00017 software in a product, an acknowledgment within documentation of 00018 said product would be appreciated but is not required. 00019 00020 2. Altered source versions must be plainly marked as such, and must 00021 not be misrepresented as being the original software. 00022 00023 3. This notice may not be removed or altered from any distribution 00024 of the source. 00025 00026 00027 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00028 00029 00030 @version Initial version, April 2004 00031 @author Kris 00032 00033 00034 *******************************************************************************/ 00035 00036 module mango.io.PickleRegistry; 00037 00038 private import mango.io.Exception; 00039 00040 public import mango.io.model.IReader, 00041 mango.io.model.IPickle; 00042 00043 /******************************************************************************* 00044 00045 Bare framework for registering and creating serializable objects. 00046 Such objects are intended to be transported across a local network 00047 and re-instantiated at some destination node. 00048 00049 Each IPickle exposes the means to write, or freeze, its content. An 00050 IPickleFactory provides the means to create a new instance of itself 00051 populated with thawed data. Frozen objects are uniquely identified 00052 by a guid exposed via the interface. Responsibility of maintaining 00053 uniqueness across said identifiers lies in the hands of the developer. 00054 00055 See PickleReader for an example of how this is expected to operate. 00056 00057 *******************************************************************************/ 00058 00059 class PickleRegistry 00060 { 00061 private static Object lock; 00062 private static Proxy[char[]] registry; 00063 00064 /*********************************************************************** 00065 00066 ***********************************************************************/ 00067 00068 alias Object function (IReader reader) SimpleProxyFnc; 00069 alias Object function (IReader reader, char[] guid) GuidProxyFnc; 00070 00071 /*********************************************************************** 00072 00073 Base registrar entry 00074 00075 ***********************************************************************/ 00076 00077 private class Proxy 00078 { 00079 abstract Object create (IReader reader); 00080 } 00081 00082 /*********************************************************************** 00083 00084 Simple registrar entry 00085 00086 ***********************************************************************/ 00087 00088 private class SimpleProxy : Proxy 00089 { 00090 SimpleProxyFnc fnc; 00091 00092 /*************************************************************** 00093 00094 ***************************************************************/ 00095 00096 this (SimpleProxyFnc fnc) 00097 { 00098 this.fnc = fnc; 00099 } 00100 00101 /*************************************************************** 00102 00103 ***************************************************************/ 00104 00105 Object create (IReader reader) 00106 { 00107 return fnc (reader); 00108 } 00109 } 00110 00111 /*********************************************************************** 00112 00113 Guid registrar entry 00114 00115 ***********************************************************************/ 00116 00117 private class GuidProxy : Proxy 00118 { 00119 GuidProxyFnc fnc; 00120 char[] guid; 00121 00122 /*************************************************************** 00123 00124 ***************************************************************/ 00125 00126 this (GuidProxyFnc fnc, char[] guid) 00127 { 00128 this.fnc = fnc; 00129 this.guid = guid; 00130 } 00131 00132 /*************************************************************** 00133 00134 ***************************************************************/ 00135 00136 Object create (IReader reader) 00137 { 00138 return fnc (reader, guid); 00139 } 00140 } 00141 00142 /*********************************************************************** 00143 00144 IPickleFactory registrar entry 00145 00146 ***********************************************************************/ 00147 00148 private class PickleProxy : Proxy 00149 { 00150 IPickleFactory factory; 00151 00152 /*************************************************************** 00153 00154 ***************************************************************/ 00155 00156 this (IPickleFactory factory) 00157 { 00158 this.factory = factory; 00159 } 00160 00161 /*************************************************************** 00162 00163 ***************************************************************/ 00164 00165 Object create (IReader reader) 00166 { 00167 return factory.create (reader); 00168 } 00169 } 00170 00171 /*********************************************************************** 00172 00173 This is a singleton: the constructor should not be exposed 00174 00175 ***********************************************************************/ 00176 00177 private this () 00178 { 00179 } 00180 00181 /*********************************************************************** 00182 00183 Initialize the environment 00184 00185 ***********************************************************************/ 00186 00187 private static this() 00188 { 00189 // have to do this to work around static syncronization bug 00190 lock = new Object(); 00191 } 00192 00193 /*********************************************************************** 00194 00195 Add the provided class to the registry. Note that one 00196 cannot change a registration once it is placed. Neither 00197 can one remove registered item. This is done to avoid 00198 major issues when trying to synchronize servers across 00199 a farm, which may still have live instances of "old" 00200 objects waiting to be passed around the cluster. New 00201 versions of an object should be given a distinct guid 00202 from the prior version; appending an incremental number 00203 may well be sufficient for your needs. 00204 00205 ***********************************************************************/ 00206 00207 private static synchronized void enroll (Proxy proxy, char[] guid) 00208 { 00209 if (guid in registry) 00210 throw new PickleException ("Invalid attempt to re-register a guid"); 00211 00212 registry[guid] = proxy; 00213 } 00214 00215 /*********************************************************************** 00216 00217 do a synchronized Proxy lookup of the guid 00218 00219 ***********************************************************************/ 00220 00221 private final static synchronized Proxy lookup (char[] guid) 00222 { 00223 if (guid in registry) 00224 return registry [guid]; 00225 return null; 00226 } 00227 00228 /*********************************************************************** 00229 00230 Add the provided object to the registry. Note that one 00231 cannot change a registration once it is placed. Neither 00232 can one remove registered item. This is done to avoid 00233 major issues when trying to synchronize servers across 00234 a farm, which may still have live instances of "old" 00235 objects waiting to be passed around the cluster. New 00236 versions of an object should be given a distinct guid 00237 from the prior version; appending an incremental number 00238 may well be sufficient for your needs. 00239 00240 ***********************************************************************/ 00241 00242 static void enroll (IPickleFactory object) 00243 { 00244 enroll (new PickleProxy(object), object.getGuid); 00245 } 00246 00247 /*********************************************************************** 00248 00249 Add the provided function to the registry. Note that one 00250 cannot change a registration once it is placed. Neither 00251 can one remove registered item. This is done to avoid 00252 major issues when trying to synchronize servers across 00253 a farm, which may still have live instances of "old" 00254 objects waiting to be passed around the cluster. New 00255 versions of an object should be given a distinct guid 00256 from the prior version; appending an incremental number 00257 may well be sufficient for your needs. 00258 00259 ***********************************************************************/ 00260 00261 static void enroll (SimpleProxyFnc sp, char[] guid) 00262 { 00263 enroll (new SimpleProxy(sp), guid); 00264 } 00265 00266 /*********************************************************************** 00267 00268 Add the provided function to the registry. Note that one 00269 cannot change a registration once it is placed. Neither 00270 can one remove registered item. This is done to avoid 00271 major issues when trying to synchronize servers across 00272 a farm, which may still have live instances of "old" 00273 objects waiting to be passed around the cluster. New 00274 versions of an object should be given a distinct guid 00275 from the prior version; appending an incremental number 00276 may well be sufficient for your needs. 00277 00278 ***********************************************************************/ 00279 00280 static void enroll (GuidProxyFnc gp, char[] guid) 00281 { 00282 enroll (new GuidProxy(gp, guid), guid); 00283 } 00284 00285 /*********************************************************************** 00286 00287 Create a new instance of a registered class from the content 00288 made available via the given reader. The factory is located 00289 using the provided guid, which must match an enrolled class. 00290 00291 Note that only the factory lookup is synchronized, and not 00292 the instance construction itself. 00293 00294 ***********************************************************************/ 00295 00296 static Object create (IReader reader, char[] guid) 00297 { 00298 // locate the appropriate Proxy. 00299 Proxy p = lookup (guid); 00300 if (p) 00301 return p.create (reader); 00302 00303 throw new PickleException ("Attempt to unpickle via unregistered guid '"~guid~"'"); 00304 } 00305 } 00306