Thursday, December 30, 2004

Integrating instant messengers into a website

Websites 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.



ICQ (download)



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.



Message Center

All of the techniques described here are also accessible though a user's message center. This is basically a web page located at



http://www.icq.com/whitepages/wwp.php?uin=98057455



which stores about all information about the user.



Sending a message

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:



http://www.icq.com/whitepages/cmd.php?uin=98057455&action=message



Adding user to your contact list

Same thing as above: Interaction with your ICQ to add a user. Uses the following link:



http://www.icq.com/whitepages/cmd.php?uin=98057455&action=add



to do so.



Skype (download)



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.



Calling a user

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:



callto://WittRaider



AIM (download)



AOL Instant Messenger was probably second most popular, when I was using it back a few years ago.



Send a message

Just like with ICQ you can directly send a message through you client installation of AIM to the addressent by clicking a link like:



aim:goim?screenname=WittRaider&message=hello



Others



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.

Under review

I have entered this site into some forums and boards now, so that people start to criticise my site. In case you are one of those people, feel free to leave a comment here as well (even if it's just a reference to your board entry). This way I hope to remember more properly what I still need to do.

Currently I have review entries in the following boards:

Tuesday, December 28, 2004

Upcoming articles on this blog

I 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 ;-)



JavaScript classes and code distribution



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.



Interaction between JavaScript and Flash



This became critical when designing the MP3-Player for the music section of this homepage. I wanted a generic way to interact with Macromedia Flash 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 Internet Explorer, Mozilla/Netscape and Opera).



Client-sided TagLibs



Developers in touch with J2EE or at least JSP know JSTL (Java Standard TagLib), 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!

This site is done... at least the contents exist

Hi all,

finally this site is completed. I have provided content for all the existing sections. This includes media such as the drawings and mp3 streaming via JavaScript and Macromedia Flash. Hope you like all of this! Even if not, don't hesitate to comment the contents of this site and the blogs contained. Hope you find some of the stuff on this page either useful and/or entertaining.

Dominik

Fantasy Interactive (FI)

Fantasy Interactive (FI) - Interactive Design & Development is a great crew of web designers who obviously understand how to take internet to the next level. Specialized in very high quality flash applications, which even outperform most of what I have seen at 2advanced. They are responsible for the roadrunner network site, which a completely new cool flash experience, the ford vehicles site. They quality put in their work is tremendous.



On their site I particularly like the way they show case their major projects. Having a nice HQ-project site together with background info on how the project was completed and which tools were used to tame the beast. Also I like the HQ-FlashVids on the site showing the people behind the scenes, their vision and how they do their work. Great site and worth a look or two.

Monday, December 27, 2004

The ABAP Developer´s Guide to Java

This is the first book that I have officially been named as an author. The ABAP Developer´s Guide to Java is a book which aims at SAP ABAP Developers, who want/need to get into Java and J2EE development - as the new SAP technology platform SAP NetWeaver heavily relies on J2EE technology.



The quote from the sales catalog reads as follows:



"You already know the ropes in the world of ABAP programming. Now, how can you utilize those finely tuned skills to speed up your journey on the road toward Java proficiency?



This all-new reference book is an indispensable guide for readers who need a rapid and in-depth introduction to Java. Detailed insights and step-by-step instruction help you leverage ABAP development skills you’ve already honed, for a smooth transition to Java. The authors highlight each fundamental aspect pertaining to the development of business applications in both languages, and the differences as well as similarities are analyzed in detail. This must-have resource helps any serious developer learn exclusive techniques to master development tools and objects, application design, application layers and much more. Learn about Beans, OpenSQL for Java, JDBC, Security, and that’s just for starters. This unique book helps you save countless hours of trial and error and avoid costly mistakes while quickly advancing your essential Java skills."




With this book I have been responsible for the overall project management during the decisive phases. Also I have written a majority of the chapters. In this sense my work with this project has produced parts of chapter 2, 4 and most or all of chapters 5 through 7. Although the book was written mostly in a hurry and besides daily work, I am pretty happy with the result.



English Releases



buy at SAP-Press.com

buy at Amazon.de



German Releases



buy at SAP-Press.de

buy at Amazon.de

Diploma Thesis - Web Application Design

A Component Framework Based On Web Services



Web Services are an XML-based set of technologies to enable remote function calls over about any web-related transport protocol like HTTP, SMTP or FTP. As it is a specification based on the maxim of extensibility and customizability this technology is also suitable for communication across platforms and programming languages. The key feature that both IT analysts and the businesses put their hopes on is the possibility of supporting the automation of business processes even across company borders and the aggregation of these processes to complete workflows that follow the mechanism of recursive composition which means that a workflow itself can be exposed as a business process to be reused within a more comprehensive system.



All concepts of Web Services are based on standards that are developed and confirmed

by consortiums of independent organizations like the W3C and OASIS consulted by the

industry leaders of infrastructure and ERP software like Microsoft, IBM, SAP, VeriSign and many more. While the terms of service location, registration, data transportation across systems, formatting and embedding into other protocols has been dealt with successfully, security, transaction and meta-descriptive standards have yet to be finalized.



On the basis of this scenario this document develops a concept of a distributable,

scalable, reusable and extensible component architecture that uses Web Services as its foundations. The theoretical model is then implemented using the server-sided scripting language PHP that itself has become the most popular server-sided scripting language for web-related purposes over the last three years. The component architecture thereby adds a model for business logic, encapsulated within distributable entities to the overall concept of multi-tiered application design, like it is popular with enterprise level applications built on the foundations of e.g. J2EE, Microsoft .NET or SAP NetWeaver.



The applicability of the concepts and the model presented is proved through both

example implementations of the basic features and a case study that creates a context

for a Web Service based application.





download the whole document

Monday, December 20, 2004

LAUNCH: Music on Yahoo!

I don't know if many people know this, but I am afraid they don't.

LAUNCH is a music video/entertainem portal on the Yahoo platform. You can get access to the latest music-vids there, have a lot of cool radio stations to tune in and stuff. I really like it although I must admit that I got registered there about 3 years ago long before Yahoo had a part in the portal. Since then performance and reach have decreased a little in my opinion but maybe that is only due to the public exposure.



Anyhow if you were looking for a place to stream your favorite music vids from. Launch is the place to go for you.

Macromedia "On Demand"

Anyone who has been to Macromedia's website in the past year or so must have stumbled over the omipresent Breeze Presentations. Those nice pieces of multimedia, Macromedia uses to provide/broadcast product information in the sense of infotainment. Although I know it's basically advertising I frequently catch myself watching those nice presentations over and over again. Ok, I am a huge fan of Macromedia in general but in my opinion Breeze Presentations are a great alternative to just reading text, especially since audio and video a frequently embedded in those presentations.



As I am a developer (or at least I call myself one) Breeze online tutorials are currently one of the favorite things to watch on the web. You get a little inside/general overview of the products and how to work with them and although it's obviously just advertising, you "just need to stay". It's kinda addictive. At least for me.



Now all those tutorials - called modules - are centrally stored in a searchable library called Macromedia On Demand. So whenever you feel you would need to get to know a little more about the macromedia products launch Macromedia On Demand to get your daily brainwash.

Macromedia Breeze

So I am a huge fan of Macromedia in general. But I particularly like Macromedia Breeze. For about a year now I am fascinated about the various infotainment breeze presentations that are spread around Macromedia.com for almost all subject. I think it's a real benefit to enable you visitors to view presentations and have a truely multimedia experience instead of just having them read text.

Now I have requested a trial account for Macromedia Breeze and I must say that I a quite impressed. It's not that you could not accomplish all of you web conferencing using MS NetMeeting but Breeze comes along so much more integrated into the web. Stop worrying about ports, bandwidth and platform. Breeze is launchable through any browser that has a flash-player 4 or higher installed. Integration into the Microsoft Office Suite is also a snap using the power-point plugin to instantly publish Powerpoint Slides (including audio) to your Breeze server. Also with Outlook integration you can directly scedule meetings in your calendar. An additional feature I like very much is the recording of meeting (either particially or completely) to enable people who could not participate in a meeting access at their convenience.

Breeze is probably best suited for small to medium size teams. But altough I doubt that it's currently effective for broader audience interaction (broadcasting works great as shown multiply on Macromedia.com), I would not know a better tool for realtime collaboration.

Monday, December 13, 2004

First day of my vacation

Ok, this is the first day of my vacation and I am already pissed. I am up since 6 am this morning and had the phone on my ear ever since.

Seems natural that the mother calls on the first day of my vacation, it's even nice that my girl is calling me from work to see what I am doing. But then I got 2 calls from work... wait here is the 3rd one.

Then I got a call from some call-center in Tokyo. WTF!!! I don't exactely know what they were even try to sell me. Their English was just so bad. And where the hell did they get my German phone number from. Very strange and probably very illegal...

Saturday, November 27, 2004

The Addison-Wesley Signature Series

The Addison-Wesley Signature Series Series is a great series of books for anyone interested in enterprise application architectures and whose daily work is designing and maintaining those systems.



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.



Patterns of Enterprise Application Architecture



by Martin Fowler



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).

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.

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#.



Enterprise Integration Patterns



by Gregor Hohpe, Bobby Woolf



The first book of the series I bought is a perfect addition to the Patterns of Enterprise Application Architecture 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.

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.

This book also can be used as a reference as it introduces patterns in a way that suites this need.

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.



Beyond Software Architecture



by Luke Hohmann



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.

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.

Study Paper - Web Application Development

Concepts and Technologies



In a client-server scenario like browser based application development, the Three Tier Model is of extreme importance and is therefore base of the technological discussion within this document.



With the first tier - the presentation layer - accessibility issues and the need to serve client-specific content is discussed. It is explained how template technology helps with the maintenance process of a web-based application and how it is incorporated efficiently into the concurrent development model.



On behalf of the second – the application layer - the overcoming of the statelessness of HTTP is delineated together with related issues such as handling user sessions. In that context also security considerations are discussed at length as they remain very critical to web-based applications, mainly operating on user submitted personal data.



For the data tier the usability of file-based systems is evaluated against database

systems. In this context it is important to understand the meaning of company-spanning data exchange. XML and its transformation via XSLT will be outlined as will unified formats for data exchange. As automated communication of software system is becoming more and more important several methods to do so including SOAP and web-services will be introduced.



After dealing with the technological aspect this document will dive into system

engineering and design. As the main factors influencing web-based application design are the business plan, estimates, communication, usability and maintainability they will be analyzed as to their current importance.



The last topic will deal with the unstructured, the structured and the extreme

programming approaches common in application design. A discussion of their respective

advantages and drawbacks is followed by a concluding assessment of each.



Altogether this document is supposed to give the reader an overview of today’s technologies and concepts dealing with application design in general and web-based application design in particular.





download the whole document

X-Desktop

Just to have another system of the open-source community opposing the closed source solution just presented I have to mention X-Desktop. X-Desktop aims to bring the a skinnable windowing metaphor to the web. And they do that pretty well. The project might not have evolved much since it has been orginially released (about 2 years ago). It's comprised of a few JavaScript files which provide an API to open, close and arrage skinned inline windows on any website.



You probably find some bugs that are worth fixing but basically it's a very stable software all in all. I have started using it, when it first came out and was still published under a non-commercial license. Those guys do not have it so much with licensing and I guess it's still not perfectly clear, how you can utilize the API in commecial projects.

Söhne Mannheims

Usually I don't like German music too much. Especially German folk music (Schlager) gives me the creeps. But there are some exceptions to this general rule. One of them is the new album Zion by Söhne Mannheims (sons of mannem ;-). For all true fans of those guys please forgive me for not having done my homework on them. They pretty much live up as they have Xavier Naidoo amongst them, who is a true star on the sky of German music business.

The music they do is always a little orchestral, which I always like. But it's not only the music but also the lyrics. Always applying much needed social critisism, the lyrics ofter surrounded by christian or biblical themes. Still they manage to go to the top of the charts.

What it comes down to is sophisticated lyrics paired with some really impressive style. Currently this is probably the best, Germany has to offer musicwise as they understand to rock hearts and soul and also having a meaningful message.

Need to finish the previous article

And 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 SNP 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.



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.



Anyhow, this is why I didn't get to finish the entry this week, hope that next week will be better.

Bindows.net

Bindows.net is a client sided rich client application framework, that uses petty much CrossBrowser JavaScript to do really impressive things. It aims to enable developers to code OS-style applications using just XML and deliver them via the browser.



You can use XML to layout your application, and use JavaScript to implement dynamic behaviour for components in their own component model. Components can be embedded pretty easily into existing web site. It's a truely exiting technology, and since x-browser support is available for Internet Explorer and Mozilla I guess the reach of products built with Bindows is pretty great, too.



Although Macromedia Flash can probably deliver better user experiences, Bindows is probably better suited to provide OS-type/styled applications through the web browser.



I have not played around with Bindows too much, but the examples I see in the AppLauncher a very promising. On the downside this is no open-source technology as you need to aquire licenses if you want to use this stuff in production with a commercial project.



I originally came to notice Bindows though the creators original DHTML-website, WebFX, which provides a lot of cross-browser (and also browser specific) widgets components that are written in XHTML and JavaScript. Nice things such a menus, sortable tables, tabbed browsing etc. are available for free here. Not quite as integrated as Bindows. But this stuff got me addicted to, when I used to be a web design script kiddie ;-)

2Advanced Studios

2Advanced Studios is some site you need to love. Everything they do is like a little masterpiece of the web of it's own. They understand to give sites personality by applying new navigation concepts and still you'll never feel lost.

Although I am not too much a fan of the new prophecy design in particular (liked the old one better) I still have to say "hats off" to the great crew behind 2advanced, a name they truely deserve.

Monday, November 22, 2004

Threading in an Windows environment

Motivation



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:



"PHP is good for the web and multi-threading is not for the web, since the web is usually about synchronous user dialogs"



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.



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.



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.



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.



Under *nix systems you will probably be quite familiar with pcntl_fork() and all that is around that. "Advanced PHP Programming" by George Schlossnagle - 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:



Solution - Overview



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 debug_backtrace() along the way).



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:



// instanciating an implemented WinThread proxy

$thread = &new WinThreadImpl("arg1","arg2","arg3");



// starts the thread

$thread->start(WinThread_ASTHREAD);



// we may set the thread to sleep

$thread->suspend();



// and resume it again

$thread->resume();



// if we don't stop a thread which

// was not started as a daemon explicitly

// the parent script will eventually wait

// for it's spawn to exit before it can

// exit itself

$thread->stop();



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).



// instanciating an implemented WinThread proxy

$thread = &new WinThreadImpl("arg1","arg2","arg3");



// starts the thread as a daemon

$thread->start(WinThread_ASDAEMON);



// getting the pid of the process

echo $thread->getPid()."\n";



// usually the parent would exit if a daemonized

// thread is not explicitly collected

while($thread->collect()) {

echo "Thread is still running...\n";

sleep(1);

}



Solution - Detail



So let's look under the hood of that beast. In the first example naturally the constructor is called first.



/*<WinThread>*/ function &WinThread() {

$this->_parameters = $this->getConstructorParameters();

if($this->iAmTheParent()) {

$this->initializeSharedContext($this->generateRandomId());

}

}



First the constructor finds out which parameters were passed to it. This is simply a convenience function, which is implemented based on debug_backtrace().

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.



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



>/*<void>*/ function start(/*<bool>*/ $asDaemon = FALSE) {

if($this->iAmTheParent()) {

//building command parameters

$classPath = $this->getClassPath();

$constructorParams = base64_encode(serialize($this->_parameters));

$launchScript = realpath(__FILE__);

$execCommand = WinThread::getInterpreterPath().

" \"".$launchScript."\"".

" \"launchAsThread\"".

" \"".$this->_id."\"".

" \"".$classPath."\"".

" \"".$constructorParams."\"".

" \"".(int)$asDaemon."\"";

//prefix command if the thread needs to run as a daemon

if($asDaemon) {

$execCommand = "start /B ".$execCommand;

}

//starting the external process

$this->_process = @popen($command,"r");

if($this->_process) {

//hold as long as the sub process has indicated that it

//is running by creating one byte of output

fread($this->_process, 1);

}

}

}



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 WinThreadImpl not WinThread.

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.

The script to launch is actually the current file (WinThread). 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.

The $executionCommand, 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.

The only parameter this script takes which needs to be explained is the literal launchAsThread. This will in the child process be used as an indicator that this is in fact the child process and is the base for iAmTheParent() and iAmTheThread() type methods.

If a process is to be run as a daemon, and thereby be detached from the lifecycle of it's parent, the DOS command start /B may be used to prefix any existing command. start would open a new command-line instance, while the option /B would make it run in the background rather than having a new window popping open.

Finally the command is triggered using the simple popen() instruction, set to read input. This pipe will be used to stop the parent process until the thread has passed it's initialization phase.



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.



declare(ticks=2);



class WinThread {



[...]



/*static*/ /*<void>*/ function launch(/*<array*/ $argv) {

if($argv[1] == "launchAsThread") {

//get command line parameters

$id = $argv[2];

$classPath = $argv[3];

$parameters = unserialize(base64_decode($argv[5]));

$isDaemon = (bool)$argv[6];

$className = WinThread::getClassFromClassPath($classPath);

//importing/including the required class(es)

Framework::imports($classPath);

//instanciate the thread

$thread = &new $class($parameters[0],

$parameters[1],

$parameters[2],

$parameters[3],

$parameters[4],

$parameters[5],

$parameters[6],

$parameters[7],

$parameters[8],

$parameters[9]);

//initialize the shared context

$thread->initializeSharedContext($id);

//publish state to shared context

$thread->publishIsDaemon();

$thread->publishPid(getmypid());

$thread->publishIsRunning();

//enable the interrupt method for this process

$thread->enableInterrupt();

//echo one byte so that the main process knows that it's thread has started

echo "1\n";

//call the thread implementation callback method

$thread->run();

//stopping the thread automatically after it has been processed

$thread->stop();

}

}

}



WinThread::launch($argv);



First we need to declare(ticks=2) so we are later able to plug in interrupt methods using register_backtick_function(). So now the first argument after the script name is launchAsThread 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.



[to be continued]



What to bear in mind





  • 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


  • 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


  • 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.



    • 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.


    • 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.




  • 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 php.net for windows. But this heavily leaks memory if you try to use it in threads.


  • 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.




Reference Coding



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.



<?php



//*** begin: launch script *********************************************************************

if($argv[1] == "launch") {

require_once($argv[2]); //includes the framework if this is run as a stand-alone

declare(ticks=2);

}

//*** end: launch script ***********************************************************************



Framework::imports("net.developaz.DAPI");

Framework::imports("net.developaz.context.ApplicationContext");

Framework::uses("php","4.3.0");



declare("WinThread_ASDAEMON",TRUE);

declare("WinThread_ASTHREAD",TRUE);



/**

@version: 0.1.5



This abstract class implements 'threads' for windows systems via

multiple process spawned on the CLI.

*/

/*abstract*/ class WinThread extends DAPI {



//*** ATTRIBUTES ****************************************************************************

/*private*/ /*<ref>*/ var $_process;

/*private*/ /*<array>*/ var $_parameters = array();

/*private*/ /*<bool>*/ var $_iamathread = false; //indicator for thread vs. environment

/*private*/ /*<ApplicationContext>*/ var $_context;



//*** CONSTRUCTOR ***************************************************************************

/**

The constructor of this thread may be called to construct the

*/

/*<WinThread>*/ function &WinThread() {

//$this->_parameters = func_get_args();

$arr = debug_backtrace();

$this->_parameters = ($arr[0]['args'])?$arr[0]['args']:$arr[1]['args'];

if(!$_ENV['thread']) {

$this->setId(md5(uniqid(rand(), true)));

} else {

$this->setAsThread();

$this->debug("starting as a thread");

}

}



//*** ABSTRACT METHODS **********************************************************************

/**

Abstract method that has to be extended and implements the thread's business logic

*/

/*abstract*/ /*<void>*/ function run() { }



//*** PRIVATE METHODS ***********************************************************************

/**

Sets a flag that indicates that this is the real instance of the thread and not the stub

*/

/*private*/ /*<void>*/ function setAsThread() {

$this->_iamathread = true;

}



/**

Sets the internal ID of the process which is primarily used to identify the correct

context which is used to access data

*/

/*private*/ /*<void>*/ function setId(/*<string>*/ $id) {

$this->_id = $id;

$contextName = "Process.".ucfirst(get_class($this))."Context.".$this->_id;

$this->_context = &ApplicationContext::instance($contextName);

}



/**

Publishes the PID of the process

*/

/*private*/ /*<void>*/ function publishPid(/*<int>*/ $pid) {

$this->debug("setting pid: $pid");

$this->_context->set("pid",$pid);

}



/**

Publishes the info that the process is done

*/

/*private*/ /*<void>*/ function publishIsDone() {

$this->_context->set("__isStarted",0);

$this->_context->set("__isRunning",0);

$this->debug("this thread is done");

}



/**

Publishes the info that the process is running

*/

/*private*/ /*<void>*/ function publishIsRunning() {

$this->debug("this thread is running");

$this->_context->set("__isStarted",1);

$this->_context->set("__isRunning",1);

}



/**

Publishes the info that the process is suspended

*/

/*private*/ /*<void>*/ function publishIsSuspended() {

$this->debug("this thread is suspended");

$this->_context->set("__isRunning",0);

}



/**

Checks for external instructions

*/

/*private*/ /*<void>*/ function checkForInstructions() {

do { //this loop will only be executed multiply if the thread is suspended

$iterate = false;

$this->wait(20); //this reduces the instruction rate and actually increases performance

$instruction = $this->getInstruction();

$this->debug("checking for instruction... $instruction");

if($instruction && $instruction != "null") {

switch($instruction) {

case "doExit":

$iterate = false;

$this->stop();

break;

case "doSuspend":

$params = $this->getInstructionParameters();

$maxMsecs = array_shift($params);

$this->publishIsSuspended();

$iterate = true;

break;

case "doResume":

$this->publishIsRunning();

$iterate = false;

break;

default:

break;

}

$this->clearInstruction();

}

} while($iterate);

}



/**

Gets the last instruction for a thread

*/

/*private*/ /*<string>*/ function getInstruction() {

return @$this->_context->get("__instruction");

}



/**

Gets the parameters of an instruction

*/

/*private*/ /*<string>*/ function getInstructionParameters() {

return @$this->_context->get("__instructionParams");

}



/**

Assigns an instruction for the thread

*/

/*private*/ /*<void>*/ function setInstruction(/*<string>*/ $instruction, /*<array>*/ $parameters = array()) {

$this->_context->set("__instruction",$instruction);

$this->_context->set("__instructionParams",$parameters);

}



/**

Clears the instruction

*/

/*private*/ /*<void>*/ function clearInstruction() {

$this->_context->set("__instruction","null");

$this->_context->set("__instructionParams",array());

}



/**

Sleeps microseconds

*/

/*incomplete/private*/ /*<void>*/ function wait(/*<int>*/ $msecs) {

return;

//$fp = @fsockopen("udp://localhost",31238,$errno,$errstr,$msecs/1000);

//if($fp) fclose($fp);

}



/**

Returns the microtime as a float

*/

/*private*/ /*<float>*/ function microtime_float() {

list($usec, $sec) = explode(" ", microtime());

return ((float)$usec + (float)$sec);

}



/**

Enables the listener

*/

/*private*/ /*<void>*/ function enableListener() {

if($this->isThread() && !$this->_listenerEnabled) {

register_tick_function(array(&$this,"checkForInstructions"),true);

$this->_listenerEnabled = true;

}

}



/**

Disables the listener

*/

/*private*/ /*<void>*/ function disableListener() {

if($this->isThread() && $this->_listenerEnabled) {

@unregister_tick_function(array(&$this,"checkForInstructions"));

$this->_listenerEnabled = false;

}

}



//*** PUBLIC METHODS ************************************************************************

/**

From the host this method starts the thread. If a process

is started as a daemon it is detached from the parent process

*/

/*<void>*/ function start(/*<bool>*/ $asDaemon = false) {

if(!$this->isThread()) {

$class = get_class($this);

$classes = Framework::get("classPaths");

$classPath = Framework::path2class($classes[$class]);

$params = base64_encode(serialize($this->_parameters));

$launchScript = realpath(__FILE__);

$framework = str_replace("//","/",Framework::get("root")."/Framework.class.php");

$command = WinThread::getInterpreterPath()." \"".$launchScript."\" \"launch\" \"".$framework."\" \"".$this->_id."\" \"".$classPath."\" \"".$params."\"";

//$this->debug($command);

if($asDaemon) {

$this->_iamadaemon = true;

$command = "start /B ".$command." \"1\"";

}

$this->_process = @popen($command,"r");

if($this->_process) {

fread($this->_process, 1); //hold as long as the sub process has indicated that is is running

} else {

$this->setError(2,"could not spawn process");

}

}

}



/**

Stops the process

*/

/*<void>*/ function stop() {

if($this->isThread()) {

$this->disableListener();

$this->debug("stopping itself");

$this->publishIsDone();

exit(0);

} else {

$this->debug("stopping from outside");

$this->setInstruction("doExit");

}

}



/**

Gets the PID of the process

*/

/*<int>*/ function getPid() {

if($this->isThread()) {

return getmypid();

} else {

return $this->_context->get("pid");

}

}



/**

Checks if this instance of the class is the thread itself or the stub in the host process

*/

/*<bool>*/ function isThread() {

return (bool)$this->_iamathread;

}



/**

Checks if this instance of the a daemon

*/

/*<bool>*/ function isDaemon() {

return (bool)$this->_iamadaemon;

}



/**

Checks if a process is done

*/

/*<bool>*/ function isDone() {

$started = $this->_context->get("__isStarted");

return (bool)!$started;

}



/**

The collecting process waits for a specific sub-process to end

*/

/*<bool>*/ function collect() {

if(!$this->isThread()) {

pclose($this->_process);

return true;

} else {

$this->setError(2,"A thread cannot wait for itself to finish");

}

}



/**

This method suspends a thread

*/

/*<void>*/ function suspend() {

if(!$this->isThread()) {

$this->setInstruction("doSuspend");

}

}



/**

This method resumes a thread, that has been suspended

*/

/*<void>*/ function resume() {

if(!$this->isThread()) {

$this->setInstruction("doResume");

} else {

$this->setError(2,"This thread is already running");

}

}



/**

Checks if the current thread is suspend

*/

/*<bool>*/ function isSuspended() {

return (bool)!$this->_context->get("__isRunning");

}



/**

Checks if the current thread is running

*/

/*<bool>*/ function isRunning() {

return (bool)$this->_context->get("__isRunning");

}



/**

Sets a parameter in the context of the thread

*/

/*<void>*/ function setParameter(/*<string>*/ $name , /*<mixed>*/ $value) {

$this->disableListener();

$this->_context->set($name,$value);

$this->enableListener();

}



/**

Gets a parameter in the context of the thread

*/

/*<void>*/ function getParameter(/*<string>*/ $name) {

$this->disableListener();

$res = $this->_context->get($name);

$this->enableListener();

return $res;

}



//*** STATIC METHODS ************************************************************************

/**

Sets the path to the PHP-cli interpreter

*/

/*static*/ /*<void>*/ function setInterpreterPath(/*<string>*/ $path) {

$GLOBALS['WINTHREAD_STATIC_VARS']['interpreter'] = $path;

}



/**

Returns the path to the PHP-cli interpreter

*/

/*static*/ /*<string>*/ function getInterpreterPath() {

$interpreter =&$GLOBALS['WINTHREAD_STATIC_VARS']['interpreter'];

if(!$interpreter) {

$php_ini = realpath(get_cfg_var('cfg_file_path'));

$php_dir = dirname($php_ini);

if(is_file($php_dir."/php-cli.exe")) $interpreter = $php_dir."/php-cli.exe";

elseif(is_file($php_dir."/cli/php.exe")) $interpreter = $php_dir."/cli/php.exe";

$interpreter .= " -c \"".$php_ini."\"";

}

return $interpreter;

}



/**

Starts a thread when this class is called as a script from the interpreter

*/

/*static*/ /*<void>*/ function launch(/*<array*/ $argv) {

if($argv[1] == "launch") {

//DAPI::startLogging("log.txt");

$id = $argv[3];

$classPath = $argv[4];

$_ENV['thread'] = true;

$parameters = unserialize(base64_decode($argv[5]));

$isDaemon = (bool)$argv[5];

$class = substr($classPath,strrpos($classPath,".")+1,strlen($classPath));

Framework::imports($classPath);

$thread = &new $class($parameters[0],

$parameters[1],

$parameters[2],

$parameters[3],

$parameters[4],

$parameters[5],

$parameters[6],

$parameters[7],

$parameters[8],

$parameters[9]);

$thread->_iamadaemon = $isDaemon;

$thread->setId($id);

$thread->publishPid(getmypid());

$thread->publishIsRunning();

$thread->enableListener();

echo "1\n"; //so that the main process knows that this process has started

$thread->run();

$thread->stop();

}

}



}



//*** begin: launch script *********************************************************************

WinThread::launch($argv);

//*** end: launch script ***********************************************************************



?>