public void run() {
	
	
	UUID sessionID = this.handleSession_connectionStart( this.userID );

	

	// Do not use the connectionUserID after this point any more! 
	// It's too strong bound to the socketmanager, to which the HTTP handler should not be bound at all (except as a handler).
	// Use the session ID instead to keep the underlying implementations disconnected from the yucca.* package.



	try {

	    // Init HTTP connection ... 
	    HTTPHeaders headers = HTTPHeaders.read( this.socket.getInputStream() );

	    // The CGI handler might use some additional data
	    this.bindHeaderFieldsToSession( sessionID, headers );


	    // Print a dump to the logger
	    for( int i = 0; i < headers.size(); i++ ) {
		this.logger.log( Level.INFO, 
				 getClass().getName() + ".run()",
				 "   HTTPHeaders read. header line [" + i + "]: " + headers.get(i) );
	    }


	    PostDataWrapper postData = null;
	    if( headers.isPOSTRequest() ) {

		Long contentLength = headers.getLongValue( HTTPHeaders.NAME_CONTENT_LENGTH );  // This search is case-insensitive
		this.logger.log( Level.INFO,
				 getClass().getName() + ".run()",
				 "Handling POST data using 'Content-Length': '" + contentLength + "'." );
	    

	   
	    
		// Is there a default value if not passed?
		InputStream postDataInputStream = null;
		if( contentLength == null ) {
		
		    postDataInputStream = new BytePositionInputStream( this.socket.getInputStream() );

		} else {
		
		    postDataInputStream = new ReadLimitInputStream( this.socket.getInputStream(),
								    contentLength.longValue() );


		}


		// Wrap the trailing data into a PostDataWrapper
		postData = new DefaultPostDataWrapper( this.logger,
						       headers,
						       postDataInputStream 
						       );

	    } // END if [is POST request]

	    
	    // Create the response. 
	    // Note that the returned response is ALREADY PREPARED!
	    PreparedHTTPResponse response = this.handler.getResponseBuilder().create( headers, 
										      postData,
										      this.socketID,
										      this.socket,
										      sessionID,    // this.userID,
										      null          // No additionals
										      );
	    // There are some very unlikely cases the server cannot send an error reply (broken error messages, ...).
	    // In these cases the builder returns null (this should not happen but one more check is more secure).
	    if( response == null ) {

		this.logger.log( Level.SEVERE,
				 getClass().getName(),
				 "Cannot handle client request. The ResponseBuilder returned a null-response. This usually indicates fatal runtime errors."
			     );

	    } else {
		
		// System.out.println( "Built response: " + response.toString() );
	    
		// Then execute (this MUST NOT throw any exceptions!)
		this.logger.log( Level.INFO,
				 getClass().getName(),
				 "Going to execute prepared response " + response.toString() );			     
		response.execute();
				
		
		// Dont't forget to clean-up and release the locks!
		this.logger.log( Level.INFO,
				 getClass().getName(),
				 "Going to dispose prepared response " + response.toString() );
		response.dispose();
	    
	    }
	    

	    this.socket.close();

	} catch( EOFException e ) {

	    //e.printStackTrace();
	    this.logger.log( Level.FINER,
			     getClass().getName(),
			     "Cannot handle client request. EOF reached before reaching end-of-headers: " + e.getMessage()
			     );
  
	} catch( IOException e ) {
	    
	    //e.printStackTrace();
	    this.logger.log( Level.FINER,
			     getClass().getName(),
			     "Cannot handle client request. IO error: " + e.getMessage()
			     );
  
	    
	}


	handleSession_connectionEnd( sessionID );

	

    }