<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>proghowto</title>
	<atom:link href="http://proghowto.com/feed" rel="self" type="application/rss+xml" />
	<link>http://proghowto.com</link>
	<description>programming...</description>
	<lastBuildDate>Thu, 12 Jan 2012 15:18:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Move a Private Key Between Two JKS Keystores</title>
		<link>http://proghowto.com/move-a-private-key-between-two-jks-keystore</link>
		<comments>http://proghowto.com/move-a-private-key-between-two-jks-keystore#comments</comments>
		<pubDate>Thu, 12 Jan 2012 15:15:31 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://proghowto.com/?p=167</guid>
		<description><![CDATA[The previous version of the article showed how to move a private key between two JKS key stores. The solution consisted in writing a Java program that would use the KeyStore class to retrieve the key from a JKS keystore &#8230; <a href="http://proghowto.com/move-a-private-key-between-two-jks-keystore">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The previous version of the article showed how to move a private key between two <strong>JKS</strong> key stores.<br />
<span id="more-167"></span></p>
<p>The solution consisted in writing a Java program that would use the <strong>KeyStore </strong>class to retrieve the key from a <strong>JKS</strong> keystore and store it in another one. The destination keystore would be completely rewritten.</p>
<script type="text/javascript"><!--
google_ad_client = "ca-pub-1248311769909722";
/* big proghowto */
google_ad_slot = "7362984964";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<p>With the tool <strong>keytool</strong> bundled with JDK versions 1.5 and newer, the process is possible without writing any program. The -importkeystore command line parameter of the new keytool does just this. Please see the keytool documentation for more information. </p>
<p>Here is the part of the keytool help presenting in detail all the parameters for importkeystore:</p>
<p><code><br />
-importkeystore [-v]<br />
             [-srckeystore <srckeystore>] [-destkeystore <destkeystore>]<br />
             [-srcstoretype <srcstoretype>] [-deststoretype <deststoretype>]<br />
             [-srcstorepass <srcstorepass>] [-deststorepass <deststorepass>]<br />
             [-srcprotected] [-destprotected]<br />
             [-srcprovidername <srcprovidername>]<br />
             [-destprovidername <destprovidername>]<br />
             [-srcalias <srcalias> [-destalias <destalias>]<br />
               [-srckeypass <srckeypass>] [-destkeypass <destkeypass>]]<br />
             [-noprompt]<br />
             [-providerclass
<provider_class_name> [-providerarg <arg>]] ...<br />
             [-providerpath
<pathlist>]<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://proghowto.com/move-a-private-key-between-two-jks-keystore/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AXIS Client Request and Response Logging</title>
		<link>http://proghowto.com/axis-client-request-and-response-logging</link>
		<comments>http://proghowto.com/axis-client-request-and-response-logging#comments</comments>
		<pubDate>Fri, 30 Dec 2011 14:10:59 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://proghowto.com/?p=129</guid>
		<description><![CDATA[You have a Java application consuming a remote SOAP web service and you want to use AXIS 1.* framework. You want to see / log the raw SOAP request / response. In a development or testing environment there are methods &#8230; <a href="http://proghowto.com/axis-client-request-and-response-logging">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>You have a Java application consuming a remote SOAP web service and you want to use AXIS 1.* framework. You want to see / log the raw SOAP request / response.</p>
<p><span id="more-129"></span></p>
<p>In a development or testing environment there are methods that don’t involve any configuration or code change for example a sniffer (if the TCP channel is not encrypted).</p>
<script type="text/javascript"><!--
google_ad_client = "ca-pub-1248311769909722";
/* big proghowto */
google_ad_slot = "7362984964";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<p>There are situations however when logging the soap requests and response/fault is needed in production on a continuous basis, usually for reconciliation purposes. In case of some integration issues, the party providing the service will want to see the actual SOAP messages.</p>
<p>The problem is solved by creating a custom handler and either register it programmatically, or use the client configuration file (<strong>WSDD</strong>).</p>
<p>I believe that adding a custom handler is not enough to justify attaching a client configuration file, therefore will show here the code related solution. BTW, the configuration oriented approach rather than the code based one reduces in my opinion the maintainability (you don&#8217;t see what happens by looking at the code, you cannot add breakpoints everywhere etc).</p>
<script type="text/javascript"><!--
google_ad_client = "ca-pub-1248311769909722";
/* big proghowto */
google_ad_slot = "7362984964";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<h3>The steps are as follows:</h3>
<ul>
<li>Obtain the WSDL document. Copy it locally if you don’ t mind and refer to the local copy when generating the client, so that the project will build even if you are not connected to internet.</li>
<li>Generate the client by using <strong>org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask</strong> ant task</li>
<li>Compile the generated code then pack everything in a jar file for easy handling (“client.jar”)</li>
<li>Create a class implementing <strong>javax.xml.rpc.handler.GenericHandler</strong></li>
<li>Register the class in the client</li>
</ul>
<p>For testing purposes I found a test web service published on web that does some simple math calculation. The WSDL was from the url <strong>http://soaptest.parasoft.com/calculator.wsdl</strong>. The service endpoint is at the url <strong>http://ws1.parasoft.com/glue/calculator</strong>.</p>
<p>Although I don’t want to get in details about how to actually generate the classes, here is the build script I used:</p>
<pre>
&lt;project name="client" default="all" basedir=".."&gt;
	&lt;property name="temp.folder" value="./temp" /&gt;
	&lt;property name="compile.folder" value="./compile" /&gt;
	&lt;property name="client.jar" value="./build-jar/client.jar" /&gt;

	&lt;path id="all.path"&gt;
		&lt;fileset dir="./lib" /&gt;
	&lt;/path&gt;

	&lt;taskdef name="wsdl2java" classname="org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask" classpathref="all.path" /&gt;

	&lt;target name="all"&gt;
		&lt;delete dir="${temp.folder}" /&gt;
		&lt;delete dir="${compile.folder}" /&gt;

		&lt;mkdir dir="${temp.folder}" /&gt;
		&lt;mkdir dir="${compile.folder}" /&gt;

		&lt;wsdl2java verbose="true" debug="true" url="./config/client.wsdl" output="${temp.folder}"/&gt;
		&lt;javac srcdir="${temp.folder}" destdir="${compile.folder}" classpathref="all.path" /&gt;

		&lt;copy todir="${compile.folder}"&gt;
			&lt;fileset dir="${temp.folder}"&gt;
				&lt;exclude name="**/*.java" /&gt;
			&lt;/fileset&gt;
		&lt;/copy&gt;

		&lt;delete file="${client.jar}" /&gt;

		&lt;jar jarfile="${client.jar}"&gt;
			&lt;fileset dir="${compile.folder}" /&gt;
		&lt;/jar&gt;

		&lt;delete dir="${temp.folder}" /&gt;
		&lt;delete dir="${compile.folder}" /&gt;
	&lt;/target&gt;
&lt;/project&gt;
</pre>
<p>I had issues generating the client, that were fixed by removing all the occurences of the attribute <strong>parameterOrder</strong> in the WSDL.</p>
<p>The port type used has the QName with the following parameters:</p>
<ul>
<li>Namespace: http://www.parasoft.com/wsdl/calculator/</li>
<li>Name: ICalculator</li>
</ul>
<h3>The approach without the logging handler</h3>
<p>Following is the code: </p>
<pre>
<pre ID="Classes">
<FONT ID="LN">1    </FONT><A NAME="1"></A><FONT ID="Package">package</FONT> com.proghowto.wsclient.test;
<FONT ID="LN">2    </FONT><A NAME="2"></A>
<FONT ID="LN">3    </FONT><A NAME="3"></A><FONT ID="Import">import</FONT> java.net.MalformedURLException;
<FONT ID="LN">4    </FONT><A NAME="4"></A><FONT ID="Import">import</FONT> java.net.URL;
<FONT ID="LN">5    </FONT><A NAME="5"></A><FONT ID="Import">import</FONT> java.rmi.RemoteException;
<FONT ID="LN">6    </FONT><A NAME="6"></A>
<FONT ID="LN">7    </FONT><A NAME="7"></A><FONT ID="Import">import</FONT> javax.xml.rpc.ServiceException;
<FONT ID="LN">8    </FONT><A NAME="8"></A>
<FONT ID="LN">9    </FONT><A NAME="9"></A><FONT ID="Import">import</FONT> com.parasoft.www.wsdl.calculator.CalculatorLocator;
<FONT ID="LN">10   </FONT><A NAME="10"></A><FONT ID="Import">import</FONT> com.parasoft.www.wsdl.calculator.ICalculator;
<FONT ID="LN">11   </FONT><A NAME="11"></A>
<FONT ID="LN">12   </FONT><A NAME="12"></A><FONT ID="Public">public</FONT> <FONT ID="Class">class</FONT> TestClient {
<FONT ID="LN">13   </FONT><A NAME="13"></A>    <FONT ID="Public">public</FONT> <FONT ID="Static">static</FONT> <FONT ID="Void">void</FONT> main(String[] args) {
<FONT ID="LN">14   </FONT><A NAME="14"></A>        <FONT ID="Try">try</FONT> {
<FONT ID="LN">15   </FONT><A NAME="15"></A>            <FONT ID="New">new</FONT> TestClient().start();
<FONT ID="LN">16   </FONT><A NAME="16"></A>        }
<FONT ID="LN">17   </FONT><A NAME="17"></A>        <FONT ID="Catch">catch</FONT>(Exception e){
<FONT ID="LN">18   </FONT><A NAME="18"></A>            e.printStackTrace();
<FONT ID="LN">19   </FONT><A NAME="19"></A>        }
<FONT ID="LN">20   </FONT><A NAME="20"></A>    }
<FONT ID="LN">21   </FONT><A NAME="21"></A>
<FONT ID="LN">22   </FONT><A NAME="22"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> start() <FONT ID="Throws">throws</FONT> MalformedURLException, ServiceException, RemoteException {
<FONT ID="LN">23   </FONT><A NAME="23"></A>        <FONT ID="SingleLineComment">// get the web service locator and then the service instance.
<FONT ID="LN">24   </FONT><A NAME="24"></A></FONT>        <FONT ID="SingleLineComment">// The url of the endpoint is provided
<FONT ID="LN">25   </FONT><A NAME="25"></A></FONT>        CalculatorLocator locator = <FONT ID="New">new</FONT> CalculatorLocator();
<FONT ID="LN">26   </FONT><A NAME="26"></A>        ICalculator service = locator.getICalculator(<FONT ID="New">new</FONT> URL(<FONT ID="StringLiteral">"http://ws1.parasoft.com/glue/calculator"</FONT>));
<FONT ID="LN">27   </FONT><A NAME="27"></A>
<FONT ID="LN">28   </FONT><A NAME="28"></A>        <FONT ID="SingleLineComment">// we calculate the total between two float parameters
<FONT ID="LN">29   </FONT><A NAME="29"></A></FONT>        <FONT ID="Float">float</FONT> x = <FONT ID="FloatPointLiteral">12.21f</FONT>;
<FONT ID="LN">30   </FONT><A NAME="30"></A>        <FONT ID="Float">float</FONT> y = <FONT ID="FloatPointLiteral">3.35f</FONT>;
<FONT ID="LN">31   </FONT><A NAME="31"></A>
<FONT ID="LN">32   </FONT><A NAME="32"></A>        <FONT ID="SingleLineComment">// call the web service
<FONT ID="LN">33   </FONT><A NAME="33"></A></FONT>        <FONT ID="Float">float</FONT> result = service.add(x, y);
<FONT ID="LN">34   </FONT><A NAME="34"></A>
<FONT ID="LN">35   </FONT><A NAME="35"></A>        <FONT ID="SingleLineComment">// and here is the result
<FONT ID="LN">36   </FONT><A NAME="36"></A></FONT>        print(<FONT ID="StringLiteral">"x = "</FONT> + x);
<FONT ID="LN">37   </FONT><A NAME="37"></A>        print(<FONT ID="StringLiteral">"y = "</FONT> + y);
<FONT ID="LN">38   </FONT><A NAME="38"></A>        print(<FONT ID="StringLiteral">"res = "</FONT> + result);
<FONT ID="LN">39   </FONT><A NAME="39"></A>    }
<FONT ID="LN">40   </FONT><A NAME="40"></A>
<FONT ID="LN">41   </FONT><A NAME="41"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> print(Object current) {
<FONT ID="LN">42   </FONT><A NAME="42"></A>        System.out.println(current);
<FONT ID="LN">43   </FONT><A NAME="43"></A>    }
<FONT ID="LN">44   </FONT><A NAME="44"></A>}
<FONT ID="LN">45   </FONT><A NAME="45"></A></pre>
</pre>
<p>Now, assuming we created the class TestHandler that extends GenericHandler, this is how we write the actual client invocation: </p>
<pre>
<FONT ID="Void">void</FONT> start() <FONT ID="Throws">throws</FONT> MalformedURLException, ServiceException, RemoteException {
<FONT ID="LN">28   </FONT><A NAME="28"></A>        CalculatorLocator locator = <FONT ID="New">new</FONT> CalculatorLocator();
<FONT ID="LN">29   </FONT><A NAME="29"></A>        HandlerRegistry handlerRegistry = locator.getHandlerRegistry();
<FONT ID="LN">30   </FONT><A NAME="30"></A>        QName qname = <FONT ID="New">new</FONT> QName(<FONT ID="StringLiteral">"http://www.parasoft.com/wsdl/calculator/"</FONT>, <FONT ID="StringLiteral">"ICalculator"</FONT>);
<FONT ID="LN">31   </FONT><A NAME="31"></A>
<FONT ID="LN">32   </FONT><A NAME="32"></A>        @SuppressWarnings(<FONT ID="StringLiteral">"rawtypes"</FONT>)
<FONT ID="LN">33   </FONT><A NAME="33"></A>        List chain = handlerRegistry.getHandlerChain(qname);
<FONT ID="LN">34   </FONT><A NAME="34"></A>
<FONT ID="LN">35   </FONT><A NAME="35"></A>        HandlerInfo info = <FONT ID="New">new</FONT> HandlerInfo();
<FONT ID="LN">36   </FONT><A NAME="36"></A>        info.setHandlerClass(TestHandler.<FONT ID="Class">class</FONT>);
<FONT ID="LN">37   </FONT><A NAME="37"></A>
<FONT ID="LN">38   </FONT><A NAME="38"></A>        chain.add(info);
<FONT ID="LN">39   </FONT><A NAME="39"></A>
<FONT ID="LN">40   </FONT><A NAME="40"></A>        ICalculator service = locator.getICalculator(<FONT ID="New">new</FONT> URL(<FONT ID="StringLiteral">"http://ws1.parasoft.com/glue/calculator"</FONT>));
<FONT ID="LN">41   </FONT><A NAME="41"></A>
<FONT ID="LN">42   </FONT><A NAME="42"></A>        <FONT ID="Float">float</FONT> x = <FONT ID="FloatPointLiteral">12.21f</FONT>;
<FONT ID="LN">43   </FONT><A NAME="43"></A>        <FONT ID="Float">float</FONT> y = <FONT ID="FloatPointLiteral">3.35f</FONT>;
<FONT ID="LN">44   </FONT><A NAME="44"></A>
<FONT ID="LN">45   </FONT><A NAME="45"></A>        <FONT ID="Float">float</FONT> result = service.add(x, y);
<FONT ID="LN">46   </FONT><A NAME="46"></A>
<FONT ID="LN">47   </FONT><A NAME="47"></A>        print(<FONT ID="StringLiteral">"x = "</FONT> + x);
<FONT ID="LN">48   </FONT><A NAME="48"></A>        print(<FONT ID="StringLiteral">"y = "</FONT> + y);
<FONT ID="LN">49   </FONT><A NAME="49"></A>        print(<FONT ID="StringLiteral">"res = "</FONT> + result);
<FONT ID="LN">50   </FONT><A NAME="50"></A>    }
</pre>
<p>Please note the following:</p>
<ul>
<li>The handler registry instance is retrieved from the locator</li>
<li>The handler list is filtered to retrieve only the ones associated to the port type in use. The port type is specified by the fully qualified QName (namespace and name).</li>
<li>The TestHandler class is registered by being wrapped in an instance of javax.xml.rpc.handler.HandlerInfo. <strong>A new instance of TestHandler is created every time a service call is placed through the indicated port type</strong>.</li>
</ul>
<p>And now the handler class. Basically there are three methods we are interested in, <strong>handleFault</strong>, <strong>handleRequest</strong>, <strong>handleResponse</strong>. All three methods give the opportunity to change the message on the fly, nevertheless our purpose is to only log it.</p>
<p>Here is the full class. I used logging to stdout for testing purposes, in production will replace this with a call to log4j.</p>
<pre>
<pre ID="Classes">
<FONT ID="LN">1    </FONT><A NAME="1"></A><FONT ID="Package">package</FONT> com.proghowto.wsclient.test;
<FONT ID="LN">2    </FONT><A NAME="2"></A>
<FONT ID="LN">3    </FONT><A NAME="3"></A><FONT ID="Import">import</FONT> java.io.ByteArrayOutputStream;
<FONT ID="LN">4    </FONT><A NAME="4"></A>
<FONT ID="LN">5    </FONT><A NAME="5"></A><FONT ID="Import">import</FONT> javax.xml.namespace.QName;
<FONT ID="LN">6    </FONT><A NAME="6"></A><FONT ID="Import">import</FONT> javax.xml.rpc.handler.GenericHandler;
<FONT ID="LN">7    </FONT><A NAME="7"></A><FONT ID="Import">import</FONT> javax.xml.rpc.handler.MessageContext;
<FONT ID="LN">8    </FONT><A NAME="8"></A><FONT ID="Import">import</FONT> javax.xml.rpc.handler.soap.SOAPMessageContext;
<FONT ID="LN">9    </FONT><A NAME="9"></A>
<FONT ID="LN">10   </FONT><A NAME="10"></A><FONT ID="Public">public</FONT> <FONT ID="Class">class</FONT> TestHandler <FONT ID="Extends">extends</FONT> GenericHandler {
<FONT ID="LN">11   </FONT><A NAME="11"></A>
<FONT ID="LN">12   </FONT><A NAME="12"></A>    <FONT ID="Private">private</FONT> <FONT ID="Static">static</FONT> <FONT ID="Final">final</FONT> <FONT ID="Long">long</FONT> serialVersionUID = -<FONT ID="IntegerLiteral">1088299597212448917L</FONT>;
<FONT ID="LN">13   </FONT><A NAME="13"></A>    <FONT ID="Private">private</FONT> String timeStamp;
<FONT ID="LN">14   </FONT><A NAME="14"></A>
<FONT ID="LN">15   </FONT><A NAME="15"></A>    <FONT ID="Public">public</FONT> TestHandler(){
<FONT ID="LN">16   </FONT><A NAME="16"></A>        timeStamp = Long.toString(System.currentTimeMillis());
<FONT ID="LN">17   </FONT><A NAME="17"></A>    }
<FONT ID="LN">18   </FONT><A NAME="18"></A>
<FONT ID="LN">19   </FONT><A NAME="19"></A>    @Override
<FONT ID="LN">20   </FONT><A NAME="20"></A>    <FONT ID="Public">public</FONT> QName[] getHeaders() {
<FONT ID="LN">21   </FONT><A NAME="21"></A>        <FONT ID="Return">return</FONT> <FONT ID="Null">null</FONT>;
<FONT ID="LN">22   </FONT><A NAME="22"></A>    }
<FONT ID="LN">23   </FONT><A NAME="23"></A>
<FONT ID="LN">24   </FONT><A NAME="24"></A>    @Override
<FONT ID="LN">25   </FONT><A NAME="25"></A>    <FONT ID="Public">public</FONT> <FONT ID="Boolean">boolean</FONT> handleFault(MessageContext context) {
<FONT ID="LN">26   </FONT><A NAME="26"></A>        System.out.println(timeStamp + <FONT ID="StringLiteral">"_fault: "</FONT> + getStringMessage(context));
<FONT ID="LN">27   </FONT><A NAME="27"></A>
<FONT ID="LN">28   </FONT><A NAME="28"></A>        <FONT ID="Return">return</FONT> <FONT ID="Super">super</FONT>.handleFault(context);
<FONT ID="LN">29   </FONT><A NAME="29"></A>    }
<FONT ID="LN">30   </FONT><A NAME="30"></A>
<FONT ID="LN">31   </FONT><A NAME="31"></A>    <FONT ID="Private">private</FONT> String getStringMessage(MessageContext context){
<FONT ID="LN">32   </FONT><A NAME="32"></A>        String res = <FONT ID="Null">null</FONT>;
<FONT ID="LN">33   </FONT><A NAME="33"></A>
<FONT ID="LN">34   </FONT><A NAME="34"></A>        <FONT ID="Try">try</FONT> {
<FONT ID="LN">35   </FONT><A NAME="35"></A>            SOAPMessageContext ctx = (SOAPMessageContext) context;
<FONT ID="LN">36   </FONT><A NAME="36"></A>
<FONT ID="LN">37   </FONT><A NAME="37"></A>            ByteArrayOutputStream stream = <FONT ID="New">new</FONT> ByteArrayOutputStream();
<FONT ID="LN">38   </FONT><A NAME="38"></A>            ctx.getMessage().writeTo(stream);
<FONT ID="LN">39   </FONT><A NAME="39"></A>            <FONT ID="Byte">byte</FONT>[] items = stream.toByteArray();
<FONT ID="LN">40   </FONT><A NAME="40"></A>
<FONT ID="LN">41   </FONT><A NAME="41"></A>            res = <FONT ID="New">new</FONT> String(items);
<FONT ID="LN">42   </FONT><A NAME="42"></A>        }
<FONT ID="LN">43   </FONT><A NAME="43"></A>        <FONT ID="Catch">catch</FONT>(Exception e){
<FONT ID="LN">44   </FONT><A NAME="44"></A>            <FONT ID="SingleLineComment">// nothing - just ensuring the method will not throw an exception in case something is wrong.
<FONT ID="LN">45   </FONT><A NAME="45"></A></FONT>        }
<FONT ID="LN">46   </FONT><A NAME="46"></A>
<FONT ID="LN">47   </FONT><A NAME="47"></A>        <FONT ID="Return">return</FONT> res;
<FONT ID="LN">48   </FONT><A NAME="48"></A>    }
<FONT ID="LN">49   </FONT><A NAME="49"></A>
<FONT ID="LN">50   </FONT><A NAME="50"></A>    @Override
<FONT ID="LN">51   </FONT><A NAME="51"></A>    <FONT ID="Public">public</FONT> <FONT ID="Boolean">boolean</FONT> handleRequest(MessageContext context) {
<FONT ID="LN">52   </FONT><A NAME="52"></A>        System.out.println(timeStamp + <FONT ID="StringLiteral">"_request: "</FONT> + getStringMessage(context));
<FONT ID="LN">53   </FONT><A NAME="53"></A>
<FONT ID="LN">54   </FONT><A NAME="54"></A>        <FONT ID="Return">return</FONT> <FONT ID="Super">super</FONT>.handleRequest(context);
<FONT ID="LN">55   </FONT><A NAME="55"></A>    }
<FONT ID="LN">56   </FONT><A NAME="56"></A>
<FONT ID="LN">57   </FONT><A NAME="57"></A>    @Override
<FONT ID="LN">58   </FONT><A NAME="58"></A>    <FONT ID="Public">public</FONT> <FONT ID="Boolean">boolean</FONT> handleResponse(MessageContext context) {
<FONT ID="LN">59   </FONT><A NAME="59"></A>        System.out.println(timeStamp + <FONT ID="StringLiteral">"_response: "</FONT> + getStringMessage(context));
<FONT ID="LN">60   </FONT><A NAME="60"></A>
<FONT ID="LN">61   </FONT><A NAME="61"></A>        <FONT ID="Return">return</FONT> <FONT ID="Super">super</FONT>.handleResponse(context);
<FONT ID="LN">62   </FONT><A NAME="62"></A>    }
<FONT ID="LN">63   </FONT><A NAME="63"></A>
<FONT ID="LN">64   </FONT><A NAME="64"></A>}
<FONT ID="LN">65   </FONT><A NAME="65"></A></pre>
</pre>
<p>Here are a logged request and response (for readability I added some new lines, however normally they were on one line both of them)</p>
<p><strong>Request</strong></p>
<pre>
1325213680787_request: &lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
&lt;soapenv:Body&gt;&lt;add xmlns="http://www.parasoft.com/wsdl/calculator/"&gt;
&lt;x&gt;12.21&lt;/x&gt;&lt;y&gt;3.35&lt;/y&gt;&lt;/add&gt;
&lt;/soapenv:Body&gt;&lt;/soapenv:Envelope&gt;
</pre>
<p><strong>Response</strong></p>
<pre>
1325213680787_response: &lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"&gt;
&lt;soap:Body&gt;&lt;n:addResponse xmlns:n="http://www.parasoft.com/wsdl/calculator/"&gt;
&lt;n:Result xsi:type="xsd:float"&gt;15.559999&lt;/n:Result&gt;&lt;/n:addResponse&gt;
&lt;/soap:Body&gt;&lt;/soap:Envelope&gt;
</pre>
<h3>Final notes</h3>
<p><strong>Log one artifact on one line only</strong></p>
<p>You want to ensure that whatever you log (request, response, fault) will be logged on one line only, or else, in a multithreaded environment it will be difficult to tell the lines from a transaction from the ones from another transaction. Search for any end of line in the logged result and change it to something else, like \N or similar.</p>
<p><strong>Pair the transaction artifacts</strong></p>
<p>Usually for one transaction there are two items logged, either the request and the response, or the request and the fault. You need a <strong>reliable</strong> method to pair the two artifacts.</p>
<p>A solution: for each transaction, a new instance of the handler (here TestHandler) is created. I created a class attribute that is initialized with some unique value in the class constructor and then ensured this is logged together with the request, response or fault. In our case, for simplicity, I chose <strong>system timestamp</strong> as the attribute value, however in production <strong>you should go for something really unique</strong>, like a random guid generator &#8211; one can be found <a href=”http://www.java2s.com/Code/Java/Development-Class/RandomGUID.htm”>here </a></p>
]]></content:encoded>
			<wfw:commentRss>http://proghowto.com/axis-client-request-and-response-logging/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Iptables redirect port 80 to port 8080</title>
		<link>http://proghowto.com/iptables-redirect-port-80-to-port-8080</link>
		<comments>http://proghowto.com/iptables-redirect-port-80-to-port-8080#comments</comments>
		<pubDate>Fri, 25 Nov 2011 19:01:07 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://proghowto.com/?p=89</guid>
		<description><![CDATA[The problem: You have a linux server Install tomcat or any other application server You don&#8217;t want the application server to run as root, therefore it cannot listen to any of the ports 80 (http) or 443 (https) From outside, &#8230; <a href="http://proghowto.com/iptables-redirect-port-80-to-port-8080">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The problem:</p>
<ul>
<li>You have a linux server </li>
<li>Install tomcat or any other application server</li>
<li>You don&#8217;t want the application server to run as root, therefore it cannot listen to any of the ports 80 (http) or 443 (https)</li>
<li>From outside, though, the application server must be accessible on ports 80 / 443</li>
</ul>
<p><span id="more-89"></span></p>
<p>The most popular approach:</p>
<ul>
<li>Create an ordinary user specificaly for the application server (ex: tomcat)</li>
<li>Configure it to listen to a port bigger than 1024 &#8211; actually Tomcat comes by default configured to 8080 instead of 80 and 8443 instead of 443</li>
<li><strong>Redirect the incoming connections from port 80 to 8080</strong></li>
</ul>
<script type="text/javascript"><!--
google_ad_client = "ca-pub-1248311769909722";
/* big proghowto */
google_ad_slot = "7362984964";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<p>The redirection is done by using the following <strong>iptables</strong> commands issued in sequence. The first one will configure the machine to accept incoming connections to port 80, the second does the same for port 8080 and the third one will do the actual rerouting. Please proceed in a similar manner for ports 443 forwarded to 8443</p>
<pre style="font-size:12px;">
iptables -A INPUT -i eth0 -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 8080 -j ACCEPT
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
</pre>
<p>One thing: iptables command is reserved for the <strong>root </strong>user. For any other user, the command will not be recognized. Please ensure you are root when trying to update the routing tables, also double check each command before submitting it as the impact is high. </p>
]]></content:encoded>
			<wfw:commentRss>http://proghowto.com/iptables-redirect-port-80-to-port-8080/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Failed to load java type corresponding to e=web-app@http://java.sun.com/xml/ns/javaee</title>
		<link>http://proghowto.com/failed-to-load-web-app</link>
		<comments>http://proghowto.com/failed-to-load-web-app#comments</comments>
		<pubDate>Mon, 16 May 2011 16:55:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://proghowto.com/?p=74</guid>
		<description><![CDATA[Working with various versions of Weblogic application server, you might have encountered the error partially described in the title. The error would not appear during the build but during deployment. A more complete stack trace of this error is presented &#8230; <a href="http://proghowto.com/failed-to-load-web-app">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Working with various versions of Weblogic application server, you might have encountered the error partially described in the title. The error would not appear during the build but during deployment. A more complete stack trace of this error is presented below:
</p>
<p><span id="more-74"></span><br />
<script type="text/javascript"><!--
google_ad_client = "ca-pub-1248311769909722";
/* big proghowto */
google_ad_slot = "7362984964";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<pre>
com.bea.xml.XmlException: failed to load java type corresponding to e=web-app@http://java.sun.com/xml/ns/javaee
        at com.bea.staxb.runtime.internal.UnmarshalResult.getPojoBindingType(UnmarshalResult.java:325)
        at com.bea.staxb.runtime.internal.UnmarshalResult.determineTypeForGlobalElement(UnmarshalResult.java:292)
        at com.bea.staxb.runtime.internal.UnmarshalResult.determineTypeForGlobalElement(UnmarshalResult.java:302)
        at com.bea.staxb.runtime.internal.UnmarshalResult.determineRootType(UnmarshalResult.java:283)
        at com.bea.staxb.runtime.internal.UnmarshalResult.unmarshalDocument(UnmarshalResult.java:153)
        at com.bea.staxb.runtime.internal.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:65)
        at weblogic.descriptor.internal.MarshallerFactory$1.createDescriptor(MarshallerFactory.java:136)
        at weblogic.descriptor.DescriptorManager.createDescriptor(DescriptorManager.java:280)
        at weblogic.descriptor.DescriptorManager.createDescriptor(DescriptorManager.java:248)
        at weblogic.application.descriptor.AbstractDescriptorLoader2.getDescriptorBeanFromReader(AbstractDescriptorLoader2.java:749)
        at weblogic.application.descriptor.AbstractDescriptorLoader2.createDescriptorBean(AbstractDescriptorLoader2.java:378)
        at weblogic.application.descriptor.AbstractDescriptorLoader2.loadDescriptorBeanWithoutPlan(AbstractDescriptorLoader2.java:720)
        at weblogic.application.descriptor.AbstractDescriptorLoader2.loadDescriptorBean(AbstractDescriptorLoader2.java:729)
        at weblogic.servlet.internal.WebAppDescriptor.getWebAppBean(WebAppDescriptor.java:134)
        at weblogic.servlet.internal.WebAppModule.loadDescriptor(WebAppModule.java:775)
        at weblogic.servlet.internal.WebAppModule.prepare(WebAppModule.java:272)
        at weblogic.application.internal.flow.ScopedModuleDriver.prepare(ScopedModuleDriver.java:176)
        at weblogic.application.internal.flow.ModuleListenerInvoker.prepare(ModuleListenerInvoker.java:93)</pre>
<p>This was very strange at first. It seemed that the DTD currently mentioned in the web.xml file corresponding to a web module was not correct. The problem was that the project had worked before, with the same Weblogic version.</p>
<p>Trying to remove the DTD definition and actually make the web.xml compliant with the latest standards (xml schema, qualify the elements with the adequate namespaces) did not fix the problem. I would not have gone with such a solution anyway, as the project works for at least one year in the current configuration.</p>
<script type="text/javascript"><!--
google_ad_client = "ca-pub-1248311769909722";
/* big proghowto */
google_ad_slot = "7362984964";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<p><span style="font-weight: bold; color:red; font-size:1.2em; ">Eventually I found the issue:</span> <strong>The build was done pointing to the wrong Weblogic version (used the weblogic.jar from 10.3 instead of 9.2)</strong> No code changes were actually necessary to fix the problem just a rebuild while pointing to the right library repository. </p>
<p>No issue was signaled during the build and I am sure that I could have deployed it on weblogic 10 without any issues, however on Weblogic 9 did not work.</p>
<p>As soon as the build was correctly executed, the problem disappeared. So if you experience the same behavior, first ensure your build runs with the adequate parameters and most important Weblogic libraries and only afterwards start applying code changes.</p>
]]></content:encoded>
			<wfw:commentRss>http://proghowto.com/failed-to-load-web-app/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Configure Postfix</title>
		<link>http://proghowto.com/configure-postfix</link>
		<comments>http://proghowto.com/configure-postfix#comments</comments>
		<pubDate>Fri, 11 Mar 2011 15:45:29 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://proghowto.com/?p=38</guid>
		<description><![CDATA[.fixed { font-family: courier, sans serif; font-weight: bold; } .red { font-weight: bold; color: red; } Postfix is one of the most popular MTA (mail transfer agent) products on unix. This article presents a simple way of configuring postfix for &#8230; <a href="http://proghowto.com/configure-postfix">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<style>
.fixed {
  font-family: courier, sans serif;
  font-weight: bold;
}
.red {
  font-weight: bold;
  color: red; 
}
</style>
<p>Postfix is one of the most popular MTA (mail transfer agent) products on unix. This  article presents a simple way of configuring postfix for virtual  domains</p>
<p><span id="more-38"></span></p>
<p>Postfix is a complext product. Most likely a normal administrator will never  need all the features. In fact the product is so complex it took a book to  explain it all &#8211; <a  target="_blank" href="http://www.amazon.com/Postfix-Definitive-Kyle-Dent-D/dp/0596002122/ref=sr_ 1_1?ie=UTF8&#038;qid=1299778896&#038;sr=8-1">http://www.amazon.com/Postfix-Definitive-Kyle-Dent-D/dp/0596002122/ref=sr_1_1?ie=UTF8&#038;qid=1299778896&#038;sr=8-1</a></p>
<script type="text/javascript"><!--
google_ad_client = "ca-pub-1248311769909722";
/* big proghowto */
google_ad_slot = "7362984964";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<p>We assume:</p>
<ul>
<li>You got a machine and multiple domains hosted on it</li>
<li>The postfix on your machine receives email for all these domains</li>
<li>The domains are configured as virtual domains, each user has a folder  configured and email is delivered in those folders</li>
</ul>
<h1>Installation</h1>
<p>Postfix installation is simple: run your preferred package installer depending on  your operating system distribution and postfix will be up and running in a  matter of minutes</p>
<p>For a Debian linux system, the command <span class="fixed">apt-get install  postfix<enter></span> as a root will get the module up and running in seconds</p>
<h1>Details</h1>
<p>Our machine is called vps20.info and we&#8217;ll install mail support for the  following domains: vps20.info, vps100.info and vps12.info</p>
<p>The email we want delivered in sub-folders under the folder <span  class="fixed">/usr/local/vmail</span></p>
<p>The user daniel@vps20.info will go to a specific folder. All the other mail  will be delivered to the postmaster user associated with each domain (we will  cofigure a postmaster user for each of the three domains)</p>
<p>We must ensure that no message relaying will be enabled. Only messages  originating from the machine or messages that are sent to users belonging to the  three domains are to be processed by our Postfix installation</p>
<p>In the end, we configure an external email address, let&#8217;s call it  <strong>whatever@domainhere</strong> where the mail sent to daniel@vps20.info will be  forwarded</p>
<h1>Configuration Steps</h1>
<h2>folders</h2>
<p>su as root and create the folder <strong>/usr/local/vmail</strong> This is the parent folder  for all the subfolders where the mail will be delivered</p>
<p>Under the above mentioned folder, create one folder for each domain, let&#8217;s  call the folders <strong>vps12.info</strong>, <strong>vps20.info</strong> and <strong>vps100.info</strong>.</p>
<p>Remember that for the <strong>vps20.info</strong> we will have two users, <strong>daniel</strong> and  <strong>postmaster</strong>, and for the other two domains we will configure only one user for  each, <strong>postmaster</strong></p>
<p>For each one of the above mentioned users, we create a folder under the  folder corresponding to the domain. Therefore we create folders <strong>daniel</strong> and  <strong>postmaster</strong> under <strong>vps20.info</strong> folder, and <strong>postmaster</strong> folders under <strong>vps12.info</strong> and  <strong>vps100.info</strong></p>
<p>Now this is important: since you are root, change the owner and the group of  the folders created at the previous step to postfix. The command<br />
<span  class="fixed">chown postfix:postfix _foldername_</span><br />
 will achieve this</p>
<p>For privacy, ensure that the folders are only accessible by postfix   by the use of chmod command. In the end, the folders will have rwx rights for  the owner (postfix user) and no other rights for the group and the &#8220;other&#8221;  category</p>
<h2>DNS</h2>
<p>Your machine must be configured in DNS as being the recipient of the  messages for the three domains. See where the domains are parked and modify the  MX DNS entry for each of them to point to this machine. MX requires a fully qualified domain name, and  not a machine IP address.</p>
<h2>main.cf</h2>
<p>/etc/postfix/main.cf is the Postfix main configuration file. We change the settings in the file to achieve the following:</p>
<ul>
<li>Only mail originating from the machine will be relayed</li>
<li>Only incoming mail accepted and process is the one for the three domains</li>
<li>Any other messages or relay requests will be rejected.</li>
</ul>
<p>Here is the listing of the <strong>main.cf</strong></p>
<pre>
# See /usr/share/postfix/main.cf.dist for a commented, more complete version

# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.

myhostname = vps20.info
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination =
relayhost =
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all

mynetworks = 127.0.0.0/32
virtual_mailbox_domains = vps20.info vps100.info vps12.info
virtual_mailbox_maps = hash:/etc/postfix/virtual
virtual_mailbox_base = /usr/local/vmail
virtual_uid_maps = static:105
virtual_gid_maps = static:108
virtual_alias_maps = hash:/etc/postfix/alias
</pre>
<p>The entries are pretty standard, please note the following:</p>
<ul>
<li><strong>mynetworks</strong> &#8211; the list of networks that would get their messages relayed. The  value ensures that only messages originating from the machine will be  relayed</li>
<li><strong>virtual_mailbox_domains</strong> &#8211; the list of domains that will get their messages  processed. You can see all three domains listed here</li>
<li><strong>virtual_mailbox_base</strong> &#8211; the parent of all the mailbox folders, previously  created.</li>
<li><strong>virtual_uid_maps</strong> and <strong>virtual_gid_maps</strong> &#8211; the user id and the group id of the  postfix user. The posfix module runs as this user. It is very important the  values are accurate. The uid can be taken from the <span class="fixed">/etc/passwd</span> line that  contains the definition of the postfix user, and the gid from the <span class="fixed">/etc/group</span> line that contains the definition of the postfix group</li>
<li><strong>virtual_mailbox_maps</strong> &#8211; a text file that contains the folder names associated  with every domain.</li>
<li><strong>virtual_alias_maps</strong> &#8211; a text file that contains email aliases</li>
</ul>
<p>These are the current entries in our <span class="fixed">/etc/group</span> and <span class="fixed">/etc/passwd</span> files for the postfix user entry</p>
<p>The entry in /etc/group folder</p>
<pre>
postfix:x:108:
</pre>
<p>The entry in the /etc/passwd folder</p>
<pre>
postfix:x:105:108::/var/spool/postfix:/bin/false
</pre>
<p>Note about <strong>virtual</strong> and <strong>alias</strong> text files &#8211; the settings point to these text  files, however postfix use them in a compiled form, alias.db and virtual.db.  </p>
<p>The db file is obtained from the regular file, compiled with a special  program called <strong>postmap</strong>. The command line <span class="fixed">postmap  /etc/postfix/alias</span> will compile the text file to /etc/postfix/alias.db.  Same applies for the /etc/postifx/virtual file.</p>
<p>Upon restart, postfix checks these files. Always *.db files must be <strong>newer</strong>  than the original files. That confirms they contain the lastest info. If they  are older, then a warning message is seen in the postfix logs</p>
<h2>virtual and virtual.db</h2>
<p><strong>/etc/postfix/virtual</strong> (and after compilation with postmap <strong>/etc/postfix/virtual.db</strong>) is a file containing information about how the virtual mail has to be delivered. Basically for each email address for a domain, a folder (relative path to the /usr/local/vmail folder) is specified</p>
<p>In our case, the virtual text file contains the following</p>
<pre>
daniel@vps20.info     vps20.info/daniel/
@vps20.info     vps20.info/postmaster/
@vps100.info    vps100.info/postmaster/
@vps12.info     vps12.info/postmaster/
</pre>
<p>Please note the following:</p>
<ul>
<li>The construct @domain_name is to process all the email messages that were sent to addresses within this domain and were not already processed</li>
<li>I am not sure whether it is mandatory to define the full blown email addresses <strong>before</strong> the catch all @domain_name is used, however I believe it is a good practice to do so</li>
<li>In the above list, for the vps20.info domain, all the emails sent to daniel@vps20.info will be written to the folder vps20.info/daniel/ while any other messages for addresses within the vps10.info domain will be written to the catch all folder, vps20.info/postmaster/</li>
<li>It is <strong>mandatory</strong> to put a forward slash at the end of the folder definition, otherwise postifx will believe we want the messages to be written in a file, not a folder.</li>
</ul>
<h2>alias and alias.db</h2>
<p>alias (actually <span class="fixed">/etc/postfix/alias</span>) is a text file containing email aliases. If you want that the email messages sent to a certain email address to be forwarded to another address, then an entry in the alias file is needed</p>
<p>The destination address does not have to be within the domains serviced by the postfix installation &#8211; for example I use alias entries to forward some emails on my address at @gmail.com so you can really use any email address</p>
<p>This is an example of alias file</p>
<pre>
daniel@vps20.info       whatever@domainhere
</pre>
<p>Note: while virtual file must define every single address (or catch all address) for all the domains serviced by the postfix installation, alias file can be empty. However, even when it is empty, you still have to compile it to alias.db using postmap program, while alias.db must be always newer than the original alias file</p>
]]></content:encoded>
			<wfw:commentRss>http://proghowto.com/configure-postfix/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache Web Services Security Using WSS4J</title>
		<link>http://proghowto.com/apache-web-services-security-using-wss4j</link>
		<comments>http://proghowto.com/apache-web-services-security-using-wss4j#comments</comments>
		<pubDate>Fri, 18 Feb 2011 19:16:57 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://proghowto.com/?p=20</guid>
		<description><![CDATA[This document presents a practical approach of how to use WSS4J to add simple security headers to both client and web service implemented with Axis 1.* Adding security at the UsernameToken level for a web service means adding a specific &#8230; <a href="http://proghowto.com/apache-web-services-security-using-wss4j">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This document presents a practical approach of how to use WSS4J to add simple security headers to both client and web service implemented with Axis 1.*</p>
<p><span id="more-20"></span></p>
<p>Adding security at the UsernameToken level for a web service means adding a specific request header with the user name and password, with the password either in clear or encrypted (digest)</p>
<script type="text/javascript"><!--
google_ad_client = "ca-pub-1248311769909722";
/* big proghowto */
google_ad_slot = "7362984964";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<p>WSS4J is implemented to permit adding security headers without changing the actual web service code.</p>
<h2>Libraries</h2>
<p>The current implementation uses the following libraries:</p>
<ul>
<li>Axis web service implementation version 1.4 <a href="http://ws.apache.org/axis/">download</a></li>
<li>WSS4J implementation from Apache <a href="http://ws.apache.org/wss4j/">download</a></li>
<li>XML security implementation, also from Apache <a href="http://santuario.apache.org/">download</a></li>
</ul>
<h2>Client</h2>
<p>The client uses the axis libraries, the client stub classes generated for the specific service and the libraries for WSS4J and XML security plus dependencies. </p>
<p> The WSS4J handler must be registered to the client handler chain in order to manipulate the SOAP request and get the security headers in place. The handler receives the user name (principal) directly from the client code through properties, and the password through a callback class.</p>
<p>The client stub classes are generated with WSDL2Java class from the service wsdl file.</p>
<p>This is the code for the client / without security added</p>
<pre>
package service.test.client;

import java.net.URL;

import javax.xml.rpc.holders.StringHolder;

import com.services.www.data.Item;
import com.services.www.data.holders.ParametersHolder;
import com.services.www.services.InfoServiceLocator;
import com.services.www.services.InfoServicePortType;

public class TestClient extends BaseClient {
	public static void main(String[] args){
		try {
			new TestClient().start();
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

	private void start() throws Exception {
		// get the locator
		InfoServiceLocator locator = new  InfoServiceLocator();

		URL address = new URL("http://localhost:8000/service/services/InfoService");
		InfoServicePortType service = locator.getInfoService(address);

		// get the service
		StringHolder statusCode = new StringHolder();
		StringHolder comments = new StringHolder();
		ParametersHolder parameters = new ParametersHolder();

		// call the operation
		service.getInformation("name here", "test id",
				new Item[]{
					new Item("id1", "name1", "comments1"),
					new Item("id2", "name2", "comments2")
				},
				statusCode, comments, parameters);

		// show the results (a collection of helper methods
		// a
		display("status", statusCode.value);
		display("comments", comments.value);

		display(parameters);
	}
}
</pre>
<p>The request as generated with this client looks like this</p>
<pre>
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;soapenv:Envelope
		xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
		xmlns:xsd="http://www.w3.org/2001/XMLSchema"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
	&lt;soapenv:Body&gt;
		&lt;getInformation xmlns="http://www.services.com/data"&gt;
			&lt;name xmlns=""&gt;name here&lt;/name&gt;
			&lt;id xmlns=""&gt;test id&lt;/id&gt;
			&lt;items xmlns=""&gt;
				&lt;item&gt;
					&lt;itemId&gt;id1&lt;/itemId&gt;
					&lt;itemName&gt;name1&lt;/itemName&gt;
					&lt;comments&gt;comments1&lt;/comments&gt;
				&lt;/item&gt;
				&lt;item&gt;
					&lt;itemId&gt;id2&lt;/itemId&gt;
					&lt;itemName&gt;name2&lt;/itemName&gt;
					&lt;comments&gt;comments2&lt;/comments&gt;
				&lt;/item&gt;
			&lt;/items&gt;
		&lt;/getInformation&gt;
	&lt;/soapenv:Body&gt;
&lt;/soapenv:Envelope&gt;
</pre>
<p>Now the only thing to do is to add the security. As mentioned, adding security headers is accomplished without changing the actual service code. The process involves registering and configuring a handler and providing a callback class implementation.</p>
<p>There are two ways of registering the handler, as a part of the client configuration file (.wsdd) or programatically. Most of the time the application already has a configuration file, there should not be any reason to maintain another one, therefore the only approach presented here is the programmatical one.</p>
<p>Here is the client code that includes the security. Please note the following: when adding the security handler programmatically, the Axis framework expects a class that implements <span class="code">javax.xml.rpc.handler.Handler</span>. When the handler is defined through the wsdd configuration file, then a class implementing <span class="code">org.apache.axis.Handler</span> is expected. If this is not followed, the error triggered is something stating that &#8220;the handler cannot be created&#8221;, however this is a wrap around a ClassCastException</p>
<p> WSS4J implementation provides two classes implementing <span class="code">org.apache.axis.Handler</span>, WSDoAllReceiver and WSDoAllSender, and one implementing <span class="code">javax.xml.rpc.handler.Handler</span> which is WSS4JHandler </p>
<p>Below is the code, please note the method addSecurityHeaders. The handler chain object is retrieved from the locator object and a new handler is added</p>
<pre>
package service.test.client;

import java.net.URL;
import java.util.List;
import java.util.TreeMap;

import javax.xml.namespace.QName;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.HandlerRegistry;
import javax.xml.rpc.holders.StringHolder;

import org.apache.ws.security.handler.WSS4JHandler;

import com.services.www.data.Item;
import com.services.www.data.holders.ParametersHolder;
import com.services.www.services.InfoServiceLocator;
import com.services.www.services.InfoServicePortType;

public class TestSecureClient extends BaseClient {
	public static void main(String[] args){
		try {
			new TestSecureClient().start();
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

	private void start() throws Exception {
		// get the locator
		InfoServiceLocator locator = new  InfoServiceLocator();

		URL address = new URL("http://localhost:8000/service/services/InfoService");
		InfoServicePortType service = locator.getInfoService(address);

		// register the security handler and provide the attributes

		// get the service
		StringHolder statusCode = new StringHolder();
		StringHolder comments = new StringHolder();
		ParametersHolder parameters = new ParametersHolder();

		// add security headers
		addSecurityHeaders(locator);

		// call the operation
		service.getInformation("name here", "test id",
				new Item[]{
					new Item("id1", "name1", "comments1"),
					new Item("id2", "name2", "comments2")
				},
				statusCode, comments, parameters);

		// show the results (a collection of helper methods
		// a
		display("status", statusCode.value);
		display("comments", comments.value);

		display(parameters);
	}

	private void addSecurityHeaders(InfoServiceLocator locator) {
		HandlerRegistry registry = locator.getHandlerRegistry();
		QName portName = new QName("http://www.services.com/services", "InfoService");

		List chain = registry.getHandlerChain(portName);

		// create the new handler info for the WSS4J handler
		HandlerInfo info = new HandlerInfo();
		info.setHandlerClass(WSS4JHandler.class);

		TreeMap tmap = new TreeMap();

		tmap.put("send.action", "UsernameToken");
		tmap.put("receive.action", "NoSecurity");

		tmap.put("passwordCallbackClass", "service.test.client.SecureCallback");
		tmap.put("deployment", "client");

		// tmap.put("passwordType", "PasswordText");
		tmap.put("passwordType", "PasswordDigest");

		// tmap.put("flow", "request");
		tmap.put("user", "testuser");

		info.setHandlerConfig(tmap);

		chain.add(info);
	}
}
</pre>
<p>A couple of things about parameters.</p>
<p> passwordType has the value PasswordDigest. This will encrypt the password sent in the request as it is visible below. If PasswordText was used instead, the security layer would have passed the password &#8220;in clear&#8221;.</p>
<p><b>send.action</b> and <b>receive.action</b> &#8211; they confirm the type of security header request and in the response respectively. When one is present, the other is also mandatory. In our case, the request (send.action) will contain UsernameToken security header, the response will not contain anything. As receive.action is mandatory, will be added with the NoSecurity value. The two parameters can be replaced with <b>action</b> when both request and response must be treated the same way. In the current case this is not possible as the response will not contain any security header</p>
<p>What happens if <b>action</b> was used with UsernameToken: the handler would create a Security element in the header and expect one in the response. As the response does not contain any security header, then the client would trigger the error with the message <b><span class="code">WSS4JHandler: Request does not contain required Security header</span></b> That is a lot misleading as the security header is missing from the response, not from the request.</p>
<p>After adding this functionality, the request will contain the security header as per standard, with the password encrypted.</p>
<pre>
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;soapenv:Envelope
	xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
&lt;soapenv:Header&gt;
&lt;wsse:Security
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
soapenv:mustUnderstand="1"&gt;
&lt;wsse:UsernameToken
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="UsernameToken-1"&gt;
&lt;wsse:Username&gt;testuser&lt;/wsse:Username&gt;
&lt;wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"&gt;SwZD8+A6Jk2stfubiJR5d0MO+mU=
&lt;/wsse:Password&gt;
&lt;wsse:Nonce
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"&gt;bMN8g5OcJgz9QbCSw8ix5g==
&lt;/wsse:Nonce&gt;
&lt;wsu:Created&gt;2010-09-13T16:57:27.876Z
&lt;/wsu:Created&gt;
	&lt;/wsse:UsernameToken&gt;
&lt;/wsse:Security&gt;
&lt;/soapenv:Header&gt;
&lt;soapenv:Body&gt;
&lt;getInformation xmlns="http://www.services.com/data"&gt;
&lt;name xmlns=""&gt;name here&lt;/name&gt;
&lt;id xmlns=""&gt;test id&lt;/id&gt;
&lt;items xmlns=""&gt;
&lt;item&gt;
	&lt;itemId&gt;id1&lt;/itemId&gt;
	&lt;itemName&gt;name1&lt;/itemName&gt;
	&lt;comments&gt;comments1&lt;/comments&gt;
&lt;/item&gt;
&lt;item&gt;
	&lt;itemId&gt;id2&lt;/itemId&gt;
	&lt;itemName&gt;name2&lt;/itemName&gt;
	&lt;comments&gt;comments2&lt;/comments&gt;
&lt;/item&gt;
&lt;/items&gt;
&lt;/getInformation&gt;
&lt;/soapenv:Body&gt;
&lt;/soapenv:Envelope&gt;
</pre>
<p>The callback defined under the property passwordCallbackClass is a Java class that implements <span class="code">javax.security.auth.callback.CallbackHandler</span>. The only purpose of this class is to provide the password associated with a principal. How the callback is implemented provides full flexibility.</p>
<p>Following is the code associated with this callback. <i><b><span class="code">getPassword</span></b></i> is a custom method implemented by the programmer that actually returns the password given the principal. As this is specific to each situation, we left it out of the document.</p>
<pre>
	public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
		// given the user, provide the password that will be sent in the
		// security header (clear format or digest)
		// we assume the provided callback array is not null
		for(int count = 0; count &lt; callbacks.length; count ++){
			Callback crt = callbacks[count];

			/* our callback must be of type WSPasswordCallback for the UsernameToken */
			if(crt instanceof WSPasswordCallback){
				WSPasswordCallback pc = (WSPasswordCallback) crt; 

				String user = pc.getIdentifier();

				// implement getPassword to actually provide
				// the correct password for the specified principal
				pc.setPassword(getPassword(user));
			}
		}
	}
</pre>
<h2>Server</h2>
<p>For the server side the security handler is configured in the server-config.wsdd file, the web service configuration file.</p>
<p>Below is the transport tag, after configuring the handler. Note the fact the handler must implement <span class="code">org.apache.axis.Handler</span> and not <span class="code">javax.xml.rpc.handler.Handler</span></p>
<pre>
	&lt;transport name="http"&gt;
	  &lt;requestFlow&gt;
	   	&lt;handler type="URLMapper"/&gt;
	   &lt;handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/&gt;
		&lt;handler type="java:org.apache.ws.axis.security.WSDoAllReceiver"&gt;
			&lt;parameter name="action" value="UsernameToken" /&gt;
			&lt;parameter name="passwordType" value="PasswordDigest" /&gt;
			&lt;parameter name="passwordCallbackClass" value="com.services.www.callback.SecureCallback" /&gt;
		&lt;/handler&gt;
	  &lt;/requestFlow&gt;
	 &lt;/transport&gt;
</pre>
<p>In the current example WSDoAllReceiver is used. The parameters define the type of security header, including the way the password must be processed (PasswordDigest).</p>
<p>The callback class defined is identical with the one used on the client.</p>
<p>The action is defined under the property <b>action</b>. It is applied to the request only anyway, as the configuration is part of the &lt;requestFlow&gt;. That is the reason it is declared different than on the client side, when we needed to specifically define the action for request and response.</p>
<p>This concludes the current example. Please ensure the latest version of xml security is used</p>
]]></content:encoded>
			<wfw:commentRss>http://proghowto.com/apache-web-services-security-using-wss4j/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Faces Context not Found getResponseWriter Will Fail</title>
		<link>http://proghowto.com/faces-context-not-found-getresponsewriter-will-fail</link>
		<comments>http://proghowto.com/faces-context-not-found-getresponsewriter-will-fail#comments</comments>
		<pubDate>Fri, 18 Feb 2011 19:13:35 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://proghowto.com/?p=18</guid>
		<description><![CDATA[Did you get the error in the title? This is a very common occurrence in JSF (Java Server Faces) applications. It is easy to get and easy to get rid off, you just have to be careful. Here is a &#8230; <a href="http://proghowto.com/faces-context-not-found-getresponsewriter-will-fail">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Did you get the error in the title? This is a very common occurrence in JSF (Java Server Faces) applications. It is easy to get and easy to get rid off, you just have to be careful.<br />
<span id="more-18"></span><br />
Here is a full error stacktrace:<br />
<script type="text/javascript"><!--
google_ad_client = "ca-pub-1248311769909722";
/* big proghowto */
google_ad_slot = "7362984964";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<pre>
javax.faces.FacesException: Faces context not found. getResponseWriter will fail.
Check if the FacesServlet has been initialized at all in your web.xml
 configuration fileand if you are accessing your jsf-pages through the correct mapping.
E.g.: if your FacesServlet is mapped to  *.jsf (with the <servlet-mapping>-element),
you need to access your pages as 'sample.jsf'.
If you tried to access 'sample.jsp', you'd get this error-message.
	Javax.faces.webapp.UIComponentTag.setupResponseWriter(UIComponentTag.java:926)
	javax.faces.webapp.UIComponentTag.doStartTag(UIComponentTag.java:313)
	org.apache.myfaces.taglib.core.ViewTag.doStartTag(ViewTag.java:73)
	org.apache.jsp.index_jsp._jspx_meth_f_005fview_005f0(index_jsp.java:92)
	org.apache.jsp.index_jsp._jspService(index_jsp.java:67)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:377)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
</pre>
<p><strong>Why it  appears:</strong> well, that is simple. It occurs when the FacesContext object is not found in the session. This object must be already in the session <strong>before</strong> the first JSF tag is processed (usually a f:view tag). We will analyse the situations when this object is missing. </p>
<p>JSF functionality revolves around a special servlet, called FacesServlet. The servlet is defined in the web.xml file. It can be initialized using various patterns, some popular ones being *.jsf, *.faces or /faces/*. When the servlet is accessed, it ensures the FacesContext object exist in the session, if not will ensure it will be created.</p>
<h3>Session Startup</h3>
<p>When a brand new session is started, the FacesContext does not exist. If you access a page with JSF tags and the FacesContext does not exist, you get the error. </p>
<p>There are two situations:</p>
<p><strong>The application context is accessed</strong></p>
<ul>
<li>The welcome page will be then loaded. </li>
<li>This page must be a resource existent in the war, probably a jsp page. If the page contains JSF tags, because the faces servlet was not invoked, you get the error</li>
</ul>
<p>The solution for this: The landing page will contain ONLY a <jsp:forward /> tag that forwards to an URL through the faces servlet (ex: forwards to first.jsf which will load first.jsp AFTER triggering the faces servlet)</p>
<p><strong>A bookmark is accessed</strong></p>
<p>The user bookmarked one of the pages inside the application. If the session is brand new and the bookmarks do not trigger the faces servlet, then the error gets displayed. </p>
<p>Solution: obviously the user bookmarked an internal application link. If the internal link would have triggered the faces servlet (being for example in the format *.jsf) then the error would not have appeared. It is obvious then that all the internal links should trigger the faces servlet &#8211; consistently use *.jsf internal links rather than *.jsp and the problem is solved.</p>
<h3>Session Expired</h3>
<p>This is a little bit different than the previous, with the same result as the situation in which a bookmark is used. </p>
<ul>
<li>In this case, there was a valid session, the user spent some time operating the application then for some reason the session was left to expire.</li>
<li>Then the operator issues another application request. In this case, if there is some security implementation in place, the application must forward to the login page with an error message &#8220;session expired, please log back in&#8221;.</li>
<li> However the FacesContext also vanished and instead of the above mentioned flow, instead of seeing the login page together with the error message, we get to see the one related to the missing FacesContext object.</li>
<li>The solution is identical with the one above: all the internal links (and the forwards) must point to urls targeting the faces servlet. Always page.jsf, never page.jsp </li>
</ul>
<h3>Final Conclusion</h3>
<ul>
<li>FacesContext is required for the entire life of a JSF session</li>
<li>The welcome page should access the faces servlet &#8211; usually forwarding to an URL with the faces servlet URL pattern. This creates the faces context object if is not existent</li>
<li>All the other internal links should follow the faces servlet URL pattern. In this way Faces Context will be recreated if needed &#8211; especially if it is accidentally destroyed by a session expiration</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://proghowto.com/faces-context-not-found-getresponsewriter-will-fail/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASP.NET Controls from Scratch</title>
		<link>http://proghowto.com/asp-net-controls-from-scratch</link>
		<comments>http://proghowto.com/asp-net-controls-from-scratch#comments</comments>
		<pubDate>Fri, 18 Feb 2011 19:09:11 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://proghowto.com/?p=13</guid>
		<description><![CDATA[In this article is presented a step by step approach to create a fully rendered ASP.NET custom control. Custom controls are a very important part of ASP.NET. They provide a very high level of encapsulation and reusability. There are roughly &#8230; <a href="http://proghowto.com/asp-net-controls-from-scratch">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In this article is presented a step by step approach to create a fully rendered ASP.NET custom control. </p>
<p><span id="more-13"></span></p>
<p>Custom controls are a very important part of ASP.NET. They provide a very high level of encapsulation and reusability. There are roughly three types of controls, as follows:</p>
<ul>
<li>Web User Control &#8211; involving a resource with .ASCX extension</li>
<li>Composite control &#8211; a custom control embedding other ASP.NET controls</li>
<li>Custom control &#8211; the fully rendered control, with full control on state management and rendering</li>
</ul>
<script type="text/javascript"><!--
google_ad_client = "ca-pub-1248311769909722";
/* big proghowto */
google_ad_slot = "7362984964";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<p>There are many advantages related to the fully rendered custom control (the third category) as follows:</p>
<ul>
<li>Full control of all the aspects of the  control lifecycle</li>
<li>Full control of the rendering process</li>
<li>The final result can be delivered as a simple library &#8211; assembly &#8211; unlike the web user control where the .ascx file  is a required deliverable</li>
</ul>
<p>Most of the professional grade custom controls are distributed as fully rendered controls</p>
<h3>Create the Class</h3>
<p>The custom control is a regular .NET class, extending System.Web.WebControl. To start our test, create a new ASP.NET project, then add a new item and select &#8220;ASP.NET Server Control&#8221;. I removed the existent Text property from the created class (we start from scratch, remember?) and there is the result:</p>
<pre>
   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel;
   4:  using System.Linq;
   5:  using System.Text;
   6:  using System.Web;
   7:  using System.Web.UI;
   8:  using System.Web.UI.WebControls;
   9:
  10:  namespace TestControl
  11:  {
  12:
  13:      [ToolboxData("&lt;{0}:TestControl runat=server&gt;&lt;/{0}:TestControl&gt;")]
  14:      public class TestControl : WebControl
  15:      {
  16:          protected override void RenderContents(HtmlTextWriter output)
  17:          {
  18:              output.Write("test control here");
  19:          }
  20:      }
  21:  }
</pre>
<p>Now compile the project and open your main page in design mode. Automatically the IDE toolbox will contain your component ready to use. Get the control and drag it to your page, and you will see the output from the RenderContents method there.</p>
<p><a href="http://proghowto.com/wp-content/uploads/2011/02/picture1.jpg"><img src="http://proghowto.com/wp-content/uploads/2011/02/picture1.jpg" alt="" title="picture1" width="437" height="239" class="alignnone size-full wp-image-15" /></a></p>
<p>Finish the componet state related design:</p>
<ul>
<li>Decide what are the attributes that define the control state (names, types, cardinality)</li>
<li>Decide which attributes will be part of form controls (editable)</li>
<li>Decide the attributes that will have static values &#8211; these will be saved into the ViewState object</li>
<li>In the end, decide how the componet will be rendered and finish the rendering method</li>
</ul>
<p>For our purpose, we will have three attributes, <strong>address</strong> (string), <strong>number</strong> (integer), and <strong>fullName</strong> (string). The first two will be static, the third one editable.</p>
<p>We go ahead and implement these attributes as part of our class (two string attributes, one integer)</p>
<pre>
   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel;
   4:  using System.Linq;
   5:  using System.Text;
   6:  using System.Web;
   7:  using System.Web.UI;
   8:  using System.Web.UI.WebControls;
   9:
  10:  namespace TestControl
  11:  {
  12:
  13:      [ToolboxData("&lt;{0}:TestControl runat=server&gt;&lt;/{0}:TestControl&gt;")]
  14:      public class TestControl : WebControl
  15:      {
  16:          private string address;
  17:          private int number;
  18:
  19:          private string fullName;
  20:
  21:          public string Address
  22:          {
  23:              get { return address; }
  24:              set { address = value; }
  25:          }
  26:
  27:          public int Number
  28:          {
  29:              get { return number; }
  30:              set { number = value; }
  31:          }
  32:
  33:          public string FullName
  34:          {
  35:              get { return fullName; }
  36:              set { fullName = value; }
  37:          }
  38:          protected override void RenderContents(HtmlTextWriter output)
  39:          {
  40:              output.Write("test control here");
  41:          }
  42:      }
  43:  }
</pre>
<p>Add the following interfaces as part of the interface list implemented by the control: INamingContainer and IPostBackDataHandler</p>
<p>INamingContainer does not have any methods, however any container that implements this interface will receive an uniqe identifier from its parent.</p>
<p>IPostBackDataHandler is very important for processing the state attributes that are rendered in http form controls. Its method LoadPostData is invoked when the controller should load the postback values from the request</p>
<p>Override the methods LoadViewState and SaveViewState from the parent; they will be invoked when the information should be saved to or loaded from the ViewState object.</p>
<h3>ViewState</h3>
<p>A lot of people say that ViewState is a very bad thing, which is not true. ViewState is an amazing way of preserving the page state across requests. Sometimes it is used in a wrong way and <strong>that</strong> is the bad thing.</p>
<p>Rule of thumb: if the state of a component is restored anyway from the database or the session every time the page is loaded, then turn its EnableViewState off. Look at each component from this perspective and you will never have problems with ViewState</p>
<p>Don&#8217;t forget to call the base class methods LoadViewState and SaveViewState with the appropriate information. You will not see any difference if you just started from scratch and the superclass is WebControl, however if you plan a more complex class hierarchy, you will avoid potential issues.</p>
<p>All the code samples from the internet use constructs as follows in order to save / retrieve information from the ViewState: </p>
<pre>
 1:              ViewState["whatevername"] = FullName;</pre>
<p>In this case, both the name (whatevername) and the value (FullName) will be saved in the view state field increasing the page size. This is a waste of traffic. You don&#8217;t need this, there is a better way:</p>
<ul>
<li>Create an ArrayList object</li>
<li>Add the objects you want to save in the array list</li>
<li>One of the objects in the ArrayList must be the one returned by the super class SaveViewState method</li>
<li>This should be the object returned by the SaveViewState method</li>
<li>This will be the object passed to LoadViewState when this method will be invoked (ok, not the very same instance, but an identical one anyway)</li>
<li>Process the stored values in the same order (it is easy to check, the two methods are a couple of lines away)</li>
<li>You are done!</li>
</ul>
<p>Here is our implementation. Note the fact that we process the object for the super class (don&#8217;t forget that) and also we process our attributes in the very same order.</p>
<pre>
   1:          protected override void LoadViewState(object current)
   2:          {
   3:              // here we know the object must be a
   4:              // ArrayList, as this is the object saved by
   5:              // SaveViewState method
   6:              if (current is ArrayList)
   7:              {
   8:                  ArrayList list = (ArrayList)current;
   9:
  10:                  // we assume the array list is of length 3 (as saved in
  11:                  // SaveViewState, we also know exactly what is at each index
  12:                  // we just need to double check the SaveViewState to
  13:                  // confirm
  14:                  object baseObject = list[0];
  15:                  base.LoadViewState(baseObject);
  16:
  17:                  object adr = list[1];
  18:                  object nr = list[2];
  19:                  object fname = list[3];
  20:
  21:                  Address = adr == null ? null : adr.ToString();
  22:                  Number = (nr == null ? 0 : (int)nr);
  23:                  FullName = fname == null ? null : fname.ToString();
  24:              }
  25:              else
  26:              {
  27:                  throw new Exception("Wrong object in the LoadViewState");
  28:              }
  29:          }
  30:
  31:          protected override object SaveViewState()
  32:          {
  33:              ArrayList list = new ArrayList();
  34:
  35:              // superclass
  36:              list.Add(base.SaveViewState());
  37:
  38:              list.Add(Address);
  39:              list.Add(Number);
  40:              list.Add(FullName);
  41:
  42:              return list;
  43:          }
</pre>
<h3>Load the postback data from the request</h3>
<p>This step consists in implementing the method LoadPostData from the IPostBackDataHandler interface. You know what names you attached to the form controls, basically just look for these names and attach the values to the variables.</p>
<p><span style="font-weight:bold; color:red;">In order for this method to be invoked, you need to have a http field part of your component with the name identical with the component UniqueID</span>. This is <strong>very important</strong>. Normally this will be a hidden text field with some hardcoded value as we&#8217;re only interested in its presence. Don&#8217;t store an empty value in it, just put something.</p>
<p>Here is the implemented method</p>
<pre>
   1:          public bool LoadPostData(string postDataKey,
                      System.Collections.Specialized.NameValueCollection postCollection)
   2:          {
   3:              // load the values componenet by component; we only have one
   4:              string fname = postCollection[UniqueID + "_full"];
   5:
   6:              // see if the state has changed - in FullName we already
   7:              // have the value loaded from ViewState, which is the value
   8:              // kept by FullName on the previous page display
   9:              bool stateChanged = false;
  10:              if (FullName == null)
  11:              {
  12:                  stateChanged = fname != null;
  13:              }
  14:              else
  15:              {
  16:                  stateChanged = ! FullName.Equals(fname);
  17:              }
  18:
  19:              FullName = fname;
  20:
  21:              return stateChanged;
  22:          }
</pre>
<p>In order to see if the component state changed, you need to see if the previous and current values for the editable controls are the same. This can be achieved in the following way:</p>
<ul>
<li>Save the editable attributes in ViewState as well</li>
<li>The ViewState will contain the &#8220;previous&#8221; attribute value</li>
<li>The postback data will contain the actual value</li>
<li>Check to see whether they are equal or not, this will determine the value returned by LoadPostData method.</li>
<li>After the evaluation, emember to store the postback data in the attribute, because this is the actual value</li>
</ul>
<h3>Rendering</h3>
<p>Basically the method RenderContents will actually generate the html for the component, based on the component state.</p>
<p>Here is the code; spot the hidden field at the beginning of the rendered content: </p>
<pre>
   1:          protected override void RenderContents(HtmlTextWriter output)
   2:          {
   3:              StringBuilder buffer = new StringBuilder();
   4:
   5:              buffer.Append("&lt;input type=\"hidden\" name=\"");
   6:              buffer.Append(UniqueID);
   7:              buffer.Append("\" value=\"hd\"&gt;");
   8:
   9:              buffer.Append("&lt;table cellpadding=\"4\" cellspacing=\"1\" border=\"1\"&gt;");
  10:              buffer.Append("&lt;tr&gt;&lt;td&gt;Item&lt;/td&gt;&lt;td&gt;Value&lt;/td&gt;&lt;/tr&gt;");
  11:
  12:              buffer.Append("&lt;tr&gt;&lt;td&gt;Address&lt;/td&gt;&lt;td&gt;");
  13:              buffer.Append(Address);
  14:              buffer.Append("&lt;/td&gt;&lt;/tr&gt;");
  15:
  16:              buffer.Append("&lt;tr&gt;&lt;td&gt;Number&lt;/td&gt;&lt;td&gt;");
  17:              buffer.Append(Number);
  18:              buffer.Append("&lt;/td&gt;&lt;/tr&gt;");
  19:
  20:              buffer.Append("&lt;tr&gt;&lt;td&gt;Full Name&lt;/td&gt;&lt;td&gt;&lt;input type=\"text\" name=\"");
  21:              buffer.Append(UniqueID + "_full");
  22:              buffer.Append("\" value=\"");
  23:              buffer.Append(FullName);
  24:              buffer.Append("\"&gt;&lt;/td&gt;&lt;/tr&gt;");
  25:
  26:              buffer.Append("&lt;/table&gt;");
  27:
  28:              output.Write(buffer.ToString());
  29:          }
</pre>
<h3>Final code</h3>
<p>Here is how the component looks like rendered; upon postback, the editable field and the two static attributes will hold their values</p>
<p><a href="http://proghowto.com/wp-content/uploads/2011/02/picture21.jpg"><img src="http://proghowto.com/wp-content/uploads/2011/02/picture21.jpg" alt="" title="picture21" width="318" height="261" class="alignnone size-full wp-image-16" /></a></p>
<p>Here is the final code; if you don&#8217;t need to track the state change, you can stop saving the editable fields in the ViewState and remove the comparison done in the LoadPostData method; just override the attribute with the actual value.</p>
<pre>
   1:  using System;
   2:  using System.ComponentModel;
   3:  using System.Web.UI;
   4:  using System.Web.UI.WebControls;
   5:  using System.Collections;
   6:  using System.Text;
   7:
   8:  namespace TestControl
   9:  {
  10:
  11:      [ToolboxData("&lt;{0}:TestControl runat=server&gt;&lt;/{0}:TestControl&gt;")]
  12:      public class TestControl : WebControl, INamingContainer, IPostBackDataHandler
  13:      {
  14:
  15:          private string address;
  16:          private int number;
  17:
  18:          private string fullName;
  19:
  20:          public string Address
  21:          {
  22:              get { return address; }
  23:              set { address = value; }
  24:          }
  25:
  26:          public int Number
  27:          {
  28:              get { return number; }
  29:              set { number = value; }
  30:          }
  31:
  32:          public string FullName
  33:          {
  34:              get { return fullName; }
  35:              set { fullName = value; }
  36:          }
  37:          protected override void RenderContents(HtmlTextWriter output)
  38:          {
  39:              StringBuilder buffer = new StringBuilder();
  40:
  41:              buffer.Append("&lt;input type=\"hidden\" name=\"");
  42:              buffer.Append(UniqueID);
  43:              buffer.Append("\" value=\"hd\"&gt;");
  44:
  45:              buffer.Append("&lt;table cellpadding=\"4\" cellspacing=\"1\" border=\"1\"&gt;");
  46:              buffer.Append("&lt;tr&gt;&lt;td&gt;Item&lt;/td&gt;&lt;td&gt;Value&lt;/td&gt;&lt;/tr&gt;");
  47:
  48:              buffer.Append("&lt;tr&gt;&lt;td&gt;Address&lt;/td&gt;&lt;td&gt;");
  49:              buffer.Append(Address);
  50:              buffer.Append("&lt;/td&gt;&lt;/tr&gt;");
  51:
  52:              buffer.Append("&lt;tr&gt;&lt;td&gt;Number&lt;/td&gt;&lt;td&gt;");
  53:              buffer.Append(Number);
  54:              buffer.Append("&lt;/td&gt;&lt;/tr&gt;");
  55:
  56:              buffer.Append("&lt;tr&gt;&lt;td&gt;Full Name&lt;/td&gt;&lt;td&gt;&lt;input type=\"text\" name=\"");
  57:              buffer.Append(UniqueID + "_full");
  58:              buffer.Append("\" value=\"");
  59:              buffer.Append(FullName);
  60:              buffer.Append("\"&gt;&lt;/td&gt;&lt;/tr&gt;");
  61:
  62:              buffer.Append("&lt;/table&gt;");
  63:
  64:              output.Write(buffer.ToString());
  65:          }
  66:
  67:          public bool LoadPostData(string postDataKey,
        System.Collections.Specialized.NameValueCollection postCollection)
  68:          {
  69:              // load the values componenet by component; we only have one
  70:              string fname = postCollection[UniqueID + "_full"];
  71:
  72:              // see if the state has changed - in FullName we already
  73:              // have the value loaded from ViewState, which is the value
  74:              // kept by FullName on the previous page display
  75:              bool stateChanged = false;
  76:              if (FullName == null)
  77:              {
  78:                  stateChanged = fname != null;
  79:              }
  80:              else
  81:              {
  82:                  stateChanged = ! FullName.Equals(fname);
  83:              }
  84:
  85:              FullName = fname;
  86:
  87:              return stateChanged;
  88:          }
  89:
  90:          public void RaisePostDataChangedEvent()
  91:          {
  92:              // not implemented for the current example
  93:          }
  94:
  95:          protected override void LoadViewState(object current)
  96:          {
  97:              // here we know the object must be a
  98:              // ArrayList, as this is the object saved by
  99:              // SaveViewState method
 100:              if (current is ArrayList)
 101:              {
 102:                  ArrayList list = (ArrayList)current;
 103:
 104:                  // we assume the array list is of length 3 (as saved in
 105:                  // SaveViewState, we also know exactly what is at each index
 106:                  // we just need to double check the SaveViewState to
 107:                  // confirm
 108:                  object baseObject = list[0];
 109:                  base.LoadViewState(baseObject);
 110:
 111:                  object adr = list[1];
 112:                  object nr = list[2];
 113:                  object fname = list[3];
 114:
 115:                  Address = adr == null ? null : adr.ToString();
 116:                  Number = (nr == null ? 0 : (int)nr);
 117:                  FullName = fname == null ? null : fname.ToString();
 118:              }
 119:              else
 120:              {
 121:                  throw new Exception("Wrong object in the LoadViewState");
 122:              }
 123:          }
 124:
 125:          protected override object SaveViewState()
 126:          {
 127:              ArrayList list = new ArrayList();
 128:
 129:              // superclass
 130:              list.Add(base.SaveViewState());
 131:
 132:              list.Add(Address);
 133:              list.Add(Number);
 134:              list.Add(FullName);
 135:
 136:              return list;
 137:          }
 138:      }
 139:  }
</pre>
]]></content:encoded>
			<wfw:commentRss>http://proghowto.com/asp-net-controls-from-scratch/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Configure Apache, PHP and MySQL</title>
		<link>http://proghowto.com/configure-apache-php-and-mysql</link>
		<comments>http://proghowto.com/configure-apache-php-and-mysql#comments</comments>
		<pubDate>Fri, 18 Feb 2011 19:01:18 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://proghowto.com/?p=6</guid>
		<description><![CDATA[This is just another tutorial of how to configure a development machine for Apache, PHP and MySQL There are packages bundling the three technologies (install the package and everything is there ready to go). They are good for start. However &#8230; <a href="http://proghowto.com/configure-apache-php-and-mysql">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This is just another tutorial of how to configure a development machine for Apache, PHP and MySQL</p>
<p><span id="more-6"></span></p>
<p>There are packages bundling the three technologies (install the package and everything is there ready to go). They are good for start. However a serious developer should install the latest production bundles from scratch. Couple or reasons: </p>
<ul>
<li>Have complete control of the process</li>
<li>Use the versions that you have or intend to have on the production machine</li>
<li>Learn how to configure everything. As a programmer, you eventually need to know that.</li>
</ul>
<script type="text/javascript"><!--
google_ad_client = "ca-pub-1248311769909722";
/* big proghowto */
google_ad_slot = "7362984964";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<p>We are going to present the simplest approach to have all the three packages installed on your machine and have you up and running in the shortest time possible.</p>
<p>We assume you got a machine running Windows XP or 2000 or Vista, and you don&#8217;t have any of the required packages installed (if you tried to install them and it did not work, please start fresh).</p>
<p>Please install the packages in the order mentioned below. The reason: for example if you install PHP after you install Apache, then the PHP installation script will automatically integrate with Apache, saving you some time.</p>
<p>Please do not install in the default Windows <strong>Program Files</strong> folder. Instead, do it in a folder with a short name, directly under the root folder. We installed everything under a folder called <strong>c:\devweb</strong></p>
<h3>Install Apache</h3>
<p>We recommend the use of a Windows msi installation kit. Please follow the installation steps:</p>
<ul>
<li>Proceed to <a href="http://www.apache.org/">http://www.apache.org/</a></li>
<li>Follow the link &#8220;<strong>http server</strong>&#8220;</li>
<li>Then select &#8220;<strong>download from a mirror</strong>&#8220;</li>
<li>Download the installation kit for Apache 2.2 without Crypto. You don&#8217;t need SSL for a development machine at least not for this example</li>
<li>At the time of this writing, the file name we downloaded is: <strong>apache_2.2.11-win32-x86-no_ssl.msi</strong></li>
</ul>
<p>Now run the installation kit. Choose the installation folder under the c:\devweb as mentioned above. We chose: <strong>c:\devweb\apache2.2.11\</strong></p>
<h3>Install PHP</h3>
<p>There are Windows installation kits .msi available for PHP as well. That means that the PHP installation is as simple as the one we just did for Apache http server. </p>
<p>Please follow the installation steps as follows:</p>
<ul>
<li>Proceed to <a href="http://www.php.net/">http://www.php.net/</a></li>
<li>Select the link under <strong>Stable Releases</strong> that points to the latest PHP version ready for production</li>
<li>Download and launch the installation kit</li>
<li>Select the folder where PHP will be installed; we chose <strong>C:\devweb\php\</strong></li>
<li>When asked for which web server you require installation, please <strong>carefully </strong> select the web server that that will be used &#8211; as per the previous paragraph, we chose <strong>Apache 2.2</strong></li>
<li>When asked, select the Apache subfolder where httpd.conf resides &#8211; in our case, <strong>c:\devweb\apache2.2.11\conf</strong>. The PHP installation kit will appropriately modify the Apache configuration file to point to the newly installed version</li>
<li>Select the extensions that are to be installed during the current process. Please consider that in this case less is more, and only select what you need. We selected only mysql and mysqli. If you need other extensions in the future, just run the PHP installation script again and add the required extensions (the current installation settings will not be affected)</li>
</ul>
<p>The installation will then be completed. You are now ready to test it. Before doing so, please have a look at the file <strong>httpd.conf</strong> in the Apache configuration folder to see what are the changes operated during PHP installation. You will see the following lines added at the end:</p>
<pre style="font-size:12px;">
#BEGIN PHP INSTALLER EDITS - REMOVE ONLY ON UNINSTALL
PHPIniDir "C:/devweb/php/"
LoadModule php5_module "C:/devweb/php/php5apache2_2.dll"
#END PHP INSTALLER EDITS - REMOVE ONLY ON UNINSTALL
</pre>
</p>
<ul>
<li>Restart the Apache server using the Apache monitor (see the icon in the tray) or directly restart the corresponding Windows service using the management console</li>
</ul>
<p><a href="http://proghowto.com/wp-content/uploads/2011/02/monitor.jpg"><img src="http://proghowto.com/wp-content/uploads/2011/02/monitor.jpg" alt="" title="monitor" width="213" height="109" class="size-full wp-image-9" /></a></p>
<ul>
<li><span style="color:red"><strong>Rename</strong></span> the file <strong>index.html</strong> at the location c:\devweb\apache2.2.11\htdocs to <strong>index.php</strong> and open it for editing</li>
<li>Delete all the existent html and insert the following:</li>
</ul>
<pre style="font-size:12px;">
<font color="#2040a0"><strong><font color="4444FF"><strong>&lt;</strong></font><font color="#2040a0">html</font><font color="4444FF"><strong>&gt;</strong></font></strong></font>
<font color="#2040a0"><strong><font color="4444FF"><strong>&lt;</strong></font><font color="#2040a0">head</font><font color="4444FF"><strong>&gt;</strong></font></strong></font>
<font color="#2040a0"><strong><font color="4444FF"><strong>&lt;</strong></font><font color="#2040a0">title</font><font color="4444FF"><strong>&gt;</strong></font></strong></font>Test functionality php<font color="#2040a0"><strong><font color="4444FF"><strong>&lt;</strong></font><font color="#2040a0">/title</font><font color="4444FF"><strong>&gt;</strong></font></strong></font>
<font color="#2040a0"><strong><font color="4444FF"><strong>&lt;</strong></font><font color="#2040a0">/head</font><font color="4444FF"><strong>&gt;</strong></font></strong></font>
<font color="#2040a0"><strong><font color="4444FF"><strong>&lt;</strong></font><font color="#2040a0">body</font><font color="4444FF"><strong>&gt;</strong></font></strong></font>
<font color="#2040a0"><strong><font color="4444FF"><strong>&lt;</strong></font><font color="#2040a0">?php
</font>  <font color="#2040a0">phpinfo();
?</font><font color="4444FF"><strong>&gt;</strong></font></strong></font>
<font color="#2040a0"><strong><font color="4444FF"><strong>&lt;</strong></font><font color="#2040a0">/body</font><font color="4444FF"><strong>&gt;</strong></font></strong></font>
<font color="#2040a0"><strong><font color="4444FF"><strong>&lt;</strong></font><font color="#2040a0">/html</font><font color="4444FF"><strong>&gt;</strong></font></strong></font>
</pre>
<ul>
<li>Access the index.php at the url <a href="http://localhost/index.php">http://localhost/index.php</a>. You should show a lengthy table that contains all the PHP configuration information. </li>
<li>Please search for the extension names you mentioned at the PHP installation (we mentioned mysql and mysqli) and double check they are there. </li>
</ul>
<p><a href="http://proghowto.com/wp-content/uploads/2011/02/php_info.jpg"><img src="http://proghowto.com/wp-content/uploads/2011/02/php_info.jpg" alt="" title="php_info" width="307" height="115" class="size-full wp-image-10" /></a></p>
<p>At this moment you are done, and (almost) ready to start the development activity on your computer. </p>
<h3>Install MySQL</h3>
<p>We want a similar easy installation process for MySQL as well. Follow the steps:</p>
<ul>
<li>Proceed to the address http://www.mysql.org</li>
<li>Click on &#8220;downloads&#8221;</li>
<li>Under the title MySQL Community Server, click on the &#8220;Download&#8221; button</li>
<li>Proceed with all the needed steps until you are in position to download the intallation kit. Under the Windows binaries, there are many options, please choose the msi insallation kit. At the time of this writing, the file we downloaded is mysql-5.1.34-win32.msi</li>
</ul>
<p>Now you can proceed with the installation. There are many steps to follow, please run the installation kit and consider the following:</p>
<ul>
<li>Don&#8217;t use &#8220;default configuration&#8221; or &#8220;default installation&#8221; as you will have to choose some of the settings different than the default ones</li>
<li>Install the MySQL under the same top folder as PHP and Apache. We installed ours in C:\devweb\mysql5.1</li>
<li>Choose it to run as a service. It is extremely convenient.</li>
<li>Choose a root password different than empty one (we chose the word &#8220;password&#8221;).</li>
<li>Just to be on the safe side, after the MySQL installation is done, please restart the Apache web server</li>
</ul>
<p>Now we are in position to test the end to end installation. We already confirmed that Apache works nicely with our PHP installation, now we have to test that MySQL can be accessed from our PHP scripts</p>
<p>Edit again the file index.php under the folder c:\devweb\apache2.2.11\htdocs (the Apache default document root) and paste the script below. The script connects to the database using the root account you just created and lists the existent databases. Most likely this is the only time you will ever use this sql from a PHP page, however right now it will do the job by showing us we can access the database server from our PHP script.</p>
<pre style="font-size:12px;">
&lt;?php
	// try to test the database
	// access from the current
	// machine - the program should
	// appropriately list the databases
	// that are currently available on
	// the current machine db server

	$sql = &quot;show databases&quot;;
	$connection =
		mysqli_connect(&quot;localhost&quot;, &quot;root&quot;, &quot;password&quot;);

	$statement = $connection-&gt;prepare($sql);
	$statement-&gt;bind_result($val);
	$statement-&gt;execute();

	$items = array();
	while($statement-&gt;fetch()){
		$items[] = $val;
	}

	$html = &quot;&quot;;
	$index = 0;
	foreach($items as $current){
		$index ++;
		$html .= &quot;value at index:
			{$index} is:
			&lt;strong&gt;{$current}&lt;/strong&gt; &lt;br/&gt;&quot;;
	}
?&gt;
&lt;html&gt;
&lt;head&gt;
	&lt;title&gt;Test database access&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
	&lt;?php echo $html; ?&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Now we are 100% done and ready to start the development. You have to update Apache configuration to have an alias for each project you work at, so that you will be able to work a couple of projects at a time without having to restart Apache every time, however this is just a detail, your main development environment is ready.</p>
]]></content:encoded>
			<wfw:commentRss>http://proghowto.com/configure-apache-php-and-mysql/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

