tag:blogger.com,1999:blog-92648302008-04-10T15:27:19.161+02:00EnterpriseApplications@blogger.comWittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comBlogger19125tag:blogger.com,1999:blog-9264830.post-1156601150800650232006-08-26T16:05:00.000+02:002006-08-26T16:16:52.080+02:00Observers and SubjectsThe most well-known design pattern for decoupling object instances or classes from one another and still have a mechanism for the observer to know, when a particular event occurs on a subject, is the <a href="http://en.wikipedia.org/wiki/Observer_pattern">Observer-Pattern</a>. The implementation is typically done either <a href="http://www.flyingwithfire.com/2006/08/24/observers-and-dispatchers/">using abstract classes</a> or <a href="http://devzone.zend.com/node/view/id/6">using interfaces</a>.<br /><br />While the prior has the advantage that the abstract classes may provide a reusable behaviour for observer registration and notification it limits an observer to stay in the observer role. It's not possible for an observer of one subject, to act as a subject itself (unless, you are relying on implicit coding/naming conventions rather than on an explicit mechanism). While this may not be a problem with languages allowing multiple inhertiance, it is for languages that support single inheritance only.<br /><br />The latter (inteface-based) approach, releaves you of this issue at the cost of implementing the required methods on every class that wants to make use of the pattern. While this may be inconvenient it is a valid means to resolve and works most of the time.<br /><br />With dynamic languages such as PHP or JavaScript there is yet another way to approach the issue using a mediating class that organizes the eventhandling between abitrary objects (or classes or basically any entity you may think of). Let's show an example for the usage of this approach:<br /><br /><pre class="block">class Event { ... }<br /><br /><br />class Subject {<br /><br /> public function doSomething() {<br /> //do something and throw the event<br /> Event::raise($this,'onDoSomething');<br /> }<br /><br />}<br /><br /><br />class Observer {<br /><br /> public function onEvent(Event $event) {<br /> //react to the event<br /> echo get_class($event->getSourceObject());<br /> }<br /><br />}<br /><br />$subject = new Subject();<br />$observer = new Observer();<br />Event::register($subject,'onDoSomething',$observer,'onEvent');<br />$subject->doSomething(); //prints 'Subject'</pre><br />What you are now probably interested in the most is the implementation of the "Event"-class. As you have seen there are two static methods on it:<br /><br />1) register() allows to register abitrary methods or functions to be registered as callbacks for a particular event - 'onDoSomething' in this case - of objects or classes (the latter is not yet supported by the following implementation)<br /><br />2) raise() allows to indicate the occurrence of a particular event on an object or class (the latter is not yet supported by the following implementation). All previously registered callback methods (you may as well call them the observers) will be executed using a single argument: an "Event"-object instance.<br /><br />This object may be used to query for particular aspects of the event happening using one of the following methods.<br /><br />1) getSourceObject() returns the subject the event occurred on if existing<br /><br />2) getName() returns the name of the event so that the observer may decide how to handle different types of events, if this is not already distinguished using different callback methods.<br /><br />3) getTargetObject() returns a reference to the observer if it is an object instance<br /><br />4) getTargetMethod() returns the name of the callback method<br /><br />5) getParameters() return an array of additional parameters that the subject may hand over to raise().<br /><br />A possible implementation of the "Event"-class may look shown below. Please note that this version currently only supports object-to-object event handling:<br /><br /><pre class="block">class Event {<br /><br /> protected $targetObject;<br /> protected $targetMethod;<br /> protected $eventName;<br /> protected $sourceObject;<br /> protected $parameters;<br /><br /> protected function __construct($targetObject,<br /> $targetMethod,<br /> $eventName,<br /> $sourceObject,<br /> array $parameters = array()) {<br /> $this->targetObject = $targetObject;<br /> $this->targetMethod = $targetMethod;<br /> $this->eventName = $eventName;<br /> $this->sourceObject = $sourceObject;<br /> $this->parameters = $parameters;<br /> }<br /><br /> public function getSourceObject() {<br /> return $this->sourceObject;<br /> }<br /><br /> public function getName() {<br /> return $this->eventName;<br /> }<br /><br /> public function getTargetMethod() {<br /> return $this->targetMethod;<br /> }<br /><br /> public function getTargetObject() {<br /> return $this->targetObject;<br /> }<br /><br /> public function getParameters() {<br /> return $this->parameters;<br /> }<br /><br /> public static function raise($onObject,<br /> $event,<br /> array $parameters = array()) {<br /> foreach($onObject->__eventRegistry[$event] as $target) {<br /> if($target[0]) {<br /> call_user_func_array($target,<br /> array(<br /> new Event(<br /> $target[0],<br /> $target[1],<br /> $event,<br /> $onObject,<br /> $parameters)<br /> )<br /> );<br /> } else {<br /> call_user_func_array($target[1],<br /> array(<br /> new Event(<br /> NULL,<br /> $target[1],<br /> $event,<br /> $onObject,<br /> $parameters)<br /> )<br /> );<br /> }<br /> }<br /><br /> public static function register($sourceObject,<br /> $forEvent,<br /> $targetObject,<br /> $targetMethod) {<br /> $sourceObject->__eventRegistry[$forEvent][] = array($targetObject,$targetMethod);<br /> }<br />}</pre><br />This implementation should be session-save as well, as the dynamically built "__eventRegistry" should be serialized to and restored from the session automatically. For class based event registries this may be a little more tricky to implement.<br /><br />But once the "strict" keywork is incorporated into PHP, this approach will not work on classes anymore that are marked strict.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1155968296732857402006-08-19T08:18:00.000+02:002006-08-19T08:18:16.743+02:00Enumerations in PHPSometimes you stumble over stuff on the net and really think to yourself. Wow! Why does not everybody talk about it yet? My Subject of the day is <a href="http://pecl.php.net/package/SPL_Types">Enumerations in PHP via SPL_Types</a>. Basically it brings Enumerations to PHP, ensuring that a variable may only contain specific values based on a value domain. This should be <a href="http://beeblex.com/lists/index.php/php.pecl.dev/3570">looking something like this</a>.<br /><br /><br /><pre class="block">class Weekday extends SplEnum<br />{<br /> const Sunnday = 0;<br /> const Monday = 1;<br /> const Tuesday = 2;<br /> const Wednesday = 3;<br /> const Thursday = 4;<br /> const Friday = 5;<br /> const Saturday = 6;<br /> const __default = Weekday::Sunday;<br />}<br /><br />$e = new Weekday;<br /><br />var_dump($e); // shows object of type SplEnum<br />var_dump((int)$e); // int(0)<br /><br />$e++;<br /><br />var_dump($e); // shows object of type SplEnum<br />var_dump((int)$e); // int(1)<br />var_dump($e + 3); // int(4)</pre>I have found this example over at a <a href="http://beeblex.com/lists/index.php/php.pecl.dev/3570">mailing list transcript at BeebleX</a>. While there is certainly a trace of this functionality in the <a href="http://cvs.php.net/viewvc.cgi/pecl/spl_types/">CVS Repository</a> at php.net you cannot yet get a precompiled version of the extension at <a href="http://snaps.php.net">PHP-Snaps</a> :-(.<br /><br />Personal note: While I love PHP for the fact that it's a dynamically typed language, I consider Enumerations a big help, to communicate and ensure consistency of parameter values on public interfaces.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1155967141030777922006-08-19T07:59:00.000+02:002006-08-19T07:59:01.043+02:00Validating user input using PECL::filter<a href="http://oss.backendmedia.com/PeclFilter">PECL::filter</a> is a new promising <a href="http://pecl.php.net/package/filter">PHP extension</a>, which will come with the new PHP 5.2.0. It is mainly meant for validation of input, which currently requires quite some work. Since there is no documentation over at <a href="http://www.php.net">php.net </a>you can <a href="http://oss.backendmedia.com/PeclFilter">read all about it over here</a>. For all the guys using Windows for your development environment here you can <a href="http://pecl4win.php.net/ext.php/php_filter.dll">download the compiled extension </a>for your current PHP installment.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1155206484864347782006-08-10T12:41:00.000+02:002006-08-10T12:41:24.943+02:00Calculating distancesSince I seem to have a fav on geo-calculation since Google-Maps has hit me, I have been looking for some information how to calculate distances between to points on the globe.<br /><br />The GoogleAPI actually <a href="http://www.google.com/apis/maps/documentation/reference.html#GLatLng">has a method to calculate the distance</a> between points based on a shperical model.<br /><br />But what if you'd like to implement a radius search on the database or calculate distances on the backend. I found <a href="http://www.meridianworlddata.com/Distance-Calculation.asp">a nice introduction for the subject </a>over at MeridianWorldData, which takes into account various levels of precision to gain performance, where it is needed.<br /><br />Also I found a <a href="http://www.web-max.ca/PHP/misc_2.php">PHP based example for distance calculation </a>as well as a <a href="http://www.web-max.ca/PHP/">series of articles</a> on the subject of <a href="http://www.web-max.ca/PHP/">GIS mapping</a>.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1155198031916319962006-08-10T10:20:00.000+02:002006-08-10T10:24:03.213+02:00Mashup GoogleMaps and GeoIPOk I have put together <a href="http://dwittenbeck.inspirationlabs.de/geoip/">a small example</a> of how to use <a href="http://www.google.com/apis/maps/">GoogleMaps</a> and <a href="http://www.maxmind.com/app/geoip_country">GeoIP</a>. Use it to look up where a specific URL or server is hosted.<br /><br />You can <a href="http://dwittenbeck.inspirationlabs.de/geoip/">view it here</a>. The application includes a bookmarklet, which you may bookmark or place in the link's bar of your browser to use it from every website to determine it's location.<br /><br />For all you PHP freaks, <a href="http://dwittenbeck.inspirationlabs.de/geoip/GeoIp.zip">you can download the complete example</a> as well. Just unpack the ZIP file on your PHP5-enabled server and you should be good to go. Just make sure to use your own GoogleMaps API key, <a href="http://www.google.com/apis/maps/signup.html">you can get here</a>.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1155189095745775472006-08-10T07:49:00.000+02:002006-08-10T07:51:35.746+02:00Republished CSTLI have just republished the article and samples about CSTL (Client Side Tag Libs), which brings TagLibs to JavaScript in an extensible object oriented model. The original articles are well 1 1/2 year old but since everyone seems to talk about AJAX these days, I just want to show, that I had my 50cent to distribute to that subject a long time ago. Besides the links were not working in quite a while.<br /><br /><a class="article_button left" href="http://dwittenbeck.inspirationlabs.de/downloads/Client%20Side%20Tag%20Libs.pdf">full article</a> <a href="http://dwittenbeck.inspirationlabs.de/downloads/Client%20Side%20Tag%20Libs.zip" class="article_button right">download files</a>WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1155124874798375512006-08-09T14:01:00.000+02:002006-08-09T14:01:14.833+02:00Matching IP to countryI have again found <a href="http://builder.com.com/5100-6371_14-6103179.html?part=rss&subj=bldr">a nice article</a> about how to match IPs to countries over at builder.com. It uses PHP::Pear's Net_GeoIP class for the querying. But what really interest me is the data behind it. Luckily <a href="http://www.maxmind.com/app/geoip_country">MaxMind</a> does provide this data in various flavors.<br /><br />There is a free CSV export at the beginning of every month, which can be downloaded on <a href="http://www.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip">country level</a> and on <a href="http://www.maxmind.com/download/geoip/database/GeoLiteCity_CSV/GeoLiteCity_20060801.zip">city level</a>.<br /><br />However there are also 2 APIs for PHP. For once there is a <a href="http://www.maxmind.com/download/geoip/api/php/">pure PHP implementation</a> and also a <a href="http://www.maxmind.com/download/geoip/api/php_extension/">PHP extension</a> as well.<br /><br />I am definately going to try these out!WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1155018727794060782006-08-08T08:32:00.000+02:002006-08-08T08:33:25.690+02:00Creating MS Office documents using PHPI have recently <a href="http://web.informbank.com/articles/technology/php-office-documents.htm">discovered an article</a> on how to generate MS Office Documents using PHP. Basically this article does not contain anything new, demonstrating how to utilize the COM API to construct Word and Powerpoint and how Excel can be created from an HTML table. While this article will not enable you to approach the issue in an OS independent way (you will in fact need a windows server to create Word and Powerpoint documents) it still assembles the concepts for all 3 major MS Office products, containing easy to understand code snippets.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1154191895473711112006-07-29T18:51:00.000+02:002006-07-29T18:51:35.486+02:00Google Code - APIs and moreThe recent hype for mashup-applications has certainly fueled the run on the it's <a href="http://www.google.com/apis/maps/">AJAX Maps API</a>. But there are <a href="http://code.google.com/apis.html">plenty other APIs</a>, which google offers, also worth a look. What will be certainly interesting for me, will be the <a href="http://code.blogspot.com/archives/atom-docs.html">Blogger Atom API</a> which you can use to search and modify your blogs on <a href="http://www.blogger.com">www.blogger.com</a>.<br /><br />Also Google now <a href="http://code.google.com/hosting/">hosts your open source projects</a>, similar to the <a href="http://sourceforge.net">sourceforge.net</a> way.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1154190736493501152006-07-29T18:32:00.001+02:002006-07-29T18:53:27.956+02:00PHP Sockets Made EasyThere is a <a href="http://www.litfuel.net/tutorials/sockets/sockets.php">really nice tutorial</a> up about creating and consuming sockets usiung PHP. At the time of this writing the first part of a 5 part tutorial series is published. I am going to following it, since I have recently written a generic Socket-Server and want to see things, I may improve.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1153232892374280192006-07-18T16:28:00.000+02:002006-07-18T16:28:12.413+02:00dompdf - The PHP 5 HTML to PDF ConverterFinally there seem to be a decent API for PHP developers to render HTML to PDF. I have just downloaded and unpacked <a href="http://www.digitaljunkies.ca/dompdf/about.php">domPdf</a> on my WAMP and it worked right away.<br /><br />Ok I had to disable php_domxml.dll first but after that it worked perfectly. Well almost, since there seems to be a problem with special characters. I guess I need to import some additional forms first before this works correctly.<br /><br />Anyhow this API is a big step forward for PHP developers trying to find an easy and convenient way to create PDFs from what they know best: PHP and HTML.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1107085320083675742005-01-30T13:34:00.000+01:002006-08-10T07:47:57.080+02:00Featured Tutorial Series - Client Side Tag LibsClient Side Tag Libraries (CSTL) are a JavaScript based infrastructure that enables web developers and designers to employ custom tags into a (X)HTML page. Custom tags are mainly used to have easy access to sophisticated UI components. Underneath CSTLs are based on JavaScript classes that provide object oriented features like inheritance, polymorphism etc. and on top of that are easily distributable and redistributable across even across domains.<br /><br />A TagLib enhanced (X)HTML document needs to loads the so called TagLibProcessor, as an external JavaScript file. The processor then looks for TagLibs registered in the <head> section of the document. After loading the TagLibs, the DOM is traversed finding and processing all custom tags – which should be XML namespaced.<br /><br />A custom tag brings with it a convenient manner to create UI components in a JavaScript class, by either direct and eased DOM modification or even easier (X)HTML generation. Also you can bind variables to custom tag attributes that may refer to JavaScript variables, objects and functions, which are resolved into their real values behind on demand. Also every tag can be independently refreshed, either on a timed basis or in reaction to events, always serving you the current variable situation. This is the base for great flicker free user experiences.<br /><br /><pre class="block"><html><br /> <head><br /> <script type="text/javascript" src="cstl.js"></script><br /> <cstl:taglib classPath="com.inspirationlabs.taglib.std.StdTagLib" ns="std"/><br /> <script type="text/javascript"><br /> function date() {<br /> return new Date();<br /> }<br /> </script><br /> </head><br /> <body><br /> <std:print var="${date}" refreshRate="1000"><br /> N/A<br /> </std:print><br /> </body><br /></html><br /></pre><br /><a class="article_button left" href="http://dwittenbeck.inspirationlabs.de/downloads/Client%20Side%20Tag%20Libs.pdf">full article</a> <a href="http://dwittenbeck.inspirationlabs.de/downloads/Client%20Side%20Tag%20Libs.zip" class="article_button right">download files</a>WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1105436706245431782005-01-11T10:39:00.000+01:002005-01-11T10:45:59.230+01:00How those articles are comingI was <a href="http://eapps.blogspot.com/2004/12/upcoming-articles-on-this-blog.html">promising some articles</a> and yes I didn't forget. In fact I am currently working hard on it. Just wanna make it sure that the example code behind the article is at least beta. Currently I am still working a little on the TagLibs as there are some small issues. Yesterday I had to completely rewrite my JavaScript class-building framework as I seem to have forgotten about static method inheritance.
<br />
<br />But I have also started writing a good piece. The first article will be about the Client Side TagLibs (CSTL), which are probably the most "revolutionary" idea. After that I will probably get the JavaScript class-building framework (the base for it all) on the road. I hope that some of that will happen this week ;-)WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1104409481333414762004-12-30T13:01:00.000+01:002004-12-30T13:31:27.816+01:00Integrating instant messengers into a websiteWebsites are an asynchronous media. You visit you view and maybe write a mail either via your e-mail client or via a web form. But there are times, when you want to be contacted synchronously. Some people just like being available to the world, others (e.g. sales representatives) want to have a way to directly be in contact with their customers. Whatever reason you might have to provide a synchronous contact to yourself. Here are various ways to do it.
<br />
<br /><h4>ICQ (<a href="http://www.icq.com/download/">download</a>)</h4>
<br />I don't know if this is still the best or even a good IM but I started out with it and now I am stuck. However ICQ is very omnipresent.
<br />
<br /><i>Message Center</i>
<br />All of the techniques described here are also accessible though a user's message center. This is basically a web page located at
<br />
<br /><a href="http://www.icq.com/whitepages/wwp.php?uin=98057455">http://www.icq.com/whitepages/wwp.php?uin=98057455</a>
<br />
<br />which stores about all information about the user.
<br />
<br /><i>Sending a message</i>
<br />If you also have ICQ installed you can have links everywhere on the web which will open up your ICQ providing a chat window to the addressent. Those links must look like this:
<br />
<br /><a href="http://www.icq.com/whitepages/cmd.php?uin=98057455&action=message">http://www.icq.com/whitepages/cmd.php?uin=98057455&action=message</a>
<br />
<br /><i>Adding user to your contact list</i>
<br />Same thing as above: Interaction with your ICQ to add a user. Uses the following link:
<br />
<br /><a href="http://www.icq.com/whitepages/cmd.php?uin=98057455&action=add">http://www.icq.com/whitepages/cmd.php?uin=98057455&action=add</a>
<br />
<br />to do so.
<br />
<br /><h4>Skype (<a href="http://www.skype.com/download/redirect">download</a>)</h4>
<br />Skype is currently the best tool I know for VOIP-Telephoning. Recently with their first stable release, you can also globally call into the telephony-networks. It uses pretty little bandwidth and is completely free of charge if you stay on peer-to-peer VOIP-calls.
<br />
<br /><i>Calling a user</i>
<br />You can embed simple links into your website, which (if Skype is installed on the client) open up Skype and initiate a call to the user. The Links must look like this:
<br />
<br /><a href="callto://WittRaider">callto://WittRaider</a>
<br />
<br /><h4>AIM (<a href="http://www.aol.de/instantmessenger/download/index.jsp">download</a>)</h4>
<br />AOL Instant Messenger was probably second most popular, when I was using it back a few years ago.
<br />
<br /><i>Send a message</i>
<br />Just like with ICQ you can directly send a message through you client installation of AIM to the addressent by clicking a link like:
<br />
<br /><a href="aim:goim?screenname=WittRaider&message=hello">aim:goim?screenname=WittRaider&message=hello</a>
<br />
<br /><h4>Others</h4>
<br />I know that I have currently been missing out on other instant messengers like MSN or Yahoo now. Sorry for that maybe later. Also you may always want to integrate a chat, possibly on an IRC base.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1104225496331638342004-12-28T10:02:00.000+01:002004-12-28T10:18:33.070+01:00Upcoming articles on this blogI just wanted to inform you what to expect on this blog in the next days/weeks. I have been experimenting with three main subjects over the last weeks, which I now want starting to present to the world ;-)
<br />
<br /><h4>JavaScript classes and code distribution</h4>
<br />As a preparation for the following two subjects I have implemented JavaScript classes, meaning I have been looking around the web and aggregating method how to create JavaScript structures which behave like classical object oriented classes providing features such as inheritance, polimorphism and the likes. Also I wanted classes to be distributable in multiple files across multiple servers and still be loadable on the fly, in order to increase cross-domain reusability of JavaScript objects.
<br />
<br /><h4>Interaction between JavaScript and Flash</h4>
<br />This became critical when designing the MP3-Player for the <a href="http://music-domiwitt.blogspot.com/">music section</a> of this homepage. I wanted a generic way to interact with <a href="http://www.macromedia.com/software/flash/">Macromedia Flash</a> objects via JavaScript guaranteeing a bidirectional communication via remote function calls and distributed event publishing, even across the domain scripting border and across all browsers I use (being <a href="http://www.microsoft.com/windows/ie/default.asp">Internet Explorer</a>, <a href="http://www.mozilla.org">Mozilla</a>/<a href="http://channels.netscape.com/ns/browsers/download.jsp">Netscape</a> and <a href="http://www.opera.com/">Opera</a>).
<br />
<br /><h4>Client-sided TagLibs</h4>
<br />Developers in touch with <a href="http://java.sun.com/j2ee">J2EE</a> or at least <a href="http://java.sun.com/jsp">JSP</a> know <a href="http://java.sun.com/products/jsp/jstl/">JSTL (Java Standard TagLib)</a>, also know about the power to such a templating language. Now there are mechanisms which allow tag lib type technology on the client using JavaScript. Sound interesting? It certainly is! So stay tuned on this blog!WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1101569279525887772004-11-27T16:27:00.000+01:002004-11-27T16:30:12.606+01:00The Addison-Wesley Signature Series<a href="http://www.awprofessional.com/series/series.asp?st=44126">The Addison-Wesley Signature Series Series</a> is a great series of books for anyone interested in enterprise application architectures and whose daily work is designing and maintaining those systems.
<br />
<br />I personally own three books of the series and each one is both a great reference and a well entertaining piece of literature as well. So let me introduce the three to you.
<br />
<br /><h4><a href="http://www.awprofessional.com/title/0321127420">Patterns of Enterprise Application Architecture</a></h4>
<br /><em><a href="http://www.awprofessional.com/authors/bio.asp?a=8877bf0c-92bd-4d0d-8317-d67fe8b88eee">by Martin Fowler</a></em>
<br />
<br />As the title states the book focusses on enterprise application architecture patterns. It's one of the eariler books of the author. The first 100 pages or so build up typical scenarios and face you with the typical problems with enterprise applications. At that time Martin probably had more a focus in the backend and infrastructure. Therefore the typically 3-tiered approach comes a little short on business logic tier and presentation tier (still about 100 pages about those subjects and great patterns to deal with common problems).
<br />What Mr Fowler really focuses this book on are relational database to domain model mapping patterns and concurrency issues that occur when more than one person tries to manipulate the same data or access a transactional service.
<br />Since at the time I bought this book I was quite firm on the presentation tier and were just building a generic relational database to object mapping and persistence layer the book was absolutely perfect for me. I dug it! And you will, too! This book is perfectly structured. After the motivation part which introduces the main issues patterns to solve those issues are presented in a reference manner. Also the author puts great emphasis on educating the reader when to use specific patters. Basically all patterns also have a reference implementation either in Java or C#.
<br />
<br /><h4><a href="http://www.awprofessional.com/title/0321200683">Enterprise Integration Patterns</a></h4>
<br /><em>by <a href="http://www.awprofessional.com/authors/bio.asp?a=1ebf95e7-b1ac-41d7-a925-6304c8443347">Gregor Hohpe</a>, <a href="http://www.awprofessional.com/authors/bio.asp?a=4b82ca2f-cdac-4aee-84db-586cc498ccc5">Bobby Woolf</a></em>
<br />
<br />The first book of the series I bought is a perfect addition to the <a href="http://www.awprofessional.com/title/0321127420">Patterns of Enterprise Application Architecture</a> just introduced. It focusses on Service Oriented Architectures. The structure is basically identical to the previous one. An introductionary chapter makes you acquainted with the basic facts of life that occur in distributed applications.
<br />I was pretty happy about the fact that this book does not focus on Web Services only but instead tries to explain, which technology is well suited in which cases of a messaging architecture.
<br />This book also can be used as a reference as it introduces patterns in a way that suites this need.
<br />Alltogether this is also a brilliant book which is worth buying if you have to deal projects which are not planned on the green but have to coexist, leverage and interconnect existing software architectures.
<br />
<br /><h4><a href="http://www.awprofessional.com/title/0201775948">Beyond Software Architecture</a></h4>
<br /><em>by <a href="http://www.awprofessional.com/authors/bio.asp?a=bb6d8118-b79d-49ff-865e-189762f5eda6">Luke Hohmann</a></em>
<br />
<br />This book unlike the other ones in the series is not intended for the developer or at least it does not intend to solve technical issues. It rather focusses on the facts how software is, can and should be developed not to built the ideal solution to a problem but rather to build a solution that fits the user requirements. Yeah, techies tend to ingnore the end-users more and more the more they start loving their creation. This is a dangerous path to go down since your ideals seldomly put food on your plate.
<br />This book also does not ignore the fact that when the first requirements are stated by the customer, he probably has a rather vague idea of the final process or functionality he needs. In this context the book also focusses on delivery managment, iterative development of user requirements and product delivery and states roles which a team of developers need to take, when wanting to create a so called winning solution.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1101542980703589802004-11-27T09:04:00.000+01:002004-11-27T12:55:45.603+01:00Need to finish the previous articleAnd there it is: sloppyness again. I was going to finish the article on "Threading in a Windows environment" this week but work got me pretty busy. Currently have two projects at the same customer and those keep me busy as hell. Especially since I am the only consultant on the team of my employer <a href="http://www.snp.de">SNP</a> at the customers site. The naggy thing is that I am not so much busy coding but more coordinating going-lives of software and stuff.
<br />
<br />I really hate all the formal processes you need to go through in big companies. In my opinion processes should be defined to support you work and guide you to do work correcly. However this drastically loses it's sense when because of a complex process involving many parties, you start forgetting what you were originally doing.
<br />
<br />Anyhow, this is why I didn't get to finish the entry this week, hope that next week will be better.WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1101137803077998052004-11-22T16:33:00.000+01:002004-12-02T22:45:15.890+01:00Threading in an Windows environment<h4>Motivation</h4>
<br />Every now and then someone drops off a question and zend.com and the likes, asking is multi-threading in a Windows environment would ever be possible. Usually the answer that poor person is getting sounds something like:
<br />
<br /><em>"PHP is good for the web and multi-threading is not for the web, since the web is usually about synchronous user dialogs"</em>
<br />
<br />In my opinion this is first of all not true: The Web is not just about synchronous user dialogs. It's about asynchronous user dialogs as well, although addmittedly they are not handeled very well by the request-response paradigm which is inheritly synchronous. This is stressed by the fact that no browser I know implements HTTP-Server capabilities and therefore simulating asnychronous processes usually involves JavaScript triggered polling, via page/frame/iframe-reloading or remote scripting.
<br />
<br />Why be asynchronous if all you use it for is a progress meter? As far as I (and I guess the majority of end-users) see it. An asynchronous procress is something you trigger and that you them may leave alone on it's own. Eventually you are going to collect a status or some pop-up will show up. Besides the latter case (which would involve polling by the client or a bi-directional connection), asynchronous processes may very well be triggered on the web. And especially when you want your application to process some really long running tasks you will need that functionality.
<br />
<br />Currently people tend to tell you, that can execute an external binary or dispatch a request to another daemon - and those things should be written in a stable more daemon-oriented language than PHP, I am saying that for some purposes PHP is well enough sufficient for daemon-type jobs.
<br />
<br />If for instance you are writing a newsletter-software which should be capable not only of maintaining newsletters, recipient-lists and such in a database and make those thing accessible via a pretty frontend, but also want to use PHP to do the ground work and send off those emails you will probably have a hard time. Possibly you want to be able to send more than one newletter at a time - so there already you have parallel processing.
<br />
<br />Under *nix systems you will probably be quite familiar with pcntl_fork() and all that is around that. <a href="http://www.amazon.com/exec/obidos/tg/detail/-/0672325616/qid=1101122931/sr=1-4/ref=sr_1_4/104-1367492-9602343?v=glance&s=books">"Advanced PHP Programming"</a> by <a href="http://www.schlossnagle.org/~george/blog/">George Schlossnagle</a> - which I like a lot - has a whole chapter about writing daemons in an *nix environment. But what if you'd like to do the same under windows? Well it's ain't quite easy but it can be done - and this is how:
<br />
<br /><h4>Solution - Overview</h4>
<br />The basic idea is about spawning new processes via the command line interface of PHP and keeping communications via a shared buffer (either shared memory or even file based). You will also have to have some interrupt mechanism on the spawned processes to become able to control the process from the outside. While there might be some trap doors along the way, you can still do all you need, even in PHP4 (4.3.0+ if you use <a href="http://www.php.net/debug_backtrace">debug_backtrace()</a> along the way).
<br />
<br />Of course we want to have a nicely playing object oriented way of dealing with the issue, so let's have a abstract class for that. Instances of this class will be used on the parental process to control a spawned thread as well as bear the implementation of the thread as well. In the end we would like to use our thread something Java-like, like this:
<br />
<br /><pre class="block">// instanciating an implemented WinThread proxy
<br />$thread = &new WinThreadImpl("arg1","arg2","arg3");
<br />
<br />// starts the thread
<br />$thread->start(WinThread_ASTHREAD);
<br />
<br />// we may set the thread to sleep
<br />$thread->suspend();
<br />
<br />// and resume it again
<br />$thread->resume();
<br />
<br />// if we don't stop a thread which
<br />// was not started as a daemon explicitly
<br />// the parent script will eventually wait
<br />// for it's spawn to exit before it can
<br />// exit itself
<br />$thread->stop();
<br /></pre>
<br />Or maybe we would like to create a daemonized thread which can outlive it's parent and is therefore well suited for asynchronous processing. While all of the above control mechanisms work perfectly fine also for this fellow, I would like to introduce some additional ones (which would also work in both cases).
<br />
<br /><pre class="block">// instanciating an implemented WinThread proxy
<br />$thread = &new WinThreadImpl("arg1","arg2","arg3");
<br />
<br />// starts the thread as a daemon
<br />$thread->start(WinThread_ASDAEMON);
<br />
<br />// getting the pid of the process
<br />echo $thread->getPid()."\n";
<br />
<br />// usually the parent would exit if a daemonized
<br />// thread is not explicitly collected
<br />while($thread->collect()) {
<br /> echo "Thread is still running...\n";
<br /> sleep(1);
<br />}
<br /></pre>
<br /><h4>Solution - Detail</h4>
<br />So let's look under the hood of that beast. In the first example naturally the constructor is called first.
<br />
<br /><pre class="block">/*<WinThread>*/ function &WinThread() {
<br /> $this->_parameters = $this->getConstructorParameters();
<br /> if($this->iAmTheParent()) {
<br /> $this->initializeSharedContext($this->generateRandomId());
<br /> }
<br />}
<br /></pre>
<br />First the constructor finds out which parameters were passed to it. This is simply a convenience function, which is implemented based on <a href="http://www.php.net/debug_backtrace">debug_backtrace()</a>.
<br />The iAmTheParent() method simply checks based on environment information if it is currently running as the proxy/parent (as it is the case here) or as the thread/child process. In the prior case some shared context buffer is initialized based on a now randomly generated unique identifier. This context will later be used to enable communications between parent and child.
<br />
<br />Next the thread is started (in thread-mode; meaning that the parental process waits for the child to exit at the end of it's processing time). The implementation of start() looks like this
<br />
<br /><pre class="block">>/*<void>*/ function start(/*<bool>*/ $asDaemon = FALSE) {
<br /> if($this->iAmTheParent()) {
<br /> //building command parameters
<br /> $classPath = $this->getClassPath();
<br /> $constructorParams = base64_encode(serialize($this->_parameters));
<br /> $launchScript = realpath(__FILE__);
<br /> $execCommand = WinThread::getInterpreterPath().
<br /> " \"".$launchScript."\"".
<br /> " \"launchAsThread\"".
<br /> " \"".$this->_id."\"".
<br /> " \"".$classPath."\"".
<br /> " \"".$constructorParams."\"".
<br /> " \"".(int)$asDaemon."\"";
<br /> //prefix command if the thread needs to run as a daemon
<br /> if($asDaemon) {
<br /> $execCommand = "start /B ".$execCommand;
<br /> }
<br /> //starting the external process
<br /> $this->_process = @popen($command,"r");
<br /> if($this->_process) {
<br /> //hold as long as the sub process has indicated that it
<br /> //is running by creating one byte of output
<br /> fread($this->_process, 1);
<br /> }
<br /> }
<br />}
<br /></pre>
<br />First of all the current classpath is fetched. This may be the absolute path to the current class or some other addressing mechanism. Just remember that it is the address of <code>WinThreadImpl</code> not <code>WinThread</code>.
<br />Also the parameters of the constructor which will later be needed in the child process need to be fetched, serialized and packaged so they can be passed along with the command line.
<br />The script to launch is actually the current file (<code>WinThread</code>). As this should encapsulate all technical core necessary for the thread to run. This will actually some executable code aside of the class implementation, which will conditionally be run. It's actually just necessary to have a well known, absolute address which the command line may take as an argument for the callable script that executes the thread.
<br />The <code>$executionCommand</code>, which is now built needs to contain all the information necessary to run the thread. The path to the interpreter can be derived from environment information most of the times. Although this may in fact be a little bit tricky, this is beyond the scope of this article.
<br />The only parameter this script takes which needs to be explained is the literal <code>launchAsThread</code>. This will in the child process be used as an indicator that this is in fact the child process and is the base for <code>iAmTheParent()</code> and <code>iAmTheThread()</code> type methods.
<br />If a process is to be run as a daemon, and thereby be detached from the lifecycle of it's parent, the DOS command <code>start /B</code> may be used to prefix any existing command. <code>start</code> would open a new command-line instance, while the option <code>/B</code> would make it run in the background rather than having a new window popping open.
<br />Finally the command is triggered using the simple <a href="http://www.php.net/popen">popen()</a> instruction, set to read input. This pipe will be used to stop the parent process until the thread has passed it's initialization phase.
<br />
<br />Now that we have started the thread from a parent perspective we still need to know how all of this works from the child process perspective.
<br />
<br /><pre class="block">declare(ticks=2);
<br />
<br />class WinThread {
<br />
<br /> [...]
<br />
<br /> /*static*/ /*<void>*/ function launch(/*<array*/ $argv) {
<br /> if($argv[1] == "launchAsThread") {
<br /> //get command line parameters
<br /> $id = $argv[2];
<br /> $classPath = $argv[3];
<br /> $parameters = unserialize(base64_decode($argv[5]));
<br /> $isDaemon = (bool)$argv[6];
<br /> $className = WinThread::getClassFromClassPath($classPath);
<br /> //importing/including the required class(es)
<br /> Framework::imports($classPath);
<br /> //instanciate the thread
<br /> $thread = &new $class($parameters[0],
<br /> $parameters[1],
<br /> $parameters[2],
<br /> $parameters[3],
<br /> $parameters[4],
<br /> $parameters[5],
<br /> $parameters[6],
<br /> $parameters[7],
<br /> $parameters[8],
<br /> $parameters[9]);
<br /> //initialize the shared context
<br /> $thread->initializeSharedContext($id);
<br /> //publish state to shared context
<br /> $thread->publishIsDaemon();
<br /> $thread->publishPid(getmypid());
<br /> $thread->publishIsRunning();
<br /> //enable the interrupt method for this process
<br /> $thread->enableInterrupt();
<br /> //echo one byte so that the main process knows that it's thread has started
<br /> echo "1\n";
<br /> //call the thread implementation callback method
<br /> $thread->run();
<br /> //stopping the thread automatically after it has been processed
<br /> $thread->stop();
<br /> }
<br /> }
<br />}
<br />
<br />WinThread::launch($argv);
<br /></pre>
<br />First we need to <code>declare(ticks=2)</code> so we are later able to plug in interrupt methods using <a href="http://www.php.net/register_backtick_function">register_backtick_function()</a>. So now the first argument after the script name is <code>launchAsThread</code> is enough indication that the thread should be started. First all parameters that were dropped into the command line call are extracted and correctly interpreted.
<br />
<br />[to be continued]
<br />
<br /><h4>What to bear in mind</h4>
<br /><ul>
<br /><li>This is simplified demonstration code. The real thing works quite nice I can assure you, however there are some details not shown in the presented implmenetation</li>
<br /><li>I am using a programming library that I am putting together now for about 3 years. It lives on a one-class-per-file paradigma. At it's core it has a Java-like mechanism to import classes as prerequisites to other classes. All methods on the Framework-class pretty much state what they do. How the Framework works and how this helps the implementation of design patterns will be discussed in another article</li>
<br /><li>This implementation assumes the existence of a context in the application scope for each thread running. How to implement such a context will be issue of another article. There are basically two efficient variants to do this.
<br /><ul>
<br /><li>Shared memory: Using shared memory under windows is currently a tricky beast since you may easily run into the memory-leak trap. However it's easier on you CPU-cycles.</li>
<br /><li>Files: Using files you have to make sure that you do not corrupt them by concurrent write access or create inconsistent reads. How to easily create concurrency-resistent ressources will be topic of another article.</li></li>
<br /></ul>
<br /><li>The usleep() function does not work correctly under Windows until PHP5. And not having it will be a critical hit in performance of other applications since CPU will be used to it's max. There is a workaround using fsockopen() on <a href="http://www.php.net/usleep">php.net</a> for windows. But this heavily leaks memory if you try to use it in threads.</li>
<br /><li>Remember that you are actually doing multi-processing here not multi-threading. Sinch each process is spawned completely self-contained, it will consume just as much RAM as it's parental process. This is due to the fact that the PHP runtime and libraries are yet again instanciated for each process.</li>
<br /></ul>
<br /><h4>Reference Coding</h4>
<br />Up for now is the reference implementation, that currently exists in my application framework. Don't get confused. Yes, I lean a little towards Java-style syntax.
<br />
<br /><pre class="block"><?php
<br />
<br />//*** begin: launch script *********************************************************************
<br />if($argv[1] == "launch") {
<br /> require_once($argv[2]); //includes the framework if this is run as a stand-alone
<br /> declare(ticks=2);
<br />}
<br /> //*** end: launch script ***********************************************************************
<br />
<br />Framework::imports("net.developaz.DAPI");
<br />Framework::imports("net.developaz.context.ApplicationContext");
<br />Framework::uses("php","4.3.0");
<br />
<br />declare("WinThread_ASDAEMON",TRUE);
<br />declare("WinThread_ASTHREAD",TRUE);
<br />
<br />/**
<br /> @version: 0.1.5
<br />
<br /> This abstract class implements 'threads' for windows systems via
<br /> multiple process spawned on the CLI.
<br />*/
<br />/*abstract*/ class WinThread extends DAPI {
<br />
<br /> //*** ATTRIBUTES ****************************************************************************
<br /> /*private*/ /*<ref>*/ var $_process;
<br /> /*private*/ /*<array>*/ var $_parameters = array();
<br /> /*private*/ /*<bool>*/ var $_iamathread = false; //indicator for thread vs. environment
<br /> /*private*/ /*<ApplicationContext>*/ var $_context;
<br />
<br /> //*** CONSTRUCTOR ***************************************************************************
<br /> /**
<br /> The constructor of this thread may be called to construct the
<br /> */
<br /> /*<WinThread>*/ function &WinThread() {
<br /> //$this->_parameters = func_get_args();
<br /> $arr = debug_backtrace();
<br /> $this->_parameters = ($arr[0]['args'])?$arr[0]['args']:$arr[1]['args'];
<br /> if(!$_ENV['thread']) {
<br /> $this->setId(md5(uniqid(rand(), true)));
<br /> } else {
<br /> $this->setAsThread();
<br /> $this->debug("starting as a thread");
<br /> }
<br /> }
<br />
<br /> //*** ABSTRACT METHODS **********************************************************************
<br /> /**
<br /> Abstract method that has to be extended and implements the thread's business logic
<br /> */
<br /> /*abstract*/ /*<void>*/ function run() { }
<br />
<br /> //*** PRIVATE METHODS ***********************************************************************
<br /> /**
<br /> Sets a flag that indicates that this is the real instance of the thread and not the stub
<br /> */
<br /> /*private*/ /*<void>*/ function setAsThread() {
<br /> $this->_iamathread = true;
<br /> }
<br />
<br /> /**
<br /> Sets the internal ID of the process which is primarily used to identify the correct
<br /> context which is used to access data
<br /> */
<br /> /*private*/ /*<void>*/ function setId(/*<string>*/ $id) {
<br /> $this->_id = $id;
<br /> $contextName = "Process.".ucfirst(get_class($this))."Context.".$this->_id;
<br /> $this->_context = &ApplicationContext::instance($contextName);
<br /> }
<br />
<br /> /**
<br /> Publishes the PID of the process
<br /> */
<br /> /*private*/ /*<void>*/ function publishPid(/*<int>*/ $pid) {
<br /> $this->debug("setting pid: $pid");
<br /> $this->_context->set("pid",$pid);
<br /> }
<br />
<br /> /**
<br /> Publishes the info that the process is done
<br /> */
<br /> /*private*/ /*<void>*/ function publishIsDone() {
<br /> $this->_context->set("__isStarted",0);
<br /> $this->_context->set("__isRunning",0);
<br /> $this->debug("this thread is done");
<br /> }
<br />
<br /> /**
<br /> Publishes the info that the process is running
<br /> */
<br /> /*private*/ /*<void>*/ function publishIsRunning() {
<br /> $this->debug("this thread is running");
<br /> $this->_context->set("__isStarted",1);
<br /> $this->_context->set("__isRunning",1);
<br /> }
<br />
<br /> /**
<br /> Publishes the info that the process is suspended
<br /> */
<br /> /*private*/ /*<void>*/ function publishIsSuspended() {
<br /> $this->debug("this thread is suspended");
<br /> $this->_context->set("__isRunning",0);
<br /> }
<br />
<br /> /**
<br /> Checks for external instructions
<br /> */
<br /> /*private*/ /*<void>*/ function checkForInstructions() {
<br /> do { //this loop will only be executed multiply if the thread is suspended
<br /> $iterate = false;
<br /> $this->wait(20); //this reduces the instruction rate and actually increases performance
<br /> $instruction = $this->getInstruction();
<br /> $this->debug("checking for instruction... $instruction");
<br /> if($instruction && $instruction != "null") {
<br /> switch($instruction) {
<br /> case "doExit":
<br /> $iterate = false;
<br /> $this->stop();
<br /> break;
<br /> case "doSuspend":
<br /> $params = $this->getInstructionParameters();
<br /> $maxMsecs = array_shift($params);
<br /> $this->publishIsSuspended();
<br /> $iterate = true;
<br /> break;
<br /> case "doResume":
<br /> $this->publishIsRunning();
<br /> $iterate = false;
<br /> break;
<br /> default:
<br /> break;
<br /> }
<br /> $this->clearInstruction();
<br /> }
<br /> } while($iterate);
<br /> }
<br />
<br /> /**
<br /> Gets the last instruction for a thread
<br /> */
<br /> /*private*/ /*<string>*/ function getInstruction() {
<br /> return @$this->_context->get("__instruction");
<br /> }
<br />
<br /> /**
<br /> Gets the parameters of an instruction
<br /> */
<br /> /*private*/ /*<string>*/ function getInstructionParameters() {
<br /> return @$this->_context->get("__instructionParams");
<br /> }
<br />
<br /> /**
<br /> Assigns an instruction for the thread
<br /> */
<br /> /*private*/ /*<void>*/ function setInstruction(/*<string>*/ $instruction, /*<array>*/ $parameters = array()) {
<br /> $this->_context->set("__instruction",$instruction);
<br /> $this->_context->set("__instructionParams",$parameters);
<br /> }
<br />
<br /> /**
<br /> Clears the instruction
<br /> */
<br /> /*private*/ /*<void>*/ function clearInstruction() {
<br /> $this->_context->set("__instruction","null");
<br /> $this->_context->set("__instructionParams",array());
<br /> }
<br />
<br /> /**
<br /> Sleeps microseconds
<br /> */
<br /> /*incomplete/private*/ /*<void>*/ function wait(/*<int>*/ $msecs) {
<br /> return;
<br /> //$fp = @fsockopen("udp://localhost",31238,$errno,$errstr,$msecs/1000);
<br /> //if($fp) fclose($fp);
<br /> }
<br />
<br /> /**
<br /> Returns the microtime as a float
<br /> */
<br /> /*private*/ /*<float>*/ function microtime_float() {
<br /> list($usec, $sec) = explode(" ", microtime());
<br /> return ((float)$usec + (float)$sec);
<br /> }
<br />
<br /> /**
<br /> Enables the listener
<br /> */
<br /> /*private*/ /*<void>*/ function enableListener() {
<br /> if($this->isThread() && !$this->_listenerEnabled) {
<br /> register_tick_function(array(&$this,"checkForInstructions"),true);
<br /> $this->_listenerEnabled = true;
<br /> }
<br /> }
<br />
<br /> /**
<br /> Disables the listener
<br /> */
<br /> /*private*/ /*<void>*/ function disableListener() {
<br /> if($this->isThread() && $this->_listenerEnabled) {
<br /> @unregister_tick_function(array(&$this,"checkForInstructions"));
<br /> $this->_listenerEnabled = false;
<br /> }
<br /> }
<br />
<br /> //*** PUBLIC METHODS ************************************************************************
<br /> /**
<br /> From the host this method starts the thread. If a process
<br /> is started as a daemon it is detached from the parent process
<br /> */
<br /> /*<void>*/ function start(/*<bool>*/ $asDaemon = false) {
<br /> if(!$this->isThread()) {
<br /> $class = get_class($this);
<br /> $classes = Framework::get("classPaths");
<br /> $classPath = Framework::path2class($classes[$class]);
<br /> $params = base64_encode(serialize($this->_parameters));
<br /> $launchScript = realpath(__FILE__);
<br /> $framework = str_replace("//","/",Framework::get("root")."/Framework.class.php");
<br /> $command = WinThread::getInterpreterPath()." \"".$launchScript."\" \"launch\" \"".$framework."\" \"".$this->_id."\" \"".$classPath."\" \"".$params."\"";
<br /> //$this->debug($command);
<br /> if($asDaemon) {
<br /> $this->_iamadaemon = true;
<br /> $command = "start /B ".$command." \"1\"";
<br /> }
<br /> $this->_process = @popen($command,"r");
<br /> if($this->_process) {
<br /> fread($this->_process, 1); //hold as long as the sub process has indicated that is is running
<br /> } else {
<br /> $this->setError(2,"could not spawn process");
<br /> }
<br /> }
<br /> }
<br />
<br /> /**
<br /> Stops the process
<br /> */
<br /> /*<void>*/ function stop() {
<br /> if($this->isThread()) {
<br /> $this->disableListener();
<br /> $this->debug("stopping itself");
<br /> $this->publishIsDone();
<br /> exit(0);
<br /> } else {
<br /> $this->debug("stopping from outside");
<br /> $this->setInstruction("doExit");
<br /> }
<br /> }
<br />
<br /> /**
<br /> Gets the PID of the process
<br /> */
<br /> /*<int>*/ function getPid() {
<br /> if($this->isThread()) {
<br /> return getmypid();
<br /> } else {
<br /> return $this->_context->get("pid");
<br /> }
<br /> }
<br />
<br /> /**
<br /> Checks if this instance of the class is the thread itself or the stub in the host process
<br /> */
<br /> /*<bool>*/ function isThread() {
<br /> return (bool)$this->_iamathread;
<br /> }
<br />
<br /> /**
<br /> Checks if this instance of the a daemon
<br /> */
<br /> /*<bool>*/ function isDaemon() {
<br /> return (bool)$this->_iamadaemon;
<br /> }
<br />
<br /> /**
<br /> Checks if a process is done
<br /> */
<br /> /*<bool>*/ function isDone() {
<br /> $started = $this->_context->get("__isStarted");
<br /> return (bool)!$started;
<br /> }
<br />
<br /> /**
<br /> The collecting process waits for a specific sub-process to end
<br /> */
<br /> /*<bool>*/ function collect() {
<br /> if(!$this->isThread()) {
<br /> pclose($this->_process);
<br /> return true;
<br /> } else {
<br /> $this->setError(2,"A thread cannot wait for itself to finish");
<br /> }
<br /> }
<br />
<br /> /**
<br /> This method suspends a thread
<br /> */
<br /> /*<void>*/ function suspend() {
<br /> if(!$this->isThread()) {
<br /> $this->setInstruction("doSuspend");
<br /> }
<br /> }
<br />
<br /> /**
<br /> This method resumes a thread, that has been suspended
<br /> */
<br /> /*<void>*/ function resume() {
<br /> if(!$this->isThread()) {
<br /> $this->setInstruction("doResume");
<br /> } else {
<br /> $this->setError(2,"This thread is already running");
<br /> }
<br /> }
<br />
<br /> /**
<br /> Checks if the current thread is suspend
<br /> */
<br /> /*<bool>*/ function isSuspended() {
<br /> return (bool)!$this->_context->get("__isRunning");
<br /> }
<br />
<br /> /**
<br /> Checks if the current thread is running
<br /> */
<br /> /*<bool>*/ function isRunning() {
<br /> return (bool)$this->_context->get("__isRunning");
<br /> }
<br />
<br /> /**
<br /> Sets a parameter in the context of the thread
<br /> */
<br /> /*<void>*/ function setParameter(/*<string>*/ $name , /*<mixed>*/ $value) {
<br /> $this->disableListener();
<br /> $this->_context->set($name,$value);
<br /> $this->enableListener();
<br /> }
<br />
<br /> /**
<br /> Gets a parameter in the context of the thread
<br /> */
<br /> /*<void>*/ function getParameter(/*<string>*/ $name) {
<br /> $this->disableListener();
<br /> $res = $this->_context->get($name);
<br /> $this->enableListener();
<br /> return $res;
<br /> }
<br />
<br /> //*** STATIC METHODS ************************************************************************
<br /> /**
<br /> Sets the path to the PHP-cli interpreter
<br /> */
<br /> /*static*/ /*<void>*/ function setInterpreterPath(/*<string>*/ $path) {
<br /> $GLOBALS['WINTHREAD_STATIC_VARS']['interpreter'] = $path;
<br /> }
<br />
<br /> /**
<br /> Returns the path to the PHP-cli interpreter
<br /> */
<br /> /*static*/ /*<string>*/ function getInterpreterPath() {
<br /> $interpreter =&$GLOBALS['WINTHREAD_STATIC_VARS']['interpreter'];
<br /> if(!$interpreter) {
<br /> $php_ini = realpath(get_cfg_var('cfg_file_path'));
<br /> $php_dir = dirname($php_ini);
<br /> if(is_file($php_dir."/php-cli.exe")) $interpreter = $php_dir."/php-cli.exe";
<br /> elseif(is_file($php_dir."/cli/php.exe")) $interpreter = $php_dir."/cli/php.exe";
<br /> $interpreter .= " -c \"".$php_ini."\"";
<br /> }
<br /> return $interpreter;
<br /> }
<br />
<br /> /**
<br /> Starts a thread when this class is called as a script from the interpreter
<br /> */
<br /> /*static*/ /*<void>*/ function launch(/*<array*/ $argv) {
<br /> if($argv[1] == "launch") {
<br /> //DAPI::startLogging("log.txt");
<br /> $id = $argv[3];
<br /> $classPath = $argv[4];
<br /> $_ENV['thread'] = true;
<br /> $parameters = unserialize(base64_decode($argv[5]));
<br /> $isDaemon = (bool)$argv[5];
<br /> $class = substr($classPath,strrpos($classPath,".")+1,strlen($classPath));
<br /> Framework::imports($classPath);
<br /> $thread = &new $class($parameters[0],
<br /> $parameters[1],
<br /> $parameters[2],
<br /> $parameters[3],
<br /> $parameters[4],
<br /> $parameters[5],
<br /> $parameters[6],
<br /> $parameters[7],
<br /> $parameters[8],
<br /> $parameters[9]);
<br /> $thread->_iamadaemon = $isDaemon;
<br /> $thread->setId($id);
<br /> $thread->publishPid(getmypid());
<br /> $thread->publishIsRunning();
<br /> $thread->enableListener();
<br /> echo "1\n"; //so that the main process knows that this process has started
<br /> $thread->run();
<br /> $thread->stop();
<br /> }
<br /> }
<br />
<br />}
<br />
<br />//*** begin: launch script *********************************************************************
<br /> WinThread::launch($argv);
<br />//*** end: launch script ***********************************************************************
<br />
<br />?>
<br /></pre>WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.comtag:blogger.com,1999:blog-9264830.post-1101062446536756082004-11-21T19:34:00.000+01:002004-11-21T19:40:46.536+01:00Welcome to my enterprise applications blogHi folks,
<br />
<br />on this blog I am going to spread my thoughts and rants about enterprise application development inside and outside the web-world. While most things that I would like to share are platform-independent most of the implementation example this blog will feature will probably based on PHP (some Java/J2EE and ABAP/SAP) might be included as well.
<br />
<br />I guess this blog will grow pretty quickly since this is the stuff I have to deal with at my job all day long and - needlessly to say - need to wine and rant about. So my entries are also not guaranteed to be 100% objective. Maybe I'll be commenting myself sometimes, once I change my opinion about stuff. I am not perfect as is no human being I know and is nothing that is created by a human mind. Therefore solutions which I once promoted may be worn out and replaced over time.
<br />
<br />Don't take this blog to seriously as well ;-)
<br />WittRaider's Bloghttp://www.blogger.com/profile/05216896734950208670noreply@blogger.com