<?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>Penguin Dreams &#187; Blog</title>
	<atom:link href="http://penguindreams.org/category/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://penguindreams.org</link>
	<description></description>
	<lastBuildDate>Thu, 24 Jun 2010 19:50:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>My Account&#8217;s Been Hacked (No It Hasn&#8217;t)</title>
		<link>http://penguindreams.org/blog/my-accounts-been-hacked-no-it-hasnt/</link>
		<comments>http://penguindreams.org/blog/my-accounts-been-hacked-no-it-hasnt/#comments</comments>
		<pubDate>Thu, 24 Jun 2010 19:50:50 +0000</pubDate>
		<dc:creator>sumdog</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://penguindreams.org/?p=360</guid>
		<description><![CDATA[Recently I&#8217;ve seen unsolicited SPAM e-mails coming directly from other peoples&#8217; e-mail and social networking accounts. They&#8217;ll often post messages afterwords claiming that their accounts had been hacked. I&#8217;ll usually ask these friends, &#8220;Do you use the same password on multiple websites?&#8221; and the ensuing &#8220;Yes&#8221; response from them is followed by, &#8220;Change your e-mail [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I&#8217;ve seen unsolicited <span class="caps">SPAM </span>e-mails coming directly from other peoples&#8217; e-mail and social networking accounts. They&#8217;ll often post messages afterwords claiming that their accounts had been <em>hacked</em>. I&#8217;ll usually ask these friends, &#8220;Do you use the same password on multiple websites?&#8221; and the ensuing &#8220;Yes&#8221; response from them is followed by, &#8220;Change your e-mail password, and also, you need to learn something about password security.&#8221;<br />
<span id="more-360"></span><br />
If your e-mail or social networking (Twitter, Facebook, et cetera) account is sending out unsolicited messages on your behalf, it is unlikely your account has been <em>hacked</em> and much more likely that either your password has been scraped or that you&#8217;ve granted 3rd party access to a malicious service or application. If neither of these has occurred, then there is a possibility that you account has indeed been compromised using some type of exploit, however this typically is not the case.</p>

<p><strong>Password Security</strong></p>

<p>How can someone gain access to your e-mail account without knowing your password? Have you ever signed up for a new website or service you wanted to try out? Did you give them your e-mail address during registration? Did you use the same password you used for your e-mail account?</p>

<p>Newer websites and services that haven&#8217;t been globally trusted may be scraping your passwords during registration and testing them against the e-mail account you provided. Once gaining access, it&#8217;s easy to scan e-mail for messages from other services and begin requesting access to other accounts associated with it. </p>

<p>You may have also registered with a new website or web service that is not necessarily malicious. They may just be storing your password insecurely and unencrypted. A potential hacker may have discovered a security exploit allowing them to access that password data.</p>

<p>The solution isn&#8217;t to simply use only trusted sites. Using new services and trying new concepts is what helps the Internet grow. Plus, even large trusted services can have their security compromised by badly written code allowing third parties to gain access to your data. The better solution is to use unique password for every website. How would you remember a unique password for every website? You&#8217;d use a password algorithm.   </p>

<p><strong>Password Algorithms</strong></p>

<p>Many Internet users typically use the same password for multiple systems. Some people use a slightly more secure technique of having different levels of passwords. They may use one for unsecured sites, such as social networking or instant messaging, another for secure sites such as e-mail and a very strong one for computer and bank passwords. Although this is better than using the same password everywhere, it&#8217;s not replacement for the security provided by a unique password algorithm. </p>

<p>A good password algorithms can be based off the website the password is intended for. For instance, you can take the first or last letter of the website, combine it with a pin number or short password, and then tack on a character representing something else about the site. For example, you could add a letter representing the top level domain (e.g. The letter &#8216;A&#8217; for .com, &#8216;S&#8217; for .net, &#8216;D&#8217; for .org and &#8216;F&#8217; for others). </p>

<p>You could also use something on the site itself, like the company&#8217;s primary color or the background color of the website. Although using something on the page itself may change over time, this may also force you to continually change and rotate out passwords. </p>

<p>You can be creative and find many different ways to create a good password system. However there are a few basic rules you should try to follow to ensure good password selections. </p>


<ul>
<li>Make sure your pattern will always give you a password with at least one capital letter, one lowercase letter and one number</li>
<li>Ensure your system always gives you a password between 8 and 9 characters long. Many websites have restrictions on length and 8 or 9 characters ensures your password will never be too short or two long</li>
<li>Avoid special characters. Many websites ban these (due to ignorance) for security and it&#8217;s much more difficult to remember exceptions to your password system. </li>
<li>Chose a system you can remember easily, but that&#8217;s not easy to understand should someone get a hold of one of your passwords. </li>
</ul>



<p>In addition to individual passwords for each website, you should also have secure passwords for non-web related systems such as company computers/networks and home computers. </p>

<p>You don&#8217;t need to change every password at once when you come up with an algorithm. Just start changing passwords as you access sites you use more frequently. Whenever you access a website with your old password, go into that website&#8217;s account options and change it. You can then gradually adjust to a new password algorithm over the course of a few weeks. </p>

<p><strong>Additional Tips</strong></p>


<ul>
<li>Never use your web browser&#8217;s password store to remember passwords for you. Turn it off, remember your password system and commit them to memory.</li>
<li>Always remember to log-off your accounts on computers that are not yours or that you cannot secure. </li>
</ul>



<p><strong>Security Questions</strong></p>

<p>One serious piece of contention in the network security industry are the increasing use of security questions. Although they are used to alleviate customer services calls, the questions themselves are easily guessable.  </p>

<p>In an 2009 <span class="caps">IEEE</span> Symposium on Security and Privacy, researchers from Microsoft and Carnegie Mellon University showed that in a study involving 130 people, 28% of the people who were known and trusted by the studies participants could guess the correct answers to participants&#8217; security questions. Even people not trusted still had a 17% chance of guessing a participant&#8217;s answers<sup class="footnote"><a href="#fn1">1</a></sup>. </p>

<p>Some security experts suggest typing in random letters for security questions, going through the additional burden of calling the company should one&#8217;s user account become locked. Others suggest using a similar password algorithm as described above to generate a separate password for the security question. Without doing one or the other, the system a user is accessing gains an automatic backdoor to his or her account, defeating the purpose of having password based security in the first place. </p>

<p>A better solution to using security questions is to use reset codes sent to user&#8217;s e-mail addresses, or combining an e-mailed reset code with both security questions and locking an account after several bad attempts. While this is a better solution, many websites cannot implement these e-mail based password reset systems because they allow multiple accounts to use the same e-mail address.</p>

<p><strong>Authentication without Password</strong></p>

<p>Another item to watch out for are services which ask for a password to another services. For example, a new social networking site that may ask for your e-mail password in order to search for friends that might be using the new service. While at one time this was the only way for third parties to access information on your account, it isn&#8217;t any longer.<br />
<img src="http://penguindreams.org/files/2010/06/twitter-oauth.png" alt="" title="Twitter&amp;#039;s OAuth Permissions" width="400" class="alignright size-full wp-image-367" />
Now almost all major services support some type of single sign-on authentication. Twitter uses an OAuth based system, Facebook has their own Facebook Connect system, Microsoft has LiveID and Google has third party account authentication. These systems work by directing you to a given service (Facebook, Twitter, Google, etc.) with a security token. On that site, you log-in and authorize the token granting the other website limited access to your account. </p>

<p>The advantage of this system is that if the 3rd party service does start doing something malicious, such as sending spam messages to your contacts, you can simply revoke the applications access to your account without having to change any passwords. Most services even allow their users to report malicious applications, which could cause their application tokens to be rejected permanently for all users. </p>

<p><strong>Conclusions</strong></p>

<p>Password security is critical in a world where so much of your personal information an accounts can be accessed electronically. Developing and protecting a good password system is more important in many ways than defending your social security number. </p>

<p>At a minimum, you should have different levels of passwords: An insecure password for social networking websites and other trivial services, a high security password for e-mail, payment accounts and other high security services, and finally an ultra secure password for critical websites such as on-line banking. </p>

<p>Ideally, you should create a password algorithm for all web passwords. Algorithms should always generate 8 to 9 character passwords that include at least one capital letter and one number, and the system should be easy to remember yet difficult to understand should one or more password become compromised. </p>

<p>If a user suspects a malicious website or application has gained access to one of his or her accounts, the user should change the password on that account immediately. Using an algorithm for generating passwords ensures that other accounts won&#8217;t be comprised. Without it, a user may have to change password on several websites afterwords. </p>

<p>Switching to a password system from a single universal password may seem a bit cumbersome, but the transition is a lot easier than one would anticipate. I switched from a set of three passwords to an algorithm three years ago and now have a much greater degree of confidence about the security of my information.  </p>

<p><br/><br/><br/></p>

<p class="footnote" id="fn1"><sup>1</sup> <a href="http://www.technologyreview.com/web/22662/?a=f">Are Your Secret Questions Too Easily Answered?</a>. Lemons. Technology Review. May 18, 2009. </p>]]></content:encoded>
			<wfw:commentRss>http://penguindreams.org/blog/my-accounts-been-hacked-no-it-hasnt/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Running Beans Locally that use Application Server Data Sources</title>
		<link>http://penguindreams.org/blog/running-beans-that-use-application-server-datasources-locally/</link>
		<comments>http://penguindreams.org/blog/running-beans-that-use-application-server-datasources-locally/#comments</comments>
		<pubDate>Tue, 11 May 2010 14:03:15 +0000</pubDate>
		<dc:creator>sumdog</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://penguindreams.org/?p=327</guid>
		<description><![CDATA[When writing J2EE web applications, web services, enterprise Java beans (EJBs) or other pieces of code that run on a Java application server such as RedHat&#8217;s JBoss, IBM WebSphere or Apache Tomcat, a developer typically doesn&#8217;t load database drivers or connect to the database directly. Instead, a context lookup must be made in order to [...]]]></description>
			<content:encoded><![CDATA[<p>When writing <span class="caps">J2EE </span>web applications, web services, enterprise Java beans (EJBs) or other pieces of code that run on a Java application server such as RedHat&#8217;s JBoss, <span class="caps">IBM</span> WebSphere or Apache Tomcat, a developer typically doesn&#8217;t load database drivers or connect to the database directly. Instead, a context lookup must be made in order to get a <code>DataSource</code>, and from there a <code>Connection</code>. However what if one needs to run existing code locally, outside of the web server? This guide shows developers how to setup a local context so application server code can be run in a stand-alone application without modification. <br />
<span id="more-327"></span><br />
In a typical web application that uses a straight database connection without the assistance of <acronym title="Data Access Object">DAO</acronym> layer such as Hibernate or Spring <span class="caps">DAO, </span>a connection to the database is made using something like the following:</p>



<pre class="sh_sourceCode sh_java">
public class  MyServiceBean {

    public void startProcess() {
    
        DataSource ds = (DataSource) new InitialContext().lookup(&quot;jdbc/ds1&quot;);
        con = ds.getConnection();
        
        //do something with connection        
    }    
}
</pre>



<p>The <code>DataSource</code> is simply an interface which the underlying application container implements in order to allow applications to get connections. In this way, a web application server can control the way connections are handed out as well as keep connections in a pool to be reused. The information about the data source, including the driver, host name, user name, password and database name are all setup on the web application server. The way they&#8217;re configured varies depending on the server (most have a web administration console or <span class="caps">XML </span>configuration files), but all application servers provide an initial context containing references to these data sources for all running web applications. </p>

<p>If we simply tired to test this bean using a <code>main</code> function in its own stand-alone application like so:  </p>



<pre class="sh_sourceCode sh_java">
public static void main(String[] args) {        
    MyServiceBean b = new MyServiceBean();
    b.startProcess();              
}
</pre>



<p>We would get the following exception:</p>



<pre class="sh_sourceCode sh_java">
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
	at javax.naming.spi.NamingManager.getInitialContext(Unknown Source)
        .....
</pre>



<p>In order to run code which looks up a <code>DataSource</code> this way in a stand-alone application, we must create our own implementation of a <code>DataSource</code> object as well as an <code>InitialContextFactory</code>, plus several intermediary objects, and then tell our currently running <acronym title="Java Runtime Environment">JRE</acronym> to use our context object for all subsequent calls to <code>new InitialContext()</code>. Because we&#8217;re running locally, we don&#8217;t need to implement everything out of all these interfaces, just the bare minimum in order to provide <code>DataSource</code> and <code>Connection</code> objects. </p>

<p>First, we&#8217;ll look at a very quick and dirty solution. In this solution, we declare new classes directly within the main function using the <code>final</code> keyword and hard-coding the driver and connection strings. This is a quick drop to simply test a single bean. </p>



<pre class="sh_sourceCode sh_java">
public static void main(String[] args) throws SQLException, ClassNotFoundException, NamingException
{
    final class LocalDataSource implements DataSource , Serializable {

            private String connectionString;
            private String username;
            private String password;
            
            LocalDataSource(String connectionString, String username, String password) {
                this.connectionString = connectionString;
                this.username = username;
                this.password = password;
            }
            
            public Connection getConnection() throws SQLException
            {
                return DriverManager.getConnection(connectionString, username, password);
            }
    
            public Connection getConnection(String arg0, String arg1)
                    throws SQLException
            {
                return getConnection();              
            }
    
            public PrintWriter getLogWriter() throws SQLException
            {
                return null;
            }
    
            public int getLoginTimeout() throws SQLException
            {
                return 0;
            }
    
            public void setLogWriter(PrintWriter out) throws SQLException {}
    
            public void setLoginTimeout(int seconds) throws SQLException {}

    }
    
    final class DatabaseContext extends InitialContext {

        DatabaseContext() throws NamingException {}

        @Override
        public Object lookup(String name) throws NamingException
        {
            try {
                //our connection strings
                Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
                DataSource ds1 = new LocalDataSource(&quot;jdbc:mysql://dbserver1/dboneA&quot;, &quot;username&quot;, &quot;xxxpass&quot;);
                DataSource ds2 = new LocalDataSource(&quot;jdbc:mysql://dbserver1/dboneB&quot;, &quot;username&quot;, &quot;xxxpass&quot;);

                Properties prop = new Properties();
                prop.put(&quot;jdbc/ds1&quot;, ds1);
                prop.put(&quot;jdbc/ds2&quot;, ds2);
                
                Object value = prop.get(name);
                return (value != null) ? value : super.lookup(name);
            }
             catch(Exception e) {
                 System.err.println(&quot;Lookup Problem &quot; + e.getMessage());
                 e.printStackTrace();
             }  
             return null;            
        }        
        
    }

    final class DatabaseContextFactory implements  InitialContextFactory, InitialContextFactoryBuilder {

        public Context getInitialContext(Hashtable&lt;?, ?&gt; environment)
                throws NamingException
        {
            return new DatabaseContext();
        }

        public InitialContextFactory createInitialContextFactory(
                Hashtable&lt;?, ?&gt; environment) throws NamingException
        {
            return new DatabaseContextFactory();
        }
        
    }
    
    NamingManager.setInitialContextFactoryBuilder(new DatabaseContextFactory());   

    MyServiceBean b = new MyServiceBean();
    b.startProcess();
}
</pre>

<p> </p>

<p>In this example we&#8217;ll start from the bottom. Before we run our bean we see a call to <code>NamingManager.setInitialContextFactoryBuilder()</code>. This function sets the factory that will be called in our environment by all subsequent calls to <code>new InitialContext()</code> throughout our application. Underneath the hood of a web application server, this is one of the many things that happens well before a web application is loaded.  </p>

<p>The <code>DatabaseContextFactory</code> is a class we create that not only serves as a <code>ContextFacotry</code> but also a <code>ContextFactoryBuilder</code> through appropriate interfaces. Thanks to interfaces, we can simplify these two functionalities into a single class. It&#8217;s sole purpose is to return a <code>DatabaseContext</code>. </p>

<p>The <code>DatabaseContext</code> extends a regular <code>InitialContext</code> and we simply override the one function typically used by web server code, the <code>lookup()</code> function. It is here we can inject our own <code>LocalDataSource</code> objects, which return our <code>Connection</code> objects. On an actual web application server, the <code>DataSource</code> object would typically have some type of pooling mechanism that could return existing connections into a queue once the web application calls the <code>close()</code> function on them. </p>

<p>Although is is a decent quick solution, it&#8217;s really unclean and isn&#8217;t reusable without copying and pasting. It also ignores any environment parameters passed into the <code>InitialContext</code> and discards them. For a more permanent solution, each of the classes should be separated out and compatibility should be maintained with the environment properties passed in to our custom <code>Context</code> object. </p>

<p>For our clean and reusable solution, we&#8217;re only going to have one class with public visibility. It&#8217;s our factory class. All other classes will have default/package visibility because they shouldn&#8217;t be instantiated independently outside of our factory. Let&#8217;s start with the factory:</p>



<pre class="sh_sourceCode sh_java">
package org.penguindreams.db.local;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
import javax.naming.spi.InitialContextFactoryBuilder;

public class LocalContextFactory {
	/**
	 * do not instantiate this class directly. Use the factory method.
	 */
	private LocalContextFactory() {}
	
	public static LocalContext createLocalContext(String databaseDriver) throws SimpleException {

		try { 
			LocalContext ctx = new LocalContext();
			Class.forName(databaseDriver);	
			NamingManager.setInitialContextFactoryBuilder(ctx); 			
			return ctx;
		}
		catch(Exception e) {
			throw new SimpleException(&quot;Error Initializing Context: &quot; + e.getMessage(),e);
		}
	}	
}
</pre>



<p>In the above code, we&#8217;re creating a new <code>LocalContext</code>. We&#8217;re also initializing our <span class="caps">JDBC </span>driver. As with the previous example, the <code>NamingManager.setInitialContextFactoryBuilder</code> function ensures the new context we&#8217;re creating will be given to all subsequent calls made to <code>new InitialContext()</code>. Also, as with the previous example, the <code>LocalContext</code> takes both the role of an <code>InitialContextFactory</code> and an <code>InitialContextFactoryBuilder</code> through the use of interfaces. </p>



<pre class="sh_sourceCode sh_java">
package org.penguindreams.db.local;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
import javax.naming.spi.InitialContextFactoryBuilder;

class LocalContext extends InitialContext implements InitialContextFactoryBuilder, InitialContextFactory {

	Map&lt;Object,Object&gt; dataSources;
	
	LocalContext() throws NamingException {
		super();
		dataSources = new HashMap&lt;Object,Object&gt;();
	}
	
	public void addDataSource(String name, String connectionString, String username, String password) {
		this.
		dataSources.put(name, new LocalDataSource(connectionString,username,password));
	}

	public InitialContextFactory createInitialContextFactory(
			Hashtable&lt;?, ?&gt; hsh) throws NamingException {
		dataSources.putAll(hsh);
		return this;
	}

	public Context getInitialContext(Hashtable&lt;?, ?&gt; arg0)
			throws NamingException {
		return this;
	}

	@Override
	public Object lookup(String name) throws NamingException {
		Object ret = dataSources.get(name);
		return (ret != null) ? ret : super.lookup(name);
	}	
}
</pre>



<p>In the above example, we also see that we&#8217;ve allowed for some default behavior. For instance, properties that are given to initialize our <code>LocalContext</code> are stored in our local <code>HashMap</code>. If a lookup fails, we call the parent&#8217;s lookup method as well. The important function we add above is the <code>addDataSource()</code> method which creates new <code>LocalDataSource</code> to be looked up by the passed in <code>name</code> argument. Finally we have the <code>LocalDataSource</code> itself. </p>



<pre class="sh_sourceCode sh_java">
package org.penguindreams.db.local;

import java.io.PrintWriter;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import javax.sql.DataSource;

class LocalDataSource implements DataSource , Serializable {
	
	private String connectionString;
    private String username;
    private String password;
    
    LocalDataSource(String connectionString, String username, String password) {
        this.connectionString = connectionString;
        this.username = username;
        this.password = password;
    }
    
    public Connection getConnection() throws SQLException
    {
        return DriverManager.getConnection(connectionString, username, password);
    }

	public Connection getConnection(String username, String password)
			throws SQLException {return null;}
	public PrintWriter getLogWriter() throws SQLException {return null;}
	public int getLoginTimeout() throws SQLException {return 0;}
	public void setLogWriter(PrintWriter out) throws SQLException {	}
	public void setLoginTimeout(int seconds) throws SQLException {}
}
</pre>



<p>As you can see, many of the functions for the <code>DataSource</code> have been left unimplemented. We&#8217;ve only implemented enough functionality to get lookups working and to create simple, non-pooled connections for the end client. So our main function should now look something like the following:</p>



<pre class="sh_sourceCode sh_java">
public static void main(String[] args) {        
    
    LocalContext ctx = LocalContextFactory.createLocalContext(&quot;com.mysql.jdbc.Driver&quot;);
    ctx.addDataSource(&quot;jdbc/js1&quot;,&quot;jdbc:mysql://dbserver1/dboneA&quot;, &quot;username&quot;, &quot;xxxpass&quot;);
    ctx.addDataSource(&quot;jdbc/js2&quot;,&quot;jdbc:mysql://dbserver1/dboneB&quot;, &quot;username&quot;, &quot;xxxpass&quot;);
    
    MyServiceBean b = new MyServiceBean();
    b.startProcess();              
}
</pre>



<p>The call to <code>LocalContextFactory.createLocalContext()</code> initializes our environment with the <code>LocalContext</code> as the <code>InitialContext</code>. Then we can add the <code>DataSource</code> objects we need later using the <code>addDataSource()</code> method. All of our data objects are kept within their own packages and have limited visibility to ensure they can only be instantiated and fully initialized using the factory method. </p>

<p>There are some limitations to this <em>clean</em> implementation. For one, you can only use one type of database depending on what driver you specify with the <code>LocalContextFactory</code>. Also, not all of the <code>DataSource</code> methods are fully implemented, so you may run into problems in environments that depend on other functions and more complex implementations. </p>

<p>Still, the above code will work in a testing environment and, in a pinch, you can use the final classes used at the beginning of this tutorial directly in a <code>main</code> function for some quick and dirty testing. If you need a more complete implementation, the clean version of the code is an excellent starting point to begin building a full local implementation of your own custom <code>DataSource</code> objects. </p>]]></content:encoded>
			<wfw:commentRss>http://penguindreams.org/blog/running-beans-that-use-application-server-datasources-locally/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building Java EAR files using Ant</title>
		<link>http://penguindreams.org/blog/building-java-ear-files-using-ant/</link>
		<comments>http://penguindreams.org/blog/building-java-ear-files-using-ant/#comments</comments>
		<pubDate>Mon, 12 Apr 2010 03:19:12 +0000</pubDate>
		<dc:creator>sumdog</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://penguindreams.org/?p=307</guid>
		<description><![CDATA[When creating new Java web applications within an IDE such as Eclipse or NetBeans, the IDE creates a directory structure and uses its own internal builder to create WAR and EAR files. While these build tools may be convenient when starting to develop J2EE applications, when working on production grade projects, it&#8217;s important to create [...]]]></description>
			<content:encoded><![CDATA[<p>When creating new Java web applications within an <acronym title="Integrated Development Environment">IDE</acronym> such as Eclipse or NetBeans, the <span class="caps">IDE </span>creates a directory structure and uses its own internal builder to create <span class="caps">WAR </span>and <span class="caps">EAR </span>files. While these build tools may be convenient when starting to develop <span class="caps">J2EE </span>applications, when working on production grade projects, it&#8217;s important to create your own directory structure and build scripts to automate the building and deployment process. This tutorial will take you through automating the build process of a web application using Apache Ant as well as giving you a better understanding of exactly how web applications are laid-out and built within the <span class="caps">EAR </span>file. <br />
<span id="more-307"></span><br />
First let&#8217;s take a look at the structure of a web application. The following is a directory structure I created for an upcoming <a href="/tutorials/#j2eeTutorials">series of tutorials</a> on developing <span class="caps">J2EE </span>applications of which this tutorial is a part. As you can see, it&#8217;s slightly different from the version created in Eclipse or <span class="caps">IBM </span><acronym title="Rational Application Developer">RAD</acronym>. I removed the <code>WebContent</code> folder and moved my configuration files into the <code>conf</code> folder. I moved all web content, such as jsp files and images, into the <code>web</code> folder. Web app libraries and source code will be held in <code>lib</code> and <code>src</code> respectively. You can chose different names or a different origination pattern. The folder layout itself is not important as we will see later when constructing the build file. </p>

<p><img src="http://penguindreams.org/files/2010/04/ant_tutoral_dir_layout.png" alt="Web Application Directory Layout" title="Web Application Directory Layout" class="aligncenter size-full wp-image-308" /></p>

<p>Our <code>web.xml</code> for our <span class="caps">WAR </span>file is fairly basic. It contains a single servlet and a mapping to that servlet.</p>



<pre class="sh_sourceCode sh_xml">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot; xmlns:web=&quot;http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot; xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot; id=&quot;WebApp_ID&quot; version=&quot;2.5&quot;&gt;
  &lt;display-name&gt;SimpleRest&lt;/display-name&gt;
   
  &lt;servlet&gt;
  	&lt;servlet-name&gt;RestService&lt;/servlet-name&gt;
  	&lt;servlet-class&gt;org.penguindreams.service.ServiceHandler&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  
  &lt;servlet-mapping&gt;
	&lt;servlet-name&gt;RestService&lt;/servlet-name&gt; 
	&lt;url-pattern&gt;/models/*&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;	
	
&lt;/web-app&gt;
</pre>



<p>Likewise, our <code>application.xml</code>, which is used to build an <span class="caps">EAR </span>file which can contain multiple <span class="caps">WAR </span>files, is very basic. We see it only contains support for one web module.</p>



<pre class="sh_sourceCode sh_xml">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;application xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot; xmlns:application=&quot;http://java.sun.com/xml/ns/javaee/application_5.xsd&quot; xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd&quot; id=&quot;Application_ID&quot; version=&quot;5&quot;&gt;
  &lt;display-name&gt;SimpleRestEAR&lt;/display-name&gt;
  &lt;module&gt;
    &lt;web&gt;
      &lt;web-uri&gt;SimpleRest.war&lt;/web-uri&gt;
      &lt;context-root&gt;rest&lt;/context-root&gt;
    &lt;/web&gt;
  &lt;/module&gt;
&lt;/application&gt;
</pre>



<p>Our servlet overrides the <code>doGet</code> method, sets the current time as an attribute and then passes on control to a <acronym title="Java Server Page">JSP</acronym> to finish processing the request. </p>



<pre class="sh_sourceCode sh_java">
public class ServiceHandler extends HttpServlet {
	
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)  { 		
		try {			
			request.setAttribute(&quot;timeStamp&quot;, new Date().getTime() );			
			getServletConfig().getServletContext().getRequestDispatcher(&quot;/hello.jsp&quot;).forward(request,response);			
		} catch (Exception e) {
			System.err.println(&quot;Fatal Servlet Error&quot;);
			e.printStackTrace();
		}			
	}
	
}
</pre>



<p>Likewise, our <span class="caps">JSP </span>page is very simple. It just displays a header image and the resulting time.</p>



<pre class="sh_sourceCode sh_html">
&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=ISO-8859-1&quot;
    pageEncoding=&quot;ISO-8859-1&quot;%&gt;
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html  xmlns=&quot;http://www.w3.org/1999/xhtml&quot; dir=&quot;ltr&quot; &gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot; /&gt;
	&lt;title&gt;Sample Page&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
	&lt;p&gt;
		&lt;img src=&quot;images/penguindreams.gif&quot; alt=&quot;PenguinDreams&quot; /&gt;
		&lt;br /&gt;
		TimeStamp: &lt;%= request.getAttribute(&quot;timeStamp&quot;) %&gt;
	&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>



<p>So now that we have our application out of the way, let&#8217;s focus on the building process. The first part of the <code>build.xml</code> contains our variables. The sample application is built for JBoss. Depending on your web application server, the paths and variable names should be adjusted. Notice we&#8217;re pulling in both the jar libraries within our web application as well as the libraries found on the application server itself. </p>

<p>Eclipse does this automatically when you specify a server runtime. When building from an ant file, these libraries need to be specified for the build to complete. Be careful not to include libraries in your local <code>lib</code> folder that are all ready present on the application server (i.e. <span class="caps">JSF </span>libraries, Servlet <span class="caps">API,</span> Struts, log4j, et cetera). This could cause complications. For instance, deploying a <span class="caps">WAR </span>that contains a <code>log4j.jar</code> within it will cause the logging handlers within JBoss to stop working for your web application. </p>



<pre class="sh_sourceCode sh_xml">
    &lt;property name=&quot;build&quot; value=&quot;./build&quot; /&gt;
    &lt;property name=&quot;dist&quot; value=&quot;./dist&quot; /&gt;
    &lt;property name=&quot;conf&quot;  value=&quot;./conf&quot; /&gt;
    &lt;property name=&quot;src&quot;   value=&quot;./src&quot; /&gt;
    &lt;property name=&quot;lib&quot;   value=&quot;./lib&quot; /&gt;
    &lt;property name=&quot;web&quot;   value=&quot;./web&quot; /&gt;
    &lt;property name=&quot;version&quot; value=&quot;0.1&quot; /&gt;
    &lt;property name=&quot;jbossLocation&quot; value=&quot;/Users/myhomedir/jboss-6.0.0.M1/&quot; /&gt;
    &lt;property name=&quot;servletLib&quot; value=&quot;${jbossLocation}/common/lib&quot; /&gt;
    &lt;property name=&quot;deployDir&quot; value=&quot;${jbossLocation}/server/default/deploy/&quot; /&gt;
    &lt;property name=&quot;warFile&quot; value=&quot;${dist}/${ant.project.name}.war&quot; /&gt;
    &lt;property name=&quot;earFile&quot; value=&quot;${dist}/${ant.project.name}-${version}.ear&quot; /&gt;

    &lt;path id=&quot;build.classpath&quot;&gt;
	&lt;fileset dir=&quot;${lib}&quot; includes=&quot;**/*.jar&quot; /&gt;
	&lt;fileset dir=&quot;${servletLib}&quot; includes=&quot;**/*.jar&quot; /&gt;
    &lt;/path&gt;
</pre>

<p> </p>

<p>We need to create some simple cleanup and initialization targets to clear out old bytecode as well as setup our build environment. The compile task will depend on the initialization being complete and make use of the libraries we specified above. </p>



<pre class="sh_sourceCode sh_xml">
    &lt;target name=&quot;clean&quot;&gt;
    	&lt;delete dir=&quot;${build}&quot; /&gt;
    	&lt;delete dir=&quot;${dist}&quot; /&gt;
    &lt;/target&gt;

    &lt;target name=&quot;init&quot;&gt;
    	&lt;tstamp /&gt;
    	&lt;mkdir dir=&quot;${build}&quot; /&gt;
    	&lt;mkdir dir=&quot;${dist}&quot; /&gt;
    &lt;/target&gt;
    
    &lt;target name=&quot;compile&quot; depends=&quot;init&quot;&gt;
	&lt;javac srcdir=&quot;${src}&quot; destdir=&quot;${build}&quot; optimize=&quot;on&quot;&gt;
	    &lt;classpath refid=&quot;build.classpath&quot; /&gt;
	&lt;/javac&gt;
    &lt;/target&gt;
</pre>

<p> </p>

<p>The <span class="caps">WAR </span>file task is simply an extension of the <span class="caps">ZIP </span>file task that places certain types of files within the correct location of the <span class="caps">WAR </span>file. Here we specify our <code>web.xml</code> configuration file, our Java classes, the web application libraries and the static content.</p>



<pre class="sh_sourceCode sh_xml">
    &lt;target name=&quot;war&quot; depends=&quot;compile&quot;&gt;
    	&lt;war destfile=&quot;${dist}/${ant.project.name}.war&quot; webxml=&quot;${conf}/web.xml&quot;&gt;
    	  &lt;lib dir=&quot;${lib}&quot; /&gt;
    	  &lt;classes dir=&quot;${build}&quot;/&gt;
    	  &lt;zipfileset dir=&quot;${web}&quot;  /&gt; 
    	&lt;/war&gt;
    &lt;/target&gt;
</pre>

<p> </p>

<p>The resulting <span class="caps">JAR </span>file has the following structure: </p>


<pre class="sh_sourceCode sh_sh">
META-INF/
META-INF/MANIFEST.MF
WEB-INF/
WEB-INF/web.xml
WEB-INF/lib/
WEB-INF/classes/
WEB-INF/classes/org/
WEB-INF/classes/org/penguindreams/
WEB-INF/classes/org/penguindreams/service/
WEB-INF/classes/org/penguindreams/service/ServiceHandler.class
images/
hello.jsp
images/penguindreams.gif
</pre>



<p>An <span class="caps">EAR </span>file is also very simple. It&#8217;s just a collection of <span class="caps">WAR </span>files with an <span class="caps">XML </span>describing each individual web module and it&#8217;s Context Root. For this example, there is only one web module.</p>



<pre class="sh_sourceCode sh_xml">
    &lt;target name=&quot;ear&quot; depends=&quot;war&quot;&gt;
    	&lt;ear destfile=&quot;${dist}/${ant.project.name}-${version}.ear&quot; appxml=&quot;${conf}/application.xml&quot;&gt;
    		&lt;fileset dir=&quot;${dist}&quot; includes=&quot;*.war&quot; /&gt;
    	&lt;/ear&gt;
    &lt;/target&gt;
</pre>

<p> </p>

<p>Finally, we have a deployment task. Most application servers can be configured to monitor a deployment directory and automatically install <span class="caps">EAR </span>files copied into that directory. If your application server is on a different machine than your build environment, you may need to use a remote deployment task, such as those included with <span class="caps">IBM</span> WebSphere to deploy <span class="caps">EAR </span>files using either their <acronym title="Simple Object Application Protocol">SOAP</acronym> or <acronym title="Remote Method Invocation">RMI</acronym> protocols. For this example, our server is on the same machine, so we can do a simple copy:</p>



<pre class="sh_sourceCode sh_xml">
    &lt;target name=&quot;deploy&quot; depends=&quot;ear&quot;&gt;
    	&lt;copy todir=&quot;${deployDir}&quot;&gt;
    		&lt;fileset dir=&quot;${dist}&quot; includes=&quot;*.ear&quot; /&gt;
    	&lt;/copy&gt;
    &lt;/target&gt;
</pre>

<p> </p>

<p>So our final <code>build.xml</code> is shown below. Notice the project root element where we specify the project name as well as the default task to run.</p>



<pre class="sh_sourceCode sh_xml">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;project name=&quot;SimpleRest&quot; basedir=&quot;.&quot; default=&quot;ear&quot;&gt;

	&lt;property name=&quot;build&quot; value=&quot;./build&quot; /&gt;
	&lt;property name=&quot;dist&quot; value=&quot;./dist&quot; /&gt;
	&lt;property name=&quot;conf&quot;  value=&quot;./conf&quot; /&gt;
	&lt;property name=&quot;src&quot;   value=&quot;./src&quot; /&gt;
	&lt;property name=&quot;lib&quot;   value=&quot;./lib&quot; /&gt;
	&lt;property name=&quot;web&quot;   value=&quot;./web&quot; /&gt;
	&lt;property name=&quot;version&quot; value=&quot;0.1&quot; /&gt;
	&lt;property name=&quot;jbossLocation&quot; value=&quot;/Users/myhomedir/jboss-6.0.0.M1/&quot; /&gt;
	&lt;property name=&quot;servletLib&quot; value=&quot;${jbossLocation}/common/lib&quot; /&gt;
	&lt;property name=&quot;deployDir&quot; value=&quot;${jbossLocation}/server/default/deploy/&quot; /&gt;
	&lt;property name=&quot;warFile&quot; value=&quot;${dist}/${ant.project.name}.war&quot; /&gt;
	&lt;property name=&quot;earFile&quot; value=&quot;${dist}/${ant.project.name}-${version}.ear&quot; /&gt;
	
	&lt;path id=&quot;build.classpath&quot;&gt;
		&lt;fileset dir=&quot;${lib}&quot; includes=&quot;**/*.jar&quot; /&gt;
		&lt;fileset dir=&quot;${servletLib}&quot; includes=&quot;**/*.jar&quot; /&gt;
	&lt;/path&gt;
	
	&lt;target name=&quot;clean&quot;&gt;
		&lt;delete dir=&quot;${build}&quot; /&gt;
		&lt;delete dir=&quot;${dist}&quot; /&gt;
	&lt;/target&gt;
	
	&lt;target name=&quot;init&quot;&gt;
		&lt;tstamp /&gt;
		&lt;mkdir dir=&quot;${build}&quot; /&gt;
		&lt;mkdir dir=&quot;${dist}&quot; /&gt;
	&lt;/target&gt;
	
	&lt;target name=&quot;compile&quot; depends=&quot;init&quot;&gt;
		&lt;javac srcdir=&quot;${src}&quot; destdir=&quot;${build}&quot; optimize=&quot;on&quot;&gt;
			&lt;classpath refid=&quot;build.classpath&quot; /&gt;
		&lt;/javac&gt;
	&lt;/target&gt;
	
	&lt;target name=&quot;war&quot; depends=&quot;compile&quot;&gt;
		&lt;war destfile=&quot;${dist}/${ant.project.name}.war&quot; webxml=&quot;${conf}/web.xml&quot;&gt;
		  &lt;lib dir=&quot;${lib}&quot; /&gt;
		  &lt;classes dir=&quot;${build}&quot;/&gt;
		  &lt;zipfileset dir=&quot;${web}&quot;  /&gt; 
		&lt;/war&gt;
	&lt;/target&gt;
	
	&lt;target name=&quot;ear&quot; depends=&quot;war&quot;&gt;
		&lt;ear destfile=&quot;${dist}/${ant.project.name}-${version}.ear&quot; appxml=&quot;${conf}/application.xml&quot;&gt;
			&lt;fileset dir=&quot;${dist}&quot; includes=&quot;*.war&quot; /&gt;
		&lt;/ear&gt;
	&lt;/target&gt;
	
	&lt;target name=&quot;deploy&quot; depends=&quot;ear&quot;&gt;
		&lt;copy todir=&quot;${deployDir}&quot;&gt;
			&lt;fileset dir=&quot;${dist}&quot; includes=&quot;*.ear&quot; /&gt;
		&lt;/copy&gt;
	&lt;/target&gt;
&lt;/project&gt;
</pre>



<p>We now have a complete project that can be built and deployed using a simple ant command. If you prefer to deploy your project within Eclipse, you can go to Project&gt;Properties and then select Builders and New to create a new Ant Builder. Once it is configured, preforming a build within Eclipse will launch an external delegate to run the <code>build.xml</code> file. Here is the output from running the deploy task.</p>



<pre class="sh_sourceCode">
$ ant deploy
Buildfile: build.xml

init:
    [mkdir] Created dir: /Users/myhomedir/Documents/workspace/SimpleRest/build
    [mkdir] Created dir: /Users/myhomedir/Documents/workspace/SimpleRest/dist

compile:
    [javac] Compiling 1 source file to /Users/myhomedir/Documents/workspace/SimpleRest/build

war:
      [war] Building war: /Users/myhomedir/Documents/workspace/SimpleRest/dist/SimpleRest.war

ear:
      [ear] Building ear: /Users/myhomedir/Documents/workspace/SimpleRest/dist/SimpleRest-0.1.ear

deploy:
     [copy] Copying 1 file to /Users/myhomedir/jboss-6.0.0.M1/server/default/deploy

BUILD SUCCESSFUL
Total time: 1 second
</pre>



<p>Immediately afterward, we can see JBoss pickup the new <span class="caps">EAR </span>file by watching its log file.</p>



<pre class="sh_sourceCode">
01:58:53,696 INFO  [Http11Protocol] Starting Coyote HTTP/1.1 on http-127.0.0.1-8080
01:58:53,743 INFO  [AjpProtocol] Starting Coyote AJP/1.3 on ajp-127.0.0.1-8009
01:58:53,759 INFO  [AbstractServer] JBossAS [6.0.0.M1 (build: SVNTag=JBoss_6_0_0_M1 date=200912040958)] Started in 34s:58ms
01:59:05,970 INFO  [TomcatDeployment] undeploy, ctxPath=/rest
01:59:06,231 INFO  [TomcatDeployment] deploy, ctxPath=/rest
</pre>



<p>Finally, we can open a web browser, open the appropriate <span class="caps">URL </span>to our servlet as determined by both the <code>application.xml</code> and the <code>web.xml</code>.</p>

<p><img src="http://penguindreams.org/files/2010/04/ant_tutorial_sample_page.png" alt="Servlet Sample Page" title="Servlet Sample Page" class="aligncenter size-full wp-image-316" /></p>

<p>Creating a web application with an ant build file is just the beginning. The <code>build.xml</code> can be modified with additional variables and tasks to assist in deploying web applications to different environments or for running automated unit tests prior to deployment. Variables defined within the build file can be overwritten using the <code>-D</code> command line option for ant. Scripts can be created on <span class="caps">UNIX </span>servers to automatically retrieve your projects from a source control system such as <acronym title="Concurrent Version System">CVS</acronym>, Subversion or Mercurial and run the ant script within the project with a particular set of arguments based on the environment (e.g. development, test and production).</p>

<p>Using ant to build projects is essential to streamlining development of <span class="caps">J2EE </span>web application and ensures consistency in builds and deployments. This tutorial just scratches the surface of building <span class="caps">J2EE </span>applications and is part of a series of tutorials for building solid enterprise services and web applications from the ground up. The full source code for the example application shown above can be downloaded as <a href="/files/progs/j2ee-ant-example-penguindreams.tar.bz2">j2ee-ant-example-penguindreams.tar.bz2</a> or <a href="/files/progs/j2ee-ant-example-penguindreams.zip">j2ee-ant-example-penguindreams.zip</a> </p>]]></content:encoded>
			<wfw:commentRss>http://penguindreams.org/blog/building-java-ear-files-using-ant/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Java&#8217;s Checked Exceptions</title>
		<link>http://penguindreams.org/blog/javas-checked-exceptions/</link>
		<comments>http://penguindreams.org/blog/javas-checked-exceptions/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 17:48:42 +0000</pubDate>
		<dc:creator>sumdog</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://penguindreams.org/?p=301</guid>
		<description><![CDATA[Anyone who has programmed with Java should be familiar with the concept of Checked Exceptions. Although C++ and OCaml have optional support for exception checking, Java seems to be the only major programing language where it is a built-in and required part of the language. Enforcing at compile time that certain exceptions need to be [...]]]></description>
			<content:encoded><![CDATA[<p>Anyone who has programmed with Java should be familiar with the concept of <em>Checked Exceptions</em>. Although C++ and OCaml have optional support for exception checking, Java seems to be the only major programing language where it is a built-in and required part of the language. Enforcing at compile time that certain exceptions need to be caught may have seemed like a good idea at the time Java was developed, however no major languages developed since have adapted the concept. Many view <em>Checked Exceptions</em> as a design flaw. In this article, I attempt to show how this flaw can be overcome using a base exception class to encapsulate exception handling.<br />
<span id="more-301"></span><br />
Many of the libraries in java tend to throw a lot of different exceptions, especially when dealing with any type of Input/Output either on the disk or via network. Take the following example in which the <em>sendMail</em> function uses the JavaMail <span class="caps">API </span>in order to send a message:</p>



<pre class="sh_sourceCode sh_java">
try {
    sendMail(from,to,subject,body);
}
catch(AddressException e) {
    //Handle This Exception 
}
catch(UnknownHostException e) {
    //Handle This Exception
}
catch(MessagingException e) {
    //Handle This Exception
}
</pre>



<p>In some projects I would often catch the base exception class and use the <strong>instanceof</strong> keyword to clean up the exception handling as seen below. Although the code for this technique may be cleaner, it&#8217;s more difficult to add new exception types that may be introduced later by code changes:</p>



<pre class="sh_sourceCode sh_java">
String error = &quot;&quot;;
try {
    sendMail(from,to,subject,body);
}
catch(Exception x) {

    error = &quot;Internal Error: &quot;;

    if(x instanceof AddressException) {
            error += &quot;Invalid Internal Address&quot;;
    }
    else if(x instanceof UnknownHostException) {
            error += &quot;Could Not Find Mail Server&quot;;
    }
    else if(x instanceof MessagingException) {
            error += &quot;Messaging Problem&quot;;
    }
    else {
           error += &quot;Unexpected: &quot; + x.getMesssage();
    }
}
</pre>



<p>In both instances, programmers typically just log the exception and display a general error to the end user. Catching the individual exception types doesn&#8217;t really help in any meaningful way. Also, the exception message itself is often human readable and a clear indication of what error occurred. In my current projects, I use a base exception class and simply place any code that produces checked exceptions within a large try block and rethrow any exceptions as a property of my base exception class.</p>



<pre class="sh_sourceCode sh_java">
public class SimpleException extends Exception {

	private Throwable nestedException;
	
	public SimpleException(String s) {
		super(s);
	}
	
	public SimpleException(String s, Exception nestedException) {
		super(s);
		this.nestedException = nestedException;		
	}
	
	public Throwable getNestedException() {
		return this.nestedException;
	}
	
} 
</pre>

<p> </p>

<p>Using this class, the previous example would change to the following:</p>



<pre class="sh_sourceCode sh_java">
String error = &quot;&quot;;
try {
    sendMail(from,to,subject,body);
}
catch(Exception e) {
    throw new SimpleException(&quot;Error Occurred Sending E-mail&quot;,e);
}
</pre>



<p>This cleans up our code significantly. Under the old model, say that the implementation changed and new potential exceptions could possibly be thrown. Each one of those exceptions would have to be added to the throws clause to the appropriate function. If the class implemented a interface or extended and abstract class, those base methods would have to change as well, along with any code implementing the class. If we throw only one type of exception that wraps all other exceptions, we never have to worry about the method signature changing. </p>

<p>Some programmers may oppose this approach and classify it as an anti-pattern, similar to wrapping all checked exceptions in blocks that rethrow runtime exceptions. However, in my experience in working with large projects, using this approach is much cleaner and more maintainable. Furthermore, it allows Aspect Orientated Programming (AOP) interceptors to have a lot more information when dealing with exceptions.</p>

<p>This article is the first in a series of tutorials on <span class="caps">J2EE </span>development. The use of the except pattern I&#8217;ve used will be further expanded with seeing how it can integrate into web applications using Spring and <span class="caps">AOP. </span></p>]]></content:encoded>
			<wfw:commentRss>http://penguindreams.org/blog/javas-checked-exceptions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Disappointed with Zend&#8217;s PHP5 Certification</title>
		<link>http://penguindreams.org/blog/disappointe-with-zends-php5-certification/</link>
		<comments>http://penguindreams.org/blog/disappointe-with-zends-php5-certification/#comments</comments>
		<pubDate>Fri, 05 Mar 2010 04:58:20 +0000</pubDate>
		<dc:creator>sumdog</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[certification]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[market]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[rant]]></category>

		<guid isPermaLink="false">http://penguindreams.org/?p=290</guid>
		<description><![CDATA[I&#8217;ve never been a huge fan of certification. Although I understand it is supposed to help gauge an industry benchmark in a given field, I often feel like it&#8217;s given the IT world a generation of good test takers who are not necessarily good designers. Still, I&#8217;ve programmed with PHP on my own for years [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve never been a huge fan of certification. Although I understand it is supposed to help gauge an industry benchmark in a given field, I often feel like it&#8217;s given the IT world a generation of good test takers who are not necessarily good designers. Still, I&#8217;ve programmed with <span class="caps">PHP </span>on my own for years and want to eventually move my career path towards that direction. I decided to get a one up and try for my Zend <span class="caps">PHP5 </span>certification. What I came away with was a massive sense in disappointment in Zend&#8217;s entire certification process.<br />
<span id="more-290"></span><br />
I bought the package deal from Zend&#8217;s website which included a study guide, ten practice tests and a voucher for an exam. First of all, the study guide wasn&#8217;t a study guide but a <span class="caps">PHP </span>manual repeating a lot of documentation that can be found on the official <span class="caps">PHP </span>website. I had passed four of the practice exams, two with a score of &#8216;Passed&#8217; and two with a score of &#8216;Excellent.&#8217; Needless to say I was surprised when I failed the actual <span class="caps">PHP5 </span>certification exam.</p>

<p>The actual exam&#8217;s questions barely intersected with the material on the practice exams. Many of the questions weren&#8217;t even covered in the <span class="caps">PDF </span>that Zend labeled a &#8220;Study Guide.&#8221; I checked online to see if there were similar reactions over the certification test. I found one post on the Zend forms by a user named Nick A Williams that looks as if it were lost after Zend preformed an upgrade to their bulletin board software. The following is taken from the search engine cache of the forum<sup class="footnote"><a href="#fn1">1</a></sup>.  </p>

<blockquote style="background-color:#000040;color:white;padding:10px;border:1px dashed white;">
I must say I am very disappointed with the certification program so far. I have found the practice exams and study guide to be very misleading while preparing for the exam.

<p><span class="caps">ZCE</span> Study Guide<br />
The very existence of a study guide suggests its purpose is to adequately prepare the reader for the real exam, covering everything the exam questions will ask. This is extremely misleading and actually reduces the value of the book, as it is clear that there are things asked in the exam that are not touched upon in the study guide.</p>

<p>Without explicit indication of this, a potential exam taker such as myself would have no reason to believe further studying beyond the scope of the book is necessary.</p>

<p>Online Practice Exams<br />
I have found these practice exams to provide absolutely no value whatsoever. I have yet to fail a practice exam (having taken 6 so far), 3 of which were scored as &#8220;Excellent&#8221; yet I have now failed the actual exam twice. This would suggest that the practice exam does not help one to determine his/her readiness for the actual exam. If this is the case, what is the purpose of the practice exams and why does it cost money to take them?</p>

<p>Zend has established the expectation that if one passes the practice exam, the likelihood of passing the actual one is very high. A quote from Zend&#8217;s website:</p>

<p>Quote:</p>

<p>The questions on the practice test are different from the ones used in the real exam, however, they are also more difficult and complex-thus, if you score well on this exam, you should be comfortable that you are well-prepared to take the real test.</p>

<p>Combine this statement with the scores I received, and one can see how easily one can be convinced they are prepared for the real exam when, in fact, they are not.</p>

<p>Purchasing practice exams is supposed to help mitigate the potential for having to purchase re-takes of the actual exam (spend $20 for a 10-pack, aovid another $125 for a re-take). Instead, it has achieved the opposite &#8211; providing test-takers with a false sense of confidence (which is quickly shattered upon completing the actual exam).</p>

<p>So the nutshell version?</p>

<p>Test takers: Don&#8217;t bother with the study guide or the practice tests. Just <span class="caps">RTFM </span>and maybe read everything in the manual realted to the study guide&#8217;s section headings. Do that and you should be fine.</p>

<p>Zend: Adjust the descriptions for both the practice exams and study guide in your store to avoid confusion. Inform customers that the study guide is no substitute for the <span class="caps">PHP </span>manual. Remove your current practice exam description, and suggest how to properly use the practice exams for studying.</p>

I hope the adoption rate of this certification program is indeed more important to Zend than the sales volume of books/practice exams/real exams. More certified <span class="caps">PHP </span>developers will add far more value to your business objectives than a few pointless sales<sup class="footnote"><a href="#fn1">1</a></sup>.<br />
</blockquote>

<p>I don&#8217;t want to sound whiny about this at all. After all, certification exams should be somewhat difficult, be challenging and show an aptitude for the technology or language being tested over. Still, I do agree with Mr. Williams statement about how the practice material didn&#8217;t relate accurately to the actual exam. Whether this is simply due to Zend not updating their training material or if it&#8217;s an intentional attempt by Zend to gain money out of retests is unknown. </p>

<p>I also found some interesting concerns about <span class="caps">PHP5 </span>certification in the comments to a post from Michael Kimsal&#8217;s weblog back in 2008<sup class="footnote"><a href="#fn2">2</a></sup>, showing that if the material is simply out of date, it has been for a very long time.</p>

From <a href="http://www.rooftopsolutions.nl/">Evert</a><br />
<blockquote style="background-color:#000040;color:white;padding:10px;border:1px dashed white;">
I&#8217;ve tried the Zend Certification Training, I thought it was absolute bullshit (about 1/2 years ago). The exam tested on things like order of parameters and lots of stuff that can be found in the <span class="caps">PHP </span>manual.

It&#8217;s much more important for new hires if they have problem solving skills, including being able to go to the manual, instead of memorizing it. Real skill comes from experience and being a good <span class="caps">PHP </span>developer means writing maintainable, secure and scalable code. Not being able to know the manual inside-out.<br />
</blockquote>

And another from Rb:<br />
<blockquote style="background-color:#000040;color:white;padding:10px;border:1px dashed white;">
<span class="caps">FYI</span>: I took the <span class="caps">PHP </span>architect <span class="caps">PHP</span> 5 certification class, studied the <span class="caps">PHP</span> 5 Zend certification guide, took the online practice tests and passed. I have been coding <span class="caps">PHP </span>for 6 years. Yet I failed the Zend certification test. The test feedback was non-existent.

I feel I am a better coder because I have studied. I will not waste my time to take the Zend Certification exam again.<br />
</blockquote>

<p>Having been in Java web development for over three years, I also feel like I&#8217;m slowly being priced out of the market. Although tools like Spring have eased the burden of Java development in some ways, I still feel like scripting languages like <span class="caps">PHP,</span> Python and Ruby are vastly superior in web development to Java. </p>

<p>The horrors of Java Server Faces (JSF) attempt to turn the web into a component based system that <span class="caps">HTML </span>was never intended for. Like its .NET competitors based around C# and VisualBasic.NET, I think <span class="caps">JSF </span>abstracts way too much of the underlying <span class="caps">HTML </span>and makes it very difficult to accomplish the same tasks accomplished easily and cleanly in scripting languages and frameworks. </p>

<p>Although I feel gaining <span class="caps">PHP5 </span>certification would open me to more opportunities in that job market, I do not believe it will make me a better programmer at this point. I may simply focus on creating more tutorials and release some of my own custom framework designs to show my knowledge in the field. I&#8217;d hope that good potential employers would look past my resume to my portfolio. </p>

<p><br /><br/><br/></p>

<p class="footnote" id="fn1"><sup>1</sup> <a href="http://74.125.113.132/search?q=cache%3ALn2h-fQzNfwJ%3Ahttps%3A%2F%2Fwww.zend.com%2Fen%2Fforums%2Findex.php%3Ft%3Dmsg%26goto%3D17494%26S%3D4db1b82daa429981fba1b5d076c9344f+php+certificate+practice+exam+misleading&amp;cd=1&amp;hl=en&amp;ct=clnk&amp;gl=us&amp;client=firefox-a">Certification Exam &#8211; Very Disappointed &#8211; <span class="caps">PHP</span> Certification &#8211; <span class="caps">PHP </span>support &amp; tips &#8211; Zend.com.</a> Retrieved from Google Cache on March 4, 2010. <a href="https://www.zend.com/en/forums/index.php?t=msg&amp;goto=17494&amp;S=4db1b82daa429981fba1b5d076c9344f">Original</a> cached December 30, 2009</p>

<p class="footnote" id="fn2"><sup>2</sup> <a href="http://michaelkimsal.com/blog/php-certification-views/"><span class="caps">PHP </span>certification views?</a> Michael Kimsal. May 27, 2008. Retrieved on March 4, 2009.</p>]]></content:encoded>
			<wfw:commentRss>http://penguindreams.org/blog/disappointe-with-zends-php5-certification/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>TweeFlood</title>
		<link>http://penguindreams.org/blog/tweeflood/</link>
		<comments>http://penguindreams.org/blog/tweeflood/#comments</comments>
		<pubDate>Mon, 23 Nov 2009 13:50:32 +0000</pubDate>
		<dc:creator>sumdog</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[blueprint]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[smarty]]></category>
		<category><![CDATA[tweeflood]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://penguindreams.org/?p=278</guid>
		<description><![CDATA[I just finished my latest web application project: TweeFlood. For those of you on Twitter, TweeFlood is a way to see how much you and your friends tweet. It displays statistics for how often your friends tweet per year, month, day and hour. Try it out and follow @TweeFlood. This project uses a lot of [...]]]></description>
			<content:encoded><![CDATA[<p>I just finished my latest web application project: <a href="http://tweeflood.com">TweeFlood</a>. For those of you on Twitter, TweeFlood is a way to see how much you and your friends tweet. It displays statistics for how often your friends tweet per year, month, day and hour. Try it out and follow <a href="http://twitter.com/tweeflood">@TweeFlood</a>.</p>

<p><span id="more-278"></span></p>

<p>This project uses a lot of different open source libraries including <a href="http://www.smarty.net">Smarty</a>, <a href="http://github.com/jmathai/twitter-async">twitter-async</a>, <a href="http://jquery.com">jQuery</a>, <a href="http://www.blueprintcss.org">Blueprint</a>, <a href="http://tablesorter.com">TableSorter</a>. The main engine is built upon parts of a <span class="caps">PHP </span>framework I started developing almost a year ago. I stopped development on the framework and started utilizing WordPress for all my content-based websites. </p>

<p>I may go back and start development on my framework again and experiment with new web application ideas that don&#8217;t fit into the standard content model of a blog.</p>]]></content:encoded>
			<wfw:commentRss>http://penguindreams.org/blog/tweeflood/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Installing Awstats on a Media Temple grid-server (gs)</title>
		<link>http://penguindreams.org/blog/installing-awstats-on-a-media-temple-grid-server-gs/</link>
		<comments>http://penguindreams.org/blog/installing-awstats-on-a-media-temple-grid-server-gs/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 17:10:56 +0000</pubDate>
		<dc:creator>sumdog</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://penguindreams.org/?p=243</guid>
		<description><![CDATA[I&#8217;ve been using Media Temple for web hosting for a while. Like any other host, they have their advantages and disadvantages. One of the biggest problems with Media Temples is that their basic grid-server (gs) package only allows for very simple statistics gathering using Urchin. It is so simple that it combines hit counts from [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been using Media Temple for web hosting for a while. Like any other host, they have their advantages and disadvantages. One of the biggest problems with Media Temples is that their basic grid-server (gs) package only allows for very simple statistics gathering using Urchin. It is so simple that it combines hit counts from all websites into one graph unless users purchase additional grid-server units. Although Media Temple provides raw access logs, the way virtual hosts have been setup causes difficulty when attempting to use their logs with a log analyzer. </p>

<p>The following tutorial goes through how to install and configure the free and open source web statistics program <a href="http://awstats.sourceforge.net/">Awstats</a> to be used with Media Temple&#8217;s grid-servers to provide analytic data from the Apache logs per each individual domain.<br />
<span id="more-243"></span> <br />
This tutorial assumes that you have a Media Temple grid-server account. It also assumes you have some basic knowledge about using Linux including shell commands, shell scripting and editing files. You should also know how to use <span class="caps">SSH </span>and work with <em>.htaccess</em> files. If any of this is unfamiliar to you, you may want to start with installing Linux on a local computer or virtual machine and practicing basic shell commands and setting up a basic web server before continuing with this tutorial. </p>

<p>In a typical grid-server account, there is a symbolic link created in the primary user&#8217;s home directory called <em>domains</em> which points to a data directory containing all the individual domain&#8217;s document roots. For this tutorial, we&#8217;ll create a a <em>WebApps</em> folder within the domains folder, install awstats into that folder and configure it for each domain. We&#8217;ll then create the data directories, create symbolic links from each website to awstats, protect those directories and setup a cron script to updated the stats automatically. Let&#8217;s get started. </p>

<p>First you&#8217;ll want to <span class="caps">SSH </span>into your grid-server. Once there, create the directories needed for awstats, download the latest source code and then untar it. Finally, create a symbolic link to aid in easier upgrades further down the road.</p>



<pre class="sh_sh sh_sourceCode">
ssh example.com
mkdir domains/WebApps
cd domains/WebApps
wget http://downloads.sourceforge.net/project/awstats/AWStats/6.95/awstats-6.95.tar.gz?use_mirror=softlayer
tar xvfz awstats-6.95.tar.gz
ln -s awstats-6.95 awstats
</pre>



<p>Awstatus uses it&#8217;s own file format to store statistics in. These files are created and updated by running Awstats against a set of Apache log files. Next, we&#8217;ll create the data directory and setup the configuration files. We&#8217;ll also move all the other web support files into into the <em>cgi-bin</em> directory, which will be necessary for correctly displaying the web statistics later.  </p>



<pre class="sh_sh sh_sourceCode">
cd awstats
mkdir data
cd wwwroot/cgi-bin/
mv ../classes ../css ../icon ../js .
</pre>



<p>Within this <em>cgi-bin</em> directory is the actual <em>awstats.pl</em> script. It&#8217;s used both to display the <span class="caps">HTML </span>stats page via a <span class="caps">CGI </span>interface and also to update the data files from the command line. Here is where you will create configuration files for each website. </p>

<p>The official installation documentation suggests using the command <em>awstats_configure.pl</em> located in the <em>tools</em> directory. It generates a configuration file and places it in the <em>config</em> directory, similar to the <em>awstats.model.conf</em> file located in the <em>cgi-bin</em> directory. It doesn&#8217;t matter which file you use as a template, but you must make sure the following attributes are set:</p>



<pre class="sh_sh sh_sourceCode">
LogFile=&quot;/home/XXXXX/users/.home/scripts/mt_logfix.py example.com |&quot;
LogType=W
LogFormat=1
LogSeparator=&quot; &quot;
SiteDomain=&quot;example.com&quot;
HostAliases=&quot;example.com www.example.com&quot;
DNSLookup=1
DirData=&quot;/home/XXXXX/domains/WebApps/awstats/data&quot;
DirIcons=&quot;/awstats/icon&quot;
DNSStaticCacheFile=&quot;dnscache.txt&quot;
DNSLastUpdateCacheFile=&quot;dnscachelastupdate.txt&quot;
</pre>



<p>Be sure to replace the <span class="caps">XXXXX </span>in this and other code examples with the number which leads to your home and data directories. The <em>example.com</em> should be replaced with your domain. The <em>HostAliases</em> should include any subdomains that you want included in this set of statistics. The other settings in the configuration file can be adjusted to your liking as well. </p>

<p>The file in the above example should be named <em>awstats.example.com.conf</em> and placed in the <em>cgi-bin</em> directory. Additional domains will need their own configuration file, placed in the same directory with the same naming convention.</p>

<p>You&#8217;ll notice in the above configuration file, there is a reference to <em>mt_logfix.py</em>. The trouble with the standard Apache logs for the way Media Temple sets up their grid-server is that it places the domain name for the virtual host in the actual path of each log entry. For example:</p>



<pre class="sh_sourceCode">
xxx.xxx.xxx.xxx - - [29/Oct/2009:12:08:24 -0700] &quot;GET /example.com/somepage.php HTTP/1.1&quot; 200 1232 &quot;-&quot; &quot;Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google
.com/bot.html)&quot;
</pre>



<p>The following python script extracts all the log entries for one particular website and removes the name of the virtual host from path. It uses the <em>logresolvemerge.pl</em> script that comes with Awstats to combined all the log files and process them sequentially. Awstats is designed so that it can process the same log file(s) multiple times by skipping over all the previous recorded entries, so you don&#8217;t need to keep track of which files you&#8217;ve processed. I&#8217;ve placed this file in a directory called <em>scripts</em> under my home, but you can place this anywhere you like, just be sure to adjust the configuration file(s) you created previously accordingly. Also be sure to set the two initial variables in the script to the correct path. </p>



<pre class="sh_python sh_sourceCode">
#!/usr/bin/env python

mergecmd = '/home/XXXXX/domains/WebApps/awstats/tools/logresolvemerge.pl'
logfiles = '/home/XXXXX/logs/access_log*'

import sys
import re
from subprocess import Popen, PIPE, STDOUT

#check for domain argument
if len(sys.argv) != 2:
  print '\nMT LogFix\n\nUsage: ./mt_logfix.py &lt;domain&gt;\n\n\tSumit Khanna - PenguinDreams.org\n'
  sys.exit()

domain = sys.argv[1]

#open logresolver
pipe = Popen([mergecmd,logfiles],stdout=PIPE,stdin=PIPE,stderr=STDOUT)


#filter for domain
for line in pipe.stdout:
   if re.search('GET /'+domain+'/',line) :
     print re.sub('GET /[a-z.]*/', 'GET /', line).strip()
</pre>

<p> </p>

<p>For this to work, logging must be enabled for your grid-server. To do this, login to the Media Temple account center, click on your server and go to the section titled &#8220;Report Settings and Logs.&#8221; Be sure the that the &#8220;Keep Logs For&#8221; drop down has a value in it. I would suggest keeping it at the maximum unless you start to run out of space. At a minimum, you must keep this setting higher than the cron settings you&#8217;ll establish for the batch script later so that no log data is lost. </p>

<p><img src="http://penguindreams.org/files/2009/11/mt-logs1.png" alt="Media Temple Awstats Tutorial - Logging 1" title="Media Temple Awstats Tutorial - Logging 1" width="389" height="193" class="alignnone size-full wp-image-265" />
<img src="http://penguindreams.org/files/2009/11/mt-logs2.png" alt="Media Temple Awstats Tutorial - Logging 2" title="Media Temple Awstats Tutorial - Logging 2" width="207" height="239" class="alignnone size-full wp-image-266" /></p>

<p>Next, setup the batch process to run Awstats at regular intervals and update our database files with the latest Apache logs. I created a simple script and placed it in the <em>scripts</em> directory located in my home directory. Be sure to adjust the path and domains. </p>



<pre class="sh_sourceCode sh_sh">
#!/bin/sh

SCMD=&quot;/home/XXXXX/domains/WebApps/awstats/wwwroot/cgi-bin/awstats.pl&quot; 

domains=&quot;example.com example.net example.org&quot;

for i in $domains; do
  $SCMD -config=$i
done
</pre>



<p>It would be nice if we could just schedule the above script to run through cron. Unfortunately running the above script via cron on Media Temple produces the following results</p>



<pre class="sh_sourceCode">
Create/Update database for config &quot;/home/XXXXX/domains/WebApps/awstats/wwwroot/cgi-bin/awstats.example.com.conf&quot; by AWStats version 6.9 (build 1.925)
From data in log file &quot;/home/XXXXX/users/.home/scripts/mt_logfix.py example.com |&quot;...
Phase 1 : First bypass old records, searching new record...
Searching new records from beginning of log file...
Jumped lines in file: 0
Parsed lines in file: 0
 Found 0 dropped records,
 Found 0 corrupted records,
 Found 0 old records,
 Found 0 new qualified records.
</pre>



<p>None of the log files are read and none of the data files are written. It would seem like a permission issue, however the cron scripts should run under the same permissions as your user account. I wrote the following script and ran it both through cron and through <span class="caps">SSH. </span></p>



<pre class="sh_sourceCode sh_sh">
#!/bin/sh

echo -e -n &quot;Who:\t&quot;
whoami
echo -e &quot;Home:\t$HOME&quot;
echo -e &quot;UID:\t$UID&quot;
echo -e &quot;EUID:\t$EUID&quot;
echo -e &quot;User:\t$USER&quot;
</pre>



<p>Here are the results running the script via <span class="caps">SSH</span>:</p>



<pre class="sh_sourceCode">
Who:    example.com
Home:   /home/XXXXX/users/.home
UID:    4----9
EUID:   4----9
User:   example.com
</pre>



<p>And here is the output of the same script when run via cron:</p>



<pre class="sh_sourceCode">
Who:	example.com
Home:	/home/XXXXX
UID:	4----9
EUID:	4----9
User:	
</pre>



<p>It&#8217;s important to note that although the username is the same, the home directory when running the script via cron is incorrect. Furthermore, the <em>$USER</em> shell variable is not established. Clearly the cron shell is running in a very different mode than a standard login shell, possibly due to security restrictions or certain patches for a hardened environment. A less than elegant solution is to establish a set of keys for <span class="caps">SSH </span>and have the cron script ssh to the local host and run the generation script. To do this, create a script called <em>generate_stats_ssh_fix.sh</em> and place it in the <em>scripts</em> directory you created earlier. </p>



<pre class="sh_sourceCode sh_sh">
#!/bin/sh

echo &quot;Using SSH Hack:&quot;
ssh -F /home/XXXXX/users/.home/.ssh/config -i /home/XXXXX/users/.home/.ssh/id_dsa localhost &quot;/home/XXXXX/users/.home/scripts/generate_stats.sh&quot;
</pre>



<p>In order for this script to work in cron, ssh must be able to login to the local machine without needing a password. Therefore it is necessary to create a <span class="caps">DSA </span>authorization key set and add the generated public key into the local authorized key store. If you are all ready familiar with <span class="caps">SSH </span>keys, this should make sense to you. If you don&#8217;t and have never setup any of the configuration files within the <em>.ssh</em> directory on your webserver before, then simply run the following:</p>



<pre class="sh_sourceCode sh_sh">
ssh-keygen -t dsa #press enter for all questions which will select the default answers
cat ~/.ssh/id_dsa.pub &gt;&gt; ~/.ssh/authorized_keys
ssh localhost #type yes when prompted to add the key fingerprint
</pre>



<p>If you don&#8217;t understand what is going on here, please read up on <span class="caps">SSH </span>keys and authorization to fully understand the security implications presented. Normally you would create a set of <span class="caps">SSH </span>keys and add the public key to a remote server&#8217;s authorized key store in order to <span class="caps">SSH </span>to it without needing a password. Here we are essentially doing the same thing, except we are connection to our local machine. We preform the connection once to add the local machines fingerprint into the <em>known_hosts</em> file. </p>

<p>Next, we take this <span class="caps">SSH </span>wrapper script and create a cron task out of it. In the account center, navigate to the cron section and add the <em>generate_stats_ssh_fix.sh</em> script as a new job. I would suggest setting up the notification e-mail initially to make sure the task is running correctly. After you&#8217;re sure it&#8217;s going, you can remove the e-mail from this field. The schedule time is up to you. I&#8217;d suggest running it once per day. </p>

<p><img src="http://penguindreams.org/files/2009/11/mt-cron1.png" alt="mt-crMedia Temple Awstats Tutorial - Cron 1" title="mt-crMedia Temple Awstats Tutorial - Cron 1" width="415" height="199" class="alignnone size-full wp-image-268" />
<img src="http://penguindreams.org/files/2009/11/mt-cron2.png" alt="Media Temple Awstats Tutorial - Cron 2" title="Media Temple Awstats Tutorial - Cron 2" width="767" height="161" class="alignnone size-full wp-image-270" /></p>

<p>Now that we have have log collection taken care of, we need to work on displaying the results. We can do this with the <em>awstats.pl</em> script. Let&#8217;s start by creating a <em>.htaccess</em> file within the <em>/home/XXXXX/users/.home/domains/WebApps/awstats/wwwroot/cgi-bin</em> directory:</p>



<pre class="sh_sourceCode">
AddHandler cgi-script .pl
Options +ExecCGI

AuthName &quot;Restricted Area&quot;
AuthType Basic
AuthUserFile /home/XXXXX/domains/WebApps/awstats/wwwroot/cgi-bin/.htpasswd
AuthGroupFile /dev/null
&lt;LIMIT POST GET&gt;
  require user someuser
&lt;/LIMIT&gt;
</pre>



<p>With this <em>.htaccess</em> file, we&#8217;re doing two things. The first is granting this directory permissions to execute <span class="caps">CGI </span>scripts. The second is restricting access based on an <em>.htpasswd</em> file. In the above example I place the password file within the same directory as the <span class="caps">CGI </span>script, but for security you may want to move it to some other location out of your web accessible folders. </p>

<p>Information on creating the actual <em>.htpasswd</em> file can be found in the <a href="http://kb.mediatemple.net/questions/248/Password+protecting+directories">Password Protecting Directories</a> article in Media Temple&#8217;s knowledge base.</p>

<p>Finally, we can create the symbolic links to our statistics pages.</p>



<pre class="sh_sourceCode sh_sh">
cd /home/XXXXX/domains/example.com/html/
ln -s /home/XXXXX/domains/WebApps/awstats/wwwroot/cgi-bin/ ./awstats
</pre>

<p> </p>

<p>You can create this link for each domain you&#8217;ve created configuration files for. Once created, you should be able to navigate to <em>http://example.com/awstats/awstats.pl</em>, enter in the username and password you established earlier with the <em>.htaccess</em> and <em>.htpasswd</em> files, and view the analytics for that particular domain. </p>

<p>Congratulations. You should now have Awstats setup on your Media Temple grid-server account. To add new domains, simply create a new configuration file and update the <em>generate_stats.sh</em> script. To upgrade to a newer version of Awstats, untar the newer version in the WebApps directory, copy over the data and configuration files and adjust the symbolic link. Although the example presented is for Awstats, the <em>mt_logfix.py</em> can be used to get the Apache web server logs in the correct format for many other log file analysis based analyzers. </p>

<p>Awstats is a decent free analytics tool. Although not as powerful as commercial solutions, it is much better than the horrid Urchin tool provided by Media Temple. Most other web hosting providers have an installation of Awstats in their basic packages. Although the process for installing it yourself with Media Temple is a bit cumbersome, it is worth it. Media Temple does have awstats installed on their dedicated virtual (dv) solutions, and hopefully they will eventually add this application into their grid-server account center, removing the need for this manual installation. </p>]]></content:encoded>
			<wfw:commentRss>http://penguindreams.org/blog/installing-awstats-on-a-media-temple-grid-server-gs/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>nVidia&#8217;s Hardware H.264 (1080p) codec for Linux</title>
		<link>http://penguindreams.org/blog/nvidias-hardware-h264-1080p-codec-in-linux/</link>
		<comments>http://penguindreams.org/blog/nvidias-hardware-h264-1080p-codec-in-linux/#comments</comments>
		<pubDate>Fri, 06 Feb 2009 19:25:32 +0000</pubDate>
		<dc:creator>sumdog</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[1080p]]></category>
		<category><![CDATA[hd]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[installation]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mplayer]]></category>
		<category><![CDATA[nvidia]]></category>
		<category><![CDATA[vdpau]]></category>

		<guid isPermaLink="false">http://penguindreams.org/?p=201</guid>
		<description><![CDATA[I spent a couple of hours getting a proprietary software H.264 codec working in Linux and even published a writeup to help others. A day later I learned from one of the people I sourced in my article that nVidia started releasing Linux drivers last November for the hardware high definition decoders found on the [...]]]></description>
			<content:encoded><![CDATA[<p>I spent a couple of hours getting a proprietary software <span class="caps">H.264 </span>codec working in Linux and even published a <a href="/blog/1080-video-in-linux-with-coreavc/">writeup</a> to help others. A day later I learned from one of the people I sourced in my article that nVidia started releasing Linux drivers last November for the hardware high definition decoders found on the 8xxx series of video cards as well as a customized version of mplayer to support the new drivers. </p>

<p>A mixture of emotions came across as I realized I wasted an entire day on a software decoder when a hardware solution was available for $30 to $40. The software solution was fairly disappointing, so I decided to try one of these new cards, an nVidia GeForce 8500 <span class="caps">GT, </span>to see if it provided a better solution. It took some work with my setup, but the results were worth it.  </p>

<p><span id="more-201"></span></p>

<p>The new interface from nVidia for hardware video decoding on Linux is known as the <em>Video Decode and Presentation <span class="caps">API </span>for <span class="caps">UNIX</span></em> or <span class="caps">VDPAU.</span> It&#8217;s been available officially since the release of the 180.22 nVidia Linux drivers in January of 2009, but has been available in beta drives since last November starting with 180.06. Drivers which support <span class="caps">VDPAU </span>will install special header files in <code>/usr/include/vdpau/</code> which are required to compile media players with <span class="caps">VDPAU </span>support.</p>

<p>The installation process is fairly straightforward. The patches for mplayer can be found on the <a href="ftp://download.nvidia.com/XFree86/vdpau/">nVidia <span class="caps">FTP </span>site</a>. The tarball contains not only the patch sets, but also a build script named <code>checkout-patch-build.sh</code>. As the name suggestes, the script checks out all the appropriate revisions of mplayer and its dependencies (libavcodec, libdvdread, etc) from a subversion repository, applies nVidia specific patches and compiles mplayer. The <code>README.txt</code> file in the package also suggests several free sample videos that can be used to test the new mplayer build.</p>

<p>To prevent conflicts with the copy of mplayer that may come with the Linux distribution and that is typically controlled by a package manager, I suggest manually installing the <span class="caps">VDPAU </span>version of mplayer by itself with its own name. The following are the commands I ran for both compiling and installation. Be sure to replace the tarball with the latest version available on the <a href="ftp://download.nvidia.com/XFree86/vdpau/">ftp site</a>.</p>



<pre class="sh_sourceCode sh_sh">
wget ftp://download.nvidia.com/XFree86/vdpau/mplayer-vdpau-3402051.tar.bz2
tar xvfj mplayer-vdpau-3402051.tar.bz2
cd mplayer-vdpau-3402051
./checkout-patch-build.sh
su 
cp ./mplayer /usr/local/bin/mplayer-vdpau
</pre>



<p>As stated earlier, the <code>README.txt</code> providers several sample files available to download to test out the decoder. I&#8217;d also suggest the following options when playing <span class="caps">H.264 </span>files:</p>



<pre class="sh_sourceCode sh_sh">
mplayer-vdpau -vo vdpau -vc ffh264vdpau -framedrop -nocorrect-pts &lt;filename&gt;
</pre>



<p>Both the <code>-framedrop</code> and <code>-nocorrect-pts</code> will help provider for smoother playback and may be helpful on older <span class="caps">CPU</span>s. On machines that can handle the playback, they shouldn&#8217;t degrade the video quality.</p>

<p>You may get an error such as the following along with no video window being displayed: </p>



<pre class="sh_sourceCode sh_sh">
Cannot find codec matching selected -vo and video format 0x31637661
</pre>



<p>This is most likely the result of having a <code>~/.mplayer/codecs.conf</code>. Current versions of mplayer do not require a <code>codecs.conf</code> as one is compiled into the player itself. A stray configuration file will override the built-in defaults and remove the nVidia provided codecs. You may see this error if you had followed my <a href="http://penguindreams.org/blog/1080-video-in-linux-with-coreavc/">previous tutorial</a> on implementing software <span class="caps">H.264 </span>decoding.</p>

<p>Fixing this issue involves either deleting the file, renaming the file or combining the <code>codecs.conf</code> in your home directory with the patched one located in nVidia&#8217;s <code>mplayer-vdpau</code> build directory.</p>

<p>Another issue can arise if you have a multi-seat system; that is a system with multiple X servers each with their own monitor, keyboard and mouse configuration. In such an environment, it is essential that the X server you want to use the <span class="caps">VDPAU </span>card with comes up first. The video card does not need to be in the first <span class="caps">PCI</span>-E slot. Mine resides in the second:</p>



<pre class="sh_sourceCode sh_sh">
 # lspci | grep nVidia
01:00.0 VGA compatible controller: nVidia Corporation NV42 [GeForce 6800 XT] (rev a2)
02:00.0 VGA compatible controller: nVidia Corporation GeForce 8500 GT (rev a1)
</pre>



<p>However in the greeter configuration file, the server that holds the GeForce 8500 card I want to use for decoding must be listed first. In my case, I use gdm on Gentoo Linux which uses <code>/etc/X11/gdm/custom.conf</code> to define server startup:</p>



<pre class="sh_sourceCode">
[servers]
0=Plasma
1=Console

[server-Plasma]
name=Plasma server
command=/usr/X11R6/bin/X -layout Plasma -novtswitch -sharevts -isolateDevice PCI:2:0:0
flexiable=true

[server-Console]
name=Console server
command=/usr/X11R6/bin/X  -layout Console -novtswitch -sharevts -isolateDevice PCI:1:0:0
flexiable=true
</pre>



<p>When I got the <span class="caps">VDPAU </span>mplayer up and running, I was very impressed by the results. Some video still jumped and sputtered in placed, but nothing too distracting from the video considering the high bitrates and quality. There was also occasional screen tearing where one frame partially overlapped a previous one. I&#8217;ve read turning off the X composite extension may help alleviate this problem although I haven&#8217;t tried this yet. </p>

<p>I&#8217;m glad nVidia is realizing the importance of capitalizing on the Linux market. <span class="caps">ATI </span>is trying to catch up with their own <a href="http://blog.mymediasystem.net/avchd/radeon-hd-video-driver/">RadeonHD</a> drivers. Linux support will be essential as it&#8217;s an ideal platform for embedded systems such as <a href="http://www.nvidia.com/object/sff_ion.html">nVidia&#8217;s Ion</a>. It could open up an entire realm of possibilities for small, affordable, set-top box and media PC solutions. </p>]]></content:encoded>
			<wfw:commentRss>http://penguindreams.org/blog/nvidias-hardware-h264-1080p-codec-in-linux/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>1080 Video in Linux with CoreAVC</title>
		<link>http://penguindreams.org/blog/1080-video-in-linux-with-coreavc/</link>
		<comments>http://penguindreams.org/blog/1080-video-in-linux-with-coreavc/#comments</comments>
		<pubDate>Wed, 28 Jan 2009 14:57:01 +0000</pubDate>
		<dc:creator>sumdog</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[1080p]]></category>
		<category><![CDATA[coreavc]]></category>
		<category><![CDATA[hd]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[installation]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mplayer]]></category>

		<guid isPermaLink="false">http://penguindreams.org/?p=191</guid>
		<description><![CDATA[I&#8217;ve got an old Pentium D 920. Over two years old, with the right ffmpeg options for mplayer and frame dropping enabled, this CPU can still play H.264 720p video at amazing quality in Linux. However, all 1080p and 1080i60 (camcorder M2TS files) choke horribly. The video drags, audio skips and the video is totally [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve got an old Pentium D 920. Over two years old, with the right ffmpeg options for mplayer and frame dropping enabled, this <span class="caps">CPU </span>can still play <span class="caps">H.264</span> 720p video at amazing quality in Linux. However, all 1080p and 1080i60 (camcorder <span class="caps">M2TS </span>files) choke horribly. The video drags, audio skips and the video is totally unwatchable. In my search for a better video codec, I came across <a href="http://www.coreavc.com">CoreAVC</a>, a closed source commercial codec for Windows, as well as the <a href="http://code.google.com/p/coreavc-for-linux/">coreavc-for-linux</a> project: an attempt to use those closed source drivers with various media players in Linux. </p>

<p>Unfortunately, the installation documents for coreavc-for-linux were months old, out-of-date and had few corrections for new bugs. The following are some of the common errors I found as well as the solutions I&#8217;ve found to get the trail version of the CoreAVC codec working on my Gentoo Linux system. <br />
<span id="more-191"></span></p>

<h3>Installation</h3>

<p>To start the installation, I created a new working directory within my home directory and checked out both the latest versions of mplayer and coreavc-for-linux (revision 82 for coreavc-for-linux and revision 28381 for mplayer). I then ran the configuration script for mplayer, applied the direct show patch from the coravc-for-linux project and proceeded to build mplayer:</p>



<pre class="sh_sourceCode sh_sh">
mkdir coreavc
cd coreavc
svn checkout http://coreavc-for-linux.googlecode.com/svn/trunk/ coreavc-for-linux
svn checkout svn://svn.mplayerhq.hu/mplayer/trunk mplayer
cd mplayer
./configure
patch -p0 &lt; ../coreavc-for-linux/mplayer/dshowserver.patch
make
</pre>



<p>At this point the new version of mplayer is ready. Rather than use the <code>make install</code> command, I wanted to keep this version of mplayer totally separate. So I copied the two executables I wanted directly to <code>/usr/local/bin</code> with new names like so:</p>



<pre class="sh_sourceCode sh_sh">
su
cp mplayer /usr/local/bin/mplayer-coreavc
cp mencoder /usr/local/bin/mencoder-coreavc
</pre>



<p>At this point we have mplayer installed, but not the codec itself or the directshow server. We&#8217;ll start with the codec first. You can signup for a free trial on the <a href="http://www.coreavc.com">official CoreAVC website</a>. I would suggest the trial version first to make sure the codec works on your system. The download contains an executable installer, so you can either install it onto a windows system or install it using wine. After the install, copy the installed codec to the <code>/usr/lib/win32</code> directory. The following example assumes you used wine. Your directory names may be different.</p>



<pre class="sh_sourceCode sh_sh">
cd ~
su
cp ~/.wine/drive_c/Program\ Files/CoreCodec/CoreAVC\ 14\ Day\ Trial\ Edition/CoreAVCDecoder.ax /usr/lib/win32/
</pre>



<p>Before we go further we&#8217;ll install the directshow server. The wiki has <a href="http://code.google.com/p/coreavc-for-linux/wiki/DshowserverInstall">instructions</a> for compiling the server or using a precompiled binary. If you&#8217;re like me, you&#8217;re running a 64-bit system and can therefor not compile the binary from source. Doing so will give you a pretty massive compile error with several <i>warning: &#8216;<i>stdcall</i>&#8216; attribute ignored</i> messages from <code>interfaces.h</code>. </p>

<p>If you have a 32-bit linux system available, either real or a <span class="caps">VM, </span>or if you have somehow mastered the magic of cross compiling (I gave up on this years ago when I tried building a cross compiler for <span class="caps">PPC</span>), you can probably make this binary yourself. If you used the latest precompiled binary in the <a href="http://code.google.com/p/coreavc-for-linux/downloads/list">downloads section</a> (r63 for Gentoo at the time of this writing) along with the 1.8.5 release of CoreAVC, you will get the following fault when trying to run it:</p>



<pre class="sh_sourceCode">
/usr/local/bin/dshowserver -c CoreAVCDecoder.ax -s 1280x720 -g 09571a4b-f1fe-4c60-9760de6d310c7c31 -b 12 -f 0x34363248 -o 0x30323449
No id specified, assuming test mode
Opening device
len: 992
ProductVersion: 1.8.5
Called unk_LoadImageA
Segmentation fault
</pre>



<p>This is due to a know issue with the 1.8.5 release of CoreAVC adding a dialog box in the initialization which is documented in <a href="http://code.google.com/p/coreavc-for-linux/issues/detail?id=62">Issue #62</a> and in a <a href="http://blog.mymediasystem.net/avchd/problems-with-coreavc-185-on-linux/">posting on Acmelabs&#8217; Blog</a>. In a <a href="http://blog.mymediasystem.net/avchd/coreavc-185-on-ubuntu/">later post</a>, Acmelab gives his readers a precompiled version of release 77 which I&#8217;ve made a copy of for download: <a href="/files/progs/dshowserver-ia32-r77-acme.tar.bz2">dshowserver-ia32-r77-acme.tar.bz2</a></p>

<p>Untar this file and copy the <code>dshowserver/dshowserver</code> and <code>loader/registercodec</code> binaries to your <code>/usr/local/bin</code>.</p>

<p>Now that you have the directshow server installed, you&#8217;ll need to add the trial serial number into mplayer&#8217;s virtual windows registry. The following command is known to work with version 1.7.0 and 1.8.5 of CoreAVC. Additional registry options can be found on the <a href="http://code.google.com/p/coreavc-for-linux/wiki/RegisterCoreAVC">wiki</a></p>



<pre class="sh_sourceCode sh_sh">
export REGISTRY=$HOME/.mplayer/registry32
registercodec -r $REGISTRY -k 
&quot;HKLM\\Software\\CoreCodec\\CoreAVC Trial\\Serial&quot; -v &quot;55555-55555-CORE-55555-55555&quot;
</pre>



<p>If you&#8217;re using the full version, you&#8217;d replace the word <em>Trial</em> with <em>Pro</em>. At this point you should be able to run the following command to test the codec:</p>



<pre class="sh_sourceCode sh_sh">
/usr/local/bin/dshowserver -c CoreAVCDecoder.ax -s 1280x720 -g 09571a4b-f1fe-4c60-9760de6d310c7c31 -b 12 -f 0x34363248 -o 0x30323449
</pre>



<p>You should get the following response:</p>



<pre class="sh_sourceCode">
No id specified, assuming test mode
Opening device
Called unk_IsDebuggerPresent
len: 992
ProductVersion: 1.8.5
Decoder supports the following YUV formats: YUY2 UYVY YV12 I420 
Decoder is capable of YUV output (flags 0x2b)
Setting fmt
Starting
Initialization is complete
</pre>



<p>You may get a serial number issue here. If you do, go back and check your registry key. Now the only thing left is the <code>~/.mplayer/codec.conf</code></p>

<p>Using the 28381 build of mplayer, I constantly got the following error using the <a href="http://code.google.com/p/coreavc-for-linux/wiki/MplayerInstallation">default instructions</a> for the <code>codec.conf</code>:</p>



<pre class="sh_sourceCode">
==========================================================================
Forced video codec: coreserve
Cannot find codec matching selected -vo and video format 0x3267706D.
Read DOCS/HTML/en/codecs.html!
==========================================================================
</pre>



<p>Also, using the default instructions on a current built of mplayer can also lead to seeing this error in the mplayer output:</p>



<pre class="sh_sourceCode">
This codecs.conf is too old and incompatible with this MPlayer release!
</pre>



<p>This is because newer version of the codecs.conf must have a <em>release</em> line at the top of the file to prevent conflicts with other codec configurations as stated in <a href="http://code.google.com/p/coreavc-for-linux/issues/detail?id=61">issue #61</a></p>

<p>After playing with my configuration file a lot and with no results, I eventually found a configuration file in <a href="http://code.google.com/p/coreavc-for-linux/issues/detail?id=28#c14">comment 28 on issue 14</a> that worked. I&#8217;ve made the configuration file available here as well: <a href="/files/progs/codecs.conf">codecs.conf</a></p>

<h3>Playback</h3>

<p>When running mplayer-coreavc, you made need the following options to force mplayer to use coreavc and also to have smooth playback. Obviously, replace the example file I have with an HD movie you have on your file system. </p>



<pre class="sh_sourceCode sh_sh">
/usr/local/bin/mplayer-coreavc -vc coreserver -framedrop -nocorrect-pts  /media/files/movies_HD/Wall-E_720p_DTS_BluRay.mkv
</pre>



<p>If you&#8217;re like me, you don&#8217;t use a frontend to mplayer and prefer to have the terminal output. If so, you can create these little scripts that will pop-up mplayer in a terminal and then use them from the &#8220;open with&#8221; menu in your favorite file manager:</p>

<p><code>/usr/local/bin/coreavc-ac3</code></p>


<pre class="sh_sourceCode sh_sh">
#!/bin/sh
gnome-terminal -e &quot;mplayer-coreavc -vc coreserver -framedrop -nocorrect-pts -ac hwac3 \&quot;$1\&quot;&quot;
</pre>




<p><code>/usr/local/bin/coreavc-dts</code></p>


<pre class="sh_sourceCode sh_sh">
#!/bin/sh
gnome-terminal -e &quot;mplayer-coreavc -vc coreserver -framedrop -nocorrect-pts -ac hwdts \&quot;$1\&quot;&quot;
</pre>



<p>The -ac options for <span class="caps">AC3 </span>or <span class="caps">DTS </span>allow for media that has embedded multi-channel audio in either Dolby Digital (AC3) or Sony (DTS) format to go through the digital output of your sound card and directly to a 5.1 surround sound receiver (if you have both a digital out on your sound card and such a receiver).</p>

<h3>Conclusions</h3>

<p>I made this guide because many of the guides I&#8217;ve seen were out of date and the steps I had to undertake spanned multiple websites, blogs and wikis. Keep in mind that if you&#8217;re reading this six months from now, this guide is probably out of date itself and there are probably never versions of CoreAVC, coreavc-for-linux and mplayer, all with new an fun interesting bugs that will take you an hour to figure out. If you find any other helpful information, please post a comment.</p>

<p>As far as the actual performance of the CoreAVC codec, it is considerably faster than ffmpeg. There is somewhat of a lag or frame delay effect I see with movies which I don&#8217;t see in ffmpeg. I&#8217;m guessing this is coming from the directshow server. However with 1080p content, the video decodes much faster and is very smooth without constant bumps and clicks, even when going through the considerable amounts of translation required to run a windows 32-bit native codec in a 64-bit Linux environment.</p>

<p>There are still a couple of artifacts I&#8217;ve found and distorted/garbage video during fast motion scenes. This may be due to the codec specific registry settings which I&#8217;ll need to play with, or it may be I&#8217;m exceeding the limitations of my processor. Your own mileage may vary.  </p>]]></content:encoded>
			<wfw:commentRss>http://penguindreams.org/blog/1080-video-in-linux-with-coreavc/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Upgrading the MacBook</title>
		<link>http://penguindreams.org/blog/upgrading-the-macbook/</link>
		<comments>http://penguindreams.org/blog/upgrading-the-macbook/#comments</comments>
		<pubDate>Wed, 31 Dec 2008 17:27:03 +0000</pubDate>
		<dc:creator>sumdog</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[battery]]></category>
		<category><![CDATA[hard drive]]></category>
		<category><![CDATA[laptop]]></category>
		<category><![CDATA[macos]]></category>
		<category><![CDATA[upgrade]]></category>

		<guid isPermaLink="false">http://penguindreams.org/?p=183</guid>
		<description><![CDATA[My MacBook is about two and a half years old. Aside from upgrading the memory to 2GB when I initially purchased it, I&#8217;ve kept it stock and it&#8217;s been a fairly reliable laptop and the most convenient laptop I&#8217;ve owned. Currently it&#8217;s also the only computer I own that will let me edit and play [...]]]></description>
			<content:encoded><![CDATA[<p>My MacBook is about two and a half years old. Aside from upgrading the memory to 2GB when I initially purchased it, I&#8217;ve kept it stock and it&#8217;s been a fairly reliable laptop and the most convenient laptop I&#8217;ve owned. Currently it&#8217;s also the only computer I own that will let me edit and play HD content. Even then, the video becomes jumpy after about fifteen to twenty seconds during the editing process. Also, the battery no longer holds enough power to keep the laptop operational for over an hour. So a few weeks back I decided some upgrades were in order: upgrading to OS X 10.5, a new 500GB hard drive and new battery.<br />
<span id="more-183"></span></p>

<h3>The Battery</h3>

<p>Looking at the simplest upgrade first: the battery. There is an excellent free utility called <a href="http://www.coconut-flavour.com/coconutbattery/">Coconut Battery</a> which allows you to not only see the current battery capacity, but look at the original capacity and the age of the laptop. Newer versions of the application allow saving data points to track the capacity and degradation of the battery. </p>

<div width="720" height="510">
<img src="http://penguindreams.org/files/2008/12/cocobatteryold.png" alt="Old Battery Stats" title="cocobatteryold" width="356" height="506" class=" size-full wp-image-186" style="float:left;" />
<img src="http://penguindreams.org/files/2008/12/cocobatterynew.png" alt="New Battery Stats" title="cocobatterynew" width="356" height="506" class=" size-full wp-image-185" style="clear:right;" />
</div>

<p>Lithium Ion (Li-Ion) batteries don&#8217;t suffer from the same <em>memory effect</em> as other types of rechargeable such Nickel Cadmium (NiCd) or Nickel-metal Hydride (NiMH). However, as can clearly been see by the screenshots above, Li-Ion batteries still degrade naturally over a period of time. After two and a half years, my laptop battery could barely hold over a third of its original capacity. In addition, it took much longer to charge as well. </p>

<p>Since the new version of Coconut Battery can save data points, I&#8217;m hoping by the time I retire this laptop that I&#8217;ll be able to be able to chart the capacity pattern of this new battery. I&#8217;m predicting it will be a natural logarithmic regression. </p>

<p>One additional thing I learned about the MacBook battery. It can not be removed while the laptop is on, even if it is plugged in. Unlike my old Dell Laptop which had two expansion slots providing for the ability to hot swap two batteries, removing the MacBook battery while hot caused the MacBook to crash and it had to be rebooted. </p>

<h3>The Hard Drive</h3>

<p><img src="http://penguindreams.org/files/2008/12/old_mac_hdd_enclosed.jpg" alt="Old Mac HDD in an External Enclosure" title="Old Mac HDD in an External Enclosure" width="211" height="158" class="aligncenter size-full wp-image-189" /></p>

<p>The previous hard drive was the standard 80GB that came with the laptop. I had found myself deleting unused applications and moving media from my laptop just so I could log and transfer video clips for editing. I eventually had to use a 40GB external <span class="caps">USB </span>drive as my video scratch disk. With dropping prices for <span class="caps">SATA </span>internal drives, I decided to upgrade to a 500GB, giving me more than enough room for all my applications and media clips. In addition, a low cost external <span class="caps">SATA </span>to <span class="caps">USB </span>enclosure allowed me to still utilize my old 80GB hard drive as an external disk.</p>

<p>Replacing the hard drive was about as simple as replacing the memory. They are both behind a plate on the side of the battery compartment. The hard drive did require a hex-screwdriver, which I did not expect.</p>

<h3>The Operating System</h3>

<p>One of the biggest reason I wanted to upgrade to MacOS 10.5 was the addition of &#8220;spaces&#8221; which is basically another term for virtual desktops. In 10.4, third party software such as <a href="http://desktopmanager.berlios.de/">Desktop Manager</a> had to be used to add in support for virtual desktops. They were buggy at best and different applications would react different to being on a virtual desktop. </p>

<p>Virtual desktops aren&#8217;t anything new or innovative. They&#8217;ve been available naively on <span class="caps">UNIX</span>/Linux systems for over a decade and as third party addons to Windows and Mac for years. The advantage of having &#8220;spaces&#8221; as part of the operating system layer itself is that newer version of applications will develop around and for the &#8220;spaces&#8221; rather than third party applications having to accommodate for other programs. </p>

<p>In addition OS X 10.5 does seem to add some speed increases. The visual additions and other small features are nice as well.</p>

<h3>Conclusions</h3>

<p>The upgrades I made were primarily to make the laptop useful again as a laptop and not just an overpriced desktop. However I did notice speed improvements when playing HD video within editing software. I&#8217;m not sure whether to attribute this to a higher efficiency from OS X 10.5 or if the larger hard drive allows the OS to have more swap space to play with (or both). In any case, these small upgrades, which cost under $200, seem to have given me some more life and years out of my laptop.    </p>]]></content:encoded>
			<wfw:commentRss>http://penguindreams.org/blog/upgrading-the-macbook/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
