Where's a good place for me to do one-time setup and then make certain
objects available to the rest of the application? I created a UserRepository that I want each of the components to use. So far I've created a base subclass of WAComponent, it has a class variable named TheUserRepository. I have a class-side method which lazily instantiates it. Then the instance initialize for each of my components points an instance variable at this method. The code looks like "ANComponent userRepository" userRepository TheUserRepository ifNil: [TheUserRepository := GDRepository for: ANUser]. ^ TheUserRepository "ANComponent>>initialize" initialize super initialize. userRepository := ANComponent userRepository. All of my components inherit from ANComponent so they each have the userRepository set when they're instantiated. Is this a good way of doing it? It seems to be working so far. I don't know enough about seaside to know better at this point :) If possible, I'd like to move away from using a class variable to store the repo. As it is, I can't deploy the same app twice at different entry points because they'll use the same userRepository object. So what I'd really like is an Application object that gets run once, where I can do all my setup. But that application object should be new for each deployment, so that I'm not mixing the data between deployments. Thanks for any help. Pat _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Hi Pat,
As I understand it you want application data to be separated based on entry points, but otherwise share the same environment (e.g., deployment image). If you will have a small number of pre-defined entry points, then you could have separate components for each entry point and subclass from a common ancestor so that they share behavior. With this approach you could define a 'class instance variable' in the abstract superclass and then each subclass would have its own data. Alternatively, you could use the entry point as a key in a Dictionary containing various different application data sets. You can get the entry point from 'self session baseUrl printString' or 'self session baseUrl path last'. With this approach you can keep your class variable, but make it a Dictionary and do similar lazy initialization of the Dictionary and of the contents (using #'at:ifAbsentPut:'). Also, depending on your deployment strategy, you could use multiple Smalltalk images. This "horizontal scaling" is a simplification of the approach taken by DabbleDB and allows hundreds of thousands of applications with the same code but different data and uses multiple machines efficiently. James Foster On May 17, 2009, at 1:49 PM, Pat Maddox wrote: > Where's a good place for me to do one-time setup and then make certain > objects available to the rest of the application? I created a > UserRepository that I want each of the components to use. So far I've > created a base subclass of WAComponent, it has a class variable named > TheUserRepository. I have a class-side method which lazily > instantiates it. Then the instance initialize for each of my > components points an instance variable at this method. The code looks > like > > "ANComponent userRepository" > userRepository > TheUserRepository ifNil: [TheUserRepository := GDRepository for: > ANUser]. > ^ TheUserRepository > > "ANComponent>>initialize" > initialize > super initialize. > userRepository := ANComponent userRepository. > > All of my components inherit from ANComponent so they each have the > userRepository set when they're instantiated. > > Is this a good way of doing it? It seems to be working so far. I > don't know enough about seaside to know better at this point :) > > If possible, I'd like to move away from using a class variable to > store the repo. As it is, I can't deploy the same app twice at > different entry points because they'll use the same userRepository > object. So what I'd really like is an Application object that gets > run once, where I can do all my setup. But that application object > should be new for each deployment, so that I'm not mixing the data > between deployments. > > Thanks for any help. > > Pat > _______________________________________________ > seaside mailing list > [hidden email] > http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside > _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Hey James,
Thanks for the reply. Comments inline On Sun, May 17, 2009 at 2:32 PM, James Foster <[hidden email]> wrote: > Hi Pat, > > As I understand it you want application data to be separated based on entry > points, but otherwise share the same environment (e.g., deployment image). Well my real goal is to have a single place where I wire up my app's major dependencies - repositories, connections to external services, etc. This is partly so I can do multiple installs, but mostly for ease of use. > If you will have a small number of pre-defined entry points, then you could > have separate components for each entry point and subclass from a common > ancestor so that they share behavior. With this approach you could define a > 'class instance variable' in the abstract superclass and then each subclass > would have its own data. This makes sense to me but I'm not sure how to make it work. If I have a class instance variable, then each subclass gets its own version of that variable. The whole point of this is to share one object throughout all components in an application. > Alternatively, you could use the entry point as a key in a Dictionary > containing various different application data sets. You can get the entry > point from 'self session baseUrl printString' or 'self session baseUrl path > last'. With this approach you can keep your class variable, but make it a > Dictionary and do similar lazy initialization of the Dictionary and of the > contents (using #'at:ifAbsentPut:'). I still need to know where to put this Dictionary though. I take it that a class variable in my WAComponent subclass is not such a bad idea after all? > Also, depending on your deployment strategy, you could use multiple > Smalltalk images. This "horizontal scaling" is a simplification of the > approach taken by DabbleDB and allows hundreds of thousands of applications > with the same code but different data and uses multiple machines > efficiently. Yes I certainly need to figure out how I want to deploy this stuff. That kind of strategy would work really well for this particular app. But I'm also interested in "out of the box" (and cool! (and pricey ;)) behavior with gemstone. Pat > > James Foster > > On May 17, 2009, at 1:49 PM, Pat Maddox wrote: > >> Where's a good place for me to do one-time setup and then make certain >> objects available to the rest of the application? I created a >> UserRepository that I want each of the components to use. So far I've >> created a base subclass of WAComponent, it has a class variable named >> TheUserRepository. I have a class-side method which lazily >> instantiates it. Then the instance initialize for each of my >> components points an instance variable at this method. The code looks >> like >> >> "ANComponent userRepository" >> userRepository >> TheUserRepository ifNil: [TheUserRepository := GDRepository for: >> ANUser]. >> ^ TheUserRepository >> >> "ANComponent>>initialize" >> initialize >> super initialize. >> userRepository := ANComponent userRepository. >> >> All of my components inherit from ANComponent so they each have the >> userRepository set when they're instantiated. >> >> Is this a good way of doing it? It seems to be working so far. I >> don't know enough about seaside to know better at this point :) >> >> If possible, I'd like to move away from using a class variable to >> store the repo. As it is, I can't deploy the same app twice at >> different entry points because they'll use the same userRepository >> object. So what I'd really like is an Application object that gets >> run once, where I can do all my setup. But that application object >> should be new for each deployment, so that I'm not mixing the data >> between deployments. >> >> Thanks for any help. >> >> Pat >> _______________________________________________ >> seaside mailing list >> [hidden email] >> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside >> > > _______________________________________________ > seaside mailing list > [hidden email] > http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside > seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
On May 17, 2009, at 3:23 PM, Pat Maddox wrote:
> Hey James, > > Thanks for the reply. Comments inline > > On Sun, May 17, 2009 at 2:32 PM, James Foster > <[hidden email]> wrote: >> Hi Pat, >> >> As I understand it you want application data to be separated based >> on entry >> points, but otherwise share the same environment (e.g., deployment >> image). > > Well my real goal is to have a single place where I wire up my app's > major dependencies - repositories, connections to external services, > etc. This is partly so I can do multiple installs, but mostly for > ease of use. Do different entry points share data? Does one application have multiple entry points? Does one deployment have multiple applications? What do you mean by "multiple installs"? >> If you will have a small number of pre-defined entry points, then >> you could >> have separate components for each entry point and subclass from a >> common >> ancestor so that they share behavior. With this approach you could >> define a >> 'class instance variable' in the abstract superclass and then each >> subclass >> would have its own data. > > This makes sense to me but I'm not sure how to make it work. If I > have a class instance variable, then each subclass gets its own > version of that variable. The whole point of this is to share one > object throughout all components in an application. True enough. This would not share data among multiple components. >> Alternatively, you could use the entry point as a key in a Dictionary >> containing various different application data sets. You can get the >> entry >> point from 'self session baseUrl printString' or 'self session >> baseUrl path >> last'. With this approach you can keep your class variable, but >> make it a >> Dictionary and do similar lazy initialization of the Dictionary and >> of the >> contents (using #'at:ifAbsentPut:'). > > I still need to know where to put this Dictionary though. I take it > that a class variable in my WAComponent subclass is not such a bad > idea after all? If you are storing objects in the image (or GemStone repository), then the objects need to be reached from a persistent root. In Squeak, that root is the global named Smalltalk. In GemStone there is a global named UserGlobals that should be available. You can attach your dictionary to that global or you can attach it to something that is referenced from that global. Since classes are themselves globals, anything they reference, including class (instance) variables, are also persistent. The class (instance) variable approach is quite reasonable, though you might think about what class to use. Instead of having every domain object keep a cache of its instances, you might have a single 'Database' class that has instance variables for various things. In our Los Boquitas example, instead of having LBEvent hold on to a collection of events, you could define a LBTeam class with instance variables for players, coaches, events, etc. You could even generalize it further to have a LBLeague class with a collection of teams. (Or more general, a LBCommunity class with a collection of leagues...) Basically, we are using the Singleton Pattern (http://en.wikipedia.org/wiki/Singleton_pattern ). Create a singleton for whatever is truly singular in your object space, and then hold on to it in a class (instance) variable. Have that singleton manage whatever data you want to persist. >> Also, depending on your deployment strategy, you could use multiple >> Smalltalk images. This "horizontal scaling" is a simplification of >> the >> approach taken by DabbleDB and allows hundreds of thousands of >> applications >> with the same code but different data and uses multiple machines >> efficiently. > > Yes I certainly need to figure out how I want to deploy this stuff. > That kind of strategy would work really well for this particular app. > But I'm also interested in "out of the box" (and cool! (and pricey ;)) > behavior with gemstone. The basic idea is model your domain objects. Somewhere, there should be a singleton that knows about the various applications, customers, etc. You could even name your singleton 'Pat'! > Pat > > >> >> James Foster >> >> On May 17, 2009, at 1:49 PM, Pat Maddox wrote: >> >>> Where's a good place for me to do one-time setup and then make >>> certain >>> objects available to the rest of the application? I created a >>> UserRepository that I want each of the components to use. So far >>> I've >>> created a base subclass of WAComponent, it has a class variable >>> named >>> TheUserRepository. I have a class-side method which lazily >>> instantiates it. Then the instance initialize for each of my >>> components points an instance variable at this method. The code >>> looks >>> like >>> >>> "ANComponent userRepository" >>> userRepository >>> TheUserRepository ifNil: [TheUserRepository := GDRepository >>> for: >>> ANUser]. >>> ^ TheUserRepository >>> >>> "ANComponent>>initialize" >>> initialize >>> super initialize. >>> userRepository := ANComponent userRepository. >>> >>> All of my components inherit from ANComponent so they each have the >>> userRepository set when they're instantiated. >>> >>> Is this a good way of doing it? It seems to be working so far. I >>> don't know enough about seaside to know better at this point :) >>> >>> If possible, I'd like to move away from using a class variable to >>> store the repo. As it is, I can't deploy the same app twice at >>> different entry points because they'll use the same userRepository >>> object. So what I'd really like is an Application object that gets >>> run once, where I can do all my setup. But that application object >>> should be new for each deployment, so that I'm not mixing the data >>> between deployments. >>> >>> Thanks for any help. >>> >>> Pat seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Pat Maddox-2
"ANComponent userRepository" I agree with James but I'll be more specific, how about this... UserRepository class>>forApp: anApp ^ (Repository ifNil: [Repository := Dictionary new ]) at: anApp ifAbsentPut: [ GDRepository for: ANUser ] ANComponent>>initialize super initialize. userRepository := UserRespository forApp: self session baseUrl printString. No need to stick the repository on a component class, create a unique class just for it, you get an automatic singleton because classes *are* singletons and why shouldn't a user repository be its own abstraction? Ramon Leon http://onsmalltalk.com _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
I agree with James but I'll be more specific, how about this... Or even better... ANUser class>>repositoryForApp: anAppName ^ (Repository ifNil: [Repository := Dictionary new ]) at: anAppName ifAbsentPut: [ GDRepository for: self ] ANComponent>>initialize super initialize. userRepository := ANUser repositoryForApp: self session baseUrl printString. Let the ANUser class itself hold the repository for all its instances for all entry points. Then you don't have to think as much, you just establish the pattern that a repository for any class is on that class. This works for prototyping in Squeak/Pharo and in Gemstone works as an actual production solution because it'll automatically be persisted. Ramon Leon http://onsmalltalk.com _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Ramon Leon-5
On Sun, May 17, 2009 at 6:44 PM, Ramon Leon <[hidden email]> wrote:
>> "ANComponent userRepository" >> userRepository >> TheUserRepository ifNil: [TheUserRepository := GDRepository for: >> ANUser]. >> ^ TheUserRepository >> >> "ANComponent>>initialize" >> initialize >> super initialize. >> userRepository := ANComponent userRepository. >> > > I agree with James but I'll be more specific, how about this... > > UserRepository class>>forApp: anApp > ^ (Repository ifNil: [Repository := Dictionary new ]) > at: anApp ifAbsentPut: [ GDRepository for: ANUser ] > > > ANComponent>>initialize > super initialize. > userRepository := UserRespository forApp: self session baseUrl > printString. > > No need to stick the repository on a component class, create a unique class > just for it, you get an automatic singleton because classes *are* singletons > and why shouldn't a user repository be its own abstraction? There are a few different ways for objects to get a dependency, looking up a singleton is only one of them. I'd prefer not to use it. Let me show you some fake code that should hopefully demonstrate what I want to do better than I've explained it so far. MyBlogApp new userRepository: UserRepository new; mountAt: '/us/blog'; run. MyBlogApp new userRepository: UserRepository new; mountAt: '/ca/blog'; run. Each of those is an instance of my blog app, and runs separately from the other. The userRepository automatically gets injected into the components that make up the application. This way they can just look up their local instance variable as opposed to grabbing a singleton. Is that clearer? That's the gist of what I'm trying to do. Now I just need to know how to do it with Seaside. Pat _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Ah, I see, you're wanting to be involved in the creation of the root instance of your component and hand in the dependency there. What you're looking for is a custom render loop, subclass WARenderLoopMain so you can override #createRoot and control the creation of your component. Then you can pass in any dependencies you like during the construction of your component. You can plug in your render loop during the registration of your app on a mount point. YourRootClass class>>initialize | app | app := self registerAsApplication: 'someAppName'. app preferenceAt: #mainClass put: YourRenderLoop. ^ app Ramon Leon http://onsmalltalk.com _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
When I load Seaside 2.8a1-pmm.573 from the public Store, what version
of the Squeak bundle is supposed to work with that? It sure would be great if things in Store could have some notion of what versions of other things should be used. I hate to guess. I have similar sorts of uneasiness when trying to figure out which versions of Async and Scriptaculous to load from the public Store. When I load the latest '2.8-ish' Scriptaculous I get this unloadable definition message: Color javascriptOn:(04/12/2006 7:46:56.000,mbany) This seems to be a Squeak related definition. Thanks, -Carl Gundel http://www.runbasic.com _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
It's best to load the parcel rather than load from Store for this
James Robertson Cincom Smalltalk Product Evangelist http://www.cincomsmalltalk.com/blog/blogView Talk Small and Carry a Big Class Library On May 19, 2009, at 12:10 PM, Carl Gundel wrote: > When I load Seaside 2.8a1-pmm.573 from the public Store, what > version of the Squeak bundle is supposed to work with that? > > It sure would be great if things in Store could have some notion of > what versions of other things should be used. I hate to guess. > > I have similar sorts of uneasiness when trying to figure out which > versions of Async and Scriptaculous to load from the public Store. > When I load the latest '2.8-ish' Scriptaculous I get this unloadable > definition message: > > Color javascriptOn:(04/12/2006 7:46:56.000,mbany) > > This seems to be a Squeak related definition. > > Thanks, > > -Carl Gundel > http://www.runbasic.com > _______________________________________________ > seaside mailing list > [hidden email] > http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside > _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Do you mean the parcel that comes with 7.6? That version of Squeak
2.8 has a bug in form submission that seems fixed with the latest 2.8 release from the public Store. I'd probably be happy to keep using the parceled version if I could just fix that bug. -Carl Gundel Liberty BASIC for Windows - http://www.libertybasic.com Run BASIC, easy web programming - http://www.runbasic.com On May 19, 2009, at 12:53 PM, James Robertson <[hidden email]> wrote: > It's best to load the parcel rather than load from Store for this > > James Robertson > Cincom Smalltalk Product Evangelist > http://www.cincomsmalltalk.com/blog/blogView > Talk Small and Carry a Big Class Library > > > > > On May 19, 2009, at 12:10 PM, Carl Gundel wrote: > >> When I load Seaside 2.8a1-pmm.573 from the public Store, what >> version of the Squeak bundle is supposed to work with that? >> >> It sure would be great if things in Store could have some notion of >> what versions of other things should be used. I hate to guess. >> >> I have similar sorts of uneasiness when trying to figure out which >> versions of Async and Scriptaculous to load from the public Store. >> When I load the latest '2.8-ish' Scriptaculous I get this >> unloadable definition message: >> >> Color javascriptOn:(04/12/2006 7:46:56.000,mbany) >> >> This seems to be a Squeak related definition. >> >> Thanks, >> >> -Carl Gundel >> http://www.runbasic.com >> _______________________________________________ >> seaside mailing list >> [hidden email] >> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside >> > > _______________________________________________ > seaside mailing list > [hidden email] > http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Ramon Leon-5
On Sun, May 17, 2009 at 8:35 PM, Ramon Leon <[hidden email]> wrote:
>> >> There are a few different ways for objects to get a dependency, >> looking up a singleton is only one of them. I'd prefer not to use it. >> Let me show you some fake code that should hopefully demonstrate what >> I want to do better than I've explained it so far. >> >> MyBlogApp new userRepository: UserRepository new; >> mountAt: '/us/blog'; >> run. >> >> MyBlogApp new userRepository: UserRepository new; >> mountAt: '/ca/blog'; >> run. >> >> Each of those is an instance of my blog app, and runs separately from >> the other. The userRepository automatically gets injected into the >> components that make up the application. This way they can just look >> up their local instance variable as opposed to grabbing a singleton. >> >> Is that clearer? That's the gist of what I'm trying to do. Now I >> just need to know how to do it with Seaside. >> >> Pat > > Ah, I see, you're wanting to be involved in the creation of the root > instance of your component and hand in the dependency there. What you're > looking for is a custom render loop, subclass WARenderLoopMain so you can > override #createRoot and control the creation of your component. Then you > can pass in any dependencies you like during the construction of your > component. > > You can plug in your render loop during the registration of your app on a > mount point. > > YourRootClass class>>initialize > | app | > app := self registerAsApplication: 'someAppName'. > app preferenceAt: #mainClass put: YourRenderLoop. > ^ app The *real* reason for this question, though I didn't know it at the time, was that I was asking myself "how am I going to test this?" So I wanted to know a way to inject fake repositories in. I definitely didn't need to be able to configure it at the root - right now it's a good assumption that there's only one user repository for my app. I created a class, ANUserRepository, and then pointed the global var AccountRepository at a new instance. I pointed another global DevAccountRepository at that instance as well. Now in the setUp method of my test I set AccountRepository to a fresh instance for testing purposes, and in tearDown I reset it to DevAccountRepository so I can still click around in the browser. Thanks again James & Ramon for your feedback. Pat _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Free forum by Nabble | Edit this page |