Friday, 17 December 2010

Did you ever want a more fine grained configuration for webservice interceptors of Spring WS PayloadRootAnnotationMethodEndpointMapping?

You like the feature of PayloadRootAnnotationMethodEndpointMapping to map requests to methods in one @Endpoint annotated class (because your business services have the same sort of "grouping")?

Interceptors for all annotated endpoints then are all the same you configured under PayloadRootAnnotationMethodEndpointMapping:

<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
  <property name="interceptors">
    <list>
      <bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor" />
      ...
    </list>
  </property>
...
</bean>

Let's assume you want to make some webservices secure: you have to add some security interceptors to the config.

This configuration now is making ALL webservices secure...

But you want just some of them be secure and the rest without the security interceptors? ;-(

Some of you guys will end up using PayloadRootQNameEndpointMapping for secure endpoints and PayloadRootAnnotationMethodEndpointMappingfor insecure ones? Really bad...

Fortunately I had the same problem and found one solution (and only one in the whole google search!) pointing to a weblog entry (http://www.redlab.be/blog/i-tee/apigeek/java/2010/spring-ws-interceptor/) that no longer exists: ;-(
But it still remained in Google's cache: ;-)

It is from a guy called "Balder". I took the solution of making a new mapper in conjunction with a new "Interceptors" annotation and refined it to function not only on class level but even additionally on method level (speaking: on webservice request level).

So here are the classes and how to use them for configuring Interceptors on method level:

  • Interceptors.java

package com.datazuul.webapps.springws.util;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Annotation used by the MethodEndpointInterceptorAdder to add
 * interceptors to the EndpointInvocationChain.
 *
 * @see http://www.redlab.be/blog/i-tee/apigeek/java/2010/spring-ws-interceptor/
 * @author Balder
 */
@Target(value = { ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Interceptors {
  /**
   * @return the qualified names of the interceptors to be added to the
   *         invocation chain, default to an empty array
   */
  String[] qualifiers() default {};
}

  • MethodEndpointInterceptorAdder.java

package com.datazuul.webapps.springws.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.server.EndpointInvocationChain;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping;

/**
 * The MethodEndpointInterceptorAdder checks the
 * {@link MethodEndpoint#getMethod()} Method#getDeclaringClass() and
 * Method#getMethod for the {@link Interceptors} annotation. if the
 * annotation is found and declares interceptors, the beans with the given
 * beanNames will be added to the {@link EndpointInvocationChain} for this
 * call.
 *
 * @see http://www.redlab.be/blog/i-tee/apigeek/java/2010/spring-ws-interceptor/
 * @author Balder, Ralf Eichinger
 */
public class MethodEndpointInterceptorAdder extends PayloadRootAnnotationMethodEndpointMapping {
  /*
   * (non-Javadoc)
   * @see
   * org.springframework.ws.server.endpoint.mapping.AbstractEndpointMapping
   * #createEndpointInvocationChain
   * (org.springframework.ws.context.MessageContext, java.lang.Object,
   * org.springframework.ws.server.EndpointInterceptor[])
   */
  @Override
  protected EndpointInvocationChain createEndpointInvocationChain(final MessageContext messageContext,
    final Object endpoint, EndpointInterceptor[] interceptors) {
    if(endpoint.getClass().equals(MethodEndpoint.class)) {
      MethodEndpoint p = (MethodEndpoint) endpoint;
      Interceptors classInterceptors = AnnotationUtils.findAnnotation(p.getMethod().getDeclaringClass(), Interceptors.class);
      Interceptors methodInterceptors = AnnotationUtils.findAnnotation(p.getMethod(), Interceptors.class);
      HashSet allInterceptorQualifiers = new HashSet();
      if(classInterceptors != null) {
        if(classInterceptors.qualifiers().length > 0) {
          for(String interceptor : classInterceptors.qualifiers()) {
            allInterceptorQualifiers.add(interceptor);
          }
        }
      }
      if(methodInterceptors != null) {
        if(methodInterceptors.qualifiers().length > 0) {
          for(String interceptor : methodInterceptors.qualifiers()) {
            allInterceptorQualifiers.add(interceptor);
          }
        }
      }
      if(allInterceptorQualifiers.size() > 0) {
        ApplicationContext appContext = getApplicationContext();
        List list = new ArrayList();
        Iterator it = allInterceptorQualifiers.iterator();
        while(it.hasNext()) {
          String interceptor = (String) it.next();
          if(appContext.containsBean(interceptor)) {
            Object bean = appContext.getBean(interceptor);
            list.add((EndpointInterceptor) bean);
          }
        }
        if(null != interceptors) {
          list.addAll(Arrays.asList(interceptors));
        }
        interceptors = (EndpointInterceptor[]) list.toArray(new EndpointInterceptor[0]);
      }
    }
    return super.createEndpointInvocationChain(messageContext, endpoint, interceptors);
  }
}

Usage in an Endpoint class:

@Endpoint
public class PersonServiceEndpoint {
  public final static String NAMESPACE = "http://datazuul.com/schemas/person";

  @Autowired
  private PersonService personService;

  @PayloadRoot(localPart = "GetPersonRequest", namespace = NAMESPACE)
  @Interceptors(qualifiers={"payloadLoggingInterceptor"})
  // more interceptors separated by ","
  public GetPersonResponse getPerson( GetPersonRequest personRequest ) throws Exception {
    ...
  }
}

Change in Spring's configuration:

replace

<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" />

with

<bean class="com.datazuul.webapps.springws.util.MethodEndpointInterceptorAdder" />

Here you go! Individual interceptors for each request method.

Wednesday, 15 December 2010

During Maven builds some projects fail to build, because the Java Transaction API (JTA) can not be downloaded from the central Maven repository.

Solution: You have to install it into your local Maven repository manually.
  1. Download "Class Files 1.1" from http://www.oracle.com/technetwork/java/javaee/tech/jta-138684.html (or from here: https://sites.google.com/site/datazuul/jta-1_1-classes.zip)
  2. Downloaded file: jta-1_1-classes.zip
  3. Rename it to "jta-1_1-classes.jar"
  4. Install it into local Maven repository:
mvn install:install-file -DgroupId=javax.transaction -DartifactId=jta -Dversion=1.1 -Dpackaging=jar -Dfile=jta-1_1-classes.jar
  1. Download "Class Files 1.0.1B" from http://www.oracle.com/technetwork/java/javaee/tech/jta-138684.html (or from here: https://sites.google.com/site/datazuul/jta-1_0_1B-classes.zip)
  2. Downloaded file: jta-1_0_1B-classes.zip
  3. Rename it to "jta-1_0_1B-classes.jar"
  4. Install it into local Maven repository:
mvn install:install-file -DgroupId=javax.transaction -DartifactId=jta -Dversion=1.0.1B -Dpackaging=jar -Dfile=jta-1_0_1B-classes.jar

Tuesday, 14 December 2010

HTML form design is one of the most complicated design tasks. Forms are biests that do not behave like you want.
This chapter shows how to restrain them.

References

http://articles.sitepoint.com/article/fancy-form-design-css

Accessibility

  • label all sections and input elements (using "label" and "legend" tags)
  • don't use tables for layout

Labeling Form Elements

<label for="firstName">First name</label>
<input id="firstName" name="firstName" type="text" />
Label with descriptive text:
  • checkboxes
  • radio buttons
  • textareas
  • text fields (incl. upload fields)
  • select boxes (incl. selection lists)
No label needed for:
  • submit buttons / submit images (using "value" and "alt" / "title" attributes)

Grouping semantically related Elements

Grouping form elements (labeled with "label") is done via "fieldset" parent element and a descriptive "legend" element:
<form action="example.php">
  <fieldset>
    <legend>Postal Address</legend>

    <label for="street">Street address</label>
    <input id="street" name="street" type="text" />
    <label for=" suburb">Suburb</label>
    <input id="suburb" name="suburb" type="text" />
    <label for="state">State</label>
    <input id="state" name="state" type="text" />
    <label for="postcode">Postcode</label>
    <input id="postcode" name="postcode" type="text" />
  </fieldset>
</form>

Label positioning

Alternatives:
This code is the basis for layout independent form styling without tables.
<form action="#">
  <fieldset>
    <legend>Contact Details</legend>
    <ol>
      <li>
        <label for="name">Name:</label>
        <input id="name" name="name" class="text" type="text" />
      </li>
      <li>
        <label for="email">Email address:</label>
        <input id="email" name="email" class="text" type="text" />
      </li>
      <li>
        <label for="phone">Telephone:</label>
        <input id="phone" name="phone" class="text" type="text" />
      </li>
    </ol>
  </fieldset>
  <fieldset>
    <legend>Delivery Address</legend>
    <ol>
      <li>
        <label for="address1">Address 1:</label>
        <input id="address1" name="address1" class="text" type="text" />
      </li>
      <li>
        <label for="address2">Address 2:</label>
        <input id="address2" name="address2" class="text" type="text" />
      </li>
      <li>
        <label for="suburb">Suburb/Town:</label>
        <input id="suburb" name="suburb" class="text" type="text" />
      </li>
      <li>
        <label for="postcode">Postcode:</label>
        <input id="postcode" name="postcode" class="text textSmall" type="text" />
      </li>
      <li>
        <label for="country">Country:</label>
        <input id="country" name="country" class="text" type="text" />
      </li>
    </ol>
  </fieldset>
  <fieldset class="submit">
    <input class="submit" type="submit" value="Begin download" />
  </fieldset>
</form>
Comments
  • ol/li needed to have enough CSS hooks for layouting
  • class="text" etc. needed, because some browsers do not support CSS attribute selectors (just since IE7)
  • form submit inside a fieldset with class="submit" makes multiple submit actions easier to handle

Actual style (without CSS)

Independent of the final form layout, it is possible to use the same html structure. The layout can be sorted out completely to CSS. This is the live demo of the above code:
Contact Details
Delivery Address
In the previous article no CSS has been added to the form code. In this chapter we add CSS piece by piece.

Positioning/Layout independent form styling

CSS code

fieldset {
  margin: 1.5em 0 0 0;
  padding: 0;
}
legend {
  margin-left: 1em;
  color: #000000;
  font-weight: bold;
}
fieldset ol {
  padding: 1em 1em 0 1em;
  list-style: none;
}
fieldset li {
  padding-bottom: 1em;
}
fieldset.submit {
  border-style: none;
}
HTML with CSS result

Positioning of Text Labels

Labels above Fields

Additional CSS code:
label {
  display: block;
}
Result:

Labels at the left side of Fields (and left-aligned)

Complete CSS Code:
fieldset {    
  float: left;    
  clear: left;    
  width: 100%;    
  margin: 0 0 1.5em 0;    
  padding: 0;   
} 
legend {   
  margin-left: 1em;   
  color: #000000;   
  font-weight: bold;  
}  
fieldset ol {   
  padding: 1em 1em 0 1em;   
  list-style: none;  
}  
fieldset li {    
  float: left;    
  clear: left;    
  width: 100%;    
  padding-bottom: 1em;   
} 
fieldset.submit {    
  float: none;    
  width: auto;    
  border: 0 none #FFF;    
  padding-left: 12em;   
}
label {    
  float: left;    
  width: 10em;    
  margin-right: 1em;   
}
Result:

Labels at the left side of Fields (and right-aligned)

Complete CSS Code:
fieldset {    
  float: left;    
  clear: left;    
  width: 100%;    
  margin: 0 0 1.5em 0;    
  padding: 0;   
} 
legend {   
  margin-left: 1em;   
  color: #000000;   
  font-weight: bold;  
}  
fieldset ol {   
  padding: 1em 1em 0 1em;   
  list-style: none;  
}  
fieldset li {    
  float: left;    
  clear: left;    
  width: 100%;    
  padding-bottom: 1em;   
} 
fieldset.submit {    
  float: none;    
  width: auto;    
  border: 0 none #FFF;    
  padding-left: 12em;   
}
label {    
  float: left;    
  width: 10em;    
  margin-right: 1em;
  text-align: right;
}
Result:
Here is an alternative form fieldset layout, with removed boxes.






<html>
<head>
<!--[if lte IE 7]>    
<style type="text/css" media="all">@import "fieldset-styling-ie.css";</style>
<![endif]-->
<style type="text/css">
fieldset {
  position: relative;   
  float: left;      
  clear: both;      
  width: 100%;      
  margin: 0 0 -1em 0;      
  padding: 0 0 1em 0;      
  border-style: none;      
  border-top: 1px solid #BFBAB0;      
  background-color: #F2EFE9;   
}
fieldset.alt {      
  background-color: #E6E3DD;    
}
legend {
  padding: 0;     
  color: #000;     
  font-weight: bold;    
}
legend span {      
  position: absolute;
  left: 0.74em;      
  top: 0;
  margin-top: 0.3em;     
  font-size: 110%;    
}
fieldset ol {   
  padding: 1em 1em 0 1em;   
  list-style: none;  
}  
fieldset li {    
  float: left;    
  clear: left;    
  width: 100%;    
  padding-bottom: 1em;   
} 
fieldset.submit {      
  float: none;      
  width: auto;      
  padding-top: 1.5em;      
  padding-left: 12em;      
  background-color: #FFFFFF;    
}
label {    
  float: left;    
  width: 10em;    
  margin-right: 1em;
  text-align: left;
}
</style>
</head>
<body>
<form action="#">
  <fieldset>
    <legend><span>Contact Details</span></legend>
    <ol>
      <li>
        <label for="name">Name:</label>
        <input id="name" name="name" class="text" type="text" />
      </li>
      <li>
        <label for="email">Email address:</label>
        <input id="email" name="email" class="text" type="text" />
      </li>
      <li>
        <label for="phone">Telephone:</label>
        <input id="phone" name="phone" class="text" type="text" />
      </li>
    </ol>
  </fieldset>
  <fieldset class="alt">
    <legend><span>Login Details</span></legend>
    <ol>
      <li>
        <label for="username">Username:</label>
        <input id="username" name="username" class="text" type="text" />
      </li>
      <li>
        <label for="password">Password:</label>
        <input id="password" name="password" class="text" type="password" />
      </li>
    </ol>
  </fieldset>
  <fieldset>
    <legend><span>Delivery Address</span></legend>
    <ol>
      <li>
        <label for="address1">Address 1:</label>
        <input id="address1" name="address1" class="text" type="text" />
      </li>
      <li>
        <label for="address2">Address 2:</label>
        <input id="address2" name="address2" class="text" type="text" />
      </li>
      <li>
        <label for="suburb">Suburb/Town:</label>
        <input id="suburb" name="suburb" class="text" type="text" />
      </li>
      <li>
        <label for="postcode">Postcode:</label>
        <input id="postcode" name="postcode" class="text textSmall" type="text" />
      </li>
      <li>
        <label for="country">Country:</label>
        <input id="country" name="country" class="text" type="text" />
      </li>
    </ol>
  </fieldset>
  <fieldset class="alt">
    <legend><span>Payment Details</span></legend>
    <ol>
      <li>
        <label for="creditCardNumber">Credit card number:</label>
        <input id="creditCardNumber" name="creditCardNumber" class="text" type="text" />
      </li>
      <li>
        <label for="creditCardName">Credit card name:</label>
        <input id="creditCardName" name="creditCardName" class="text" type="text" />
      </li>
    </ol>
  </fieldset>
  <fieldset class="submit">
    <input class="submit" type="submit" value="Begin download" />
  </fieldset>
</form>
</body>
</html>
Internet Explorer File (fieldset-styling-ie.css):
legend {
  position: relative;    
  left: -7px;    
  top: -0.75em;   
}
legend span {      
  margin-top: 1.25em;    
}    
fieldset {    
  position: relative;   
}
fieldset ol {    
  padding-top: 3.25em;   
}
This form contains nested radio and checkbox groups inside the field column of the form.

<html>
<head>
<!--[if lte IE 7]>    
<style type="text/css" media="all">@import "fieldset-styling-ie.css";</style>
<![endif]-->
<style type="text/css">
fieldset {     
  float: left;     
  clear: both;     
  width: 100%;     
  margin: 0 0 1.5em 0;     
  padding: 0;     
  border: 1px solid #BFBAB0;     
  background-color: #F2EFE9;
  //background-image: url(images/vertical-gradient.png);
  //background-repeat: repeat-x;  
}
legend {
  margin-left: 1em;     
  padding: 0;     
  color: #000;     
  font-weight: bold;    
} 
fieldset ol {   
  padding: 1em 1em 0 1em;   
  list-style: none;  
}  
fieldset li {    
  float: left;    
  clear: left;    
  width: 100%;    
  padding-bottom: 1em;   
} 
fieldset.submit {    
  float: none;    
  width: auto;    
  border: 0 none #FFF;    
  padding-left: 12em;
  background-color: transparent;
  //background-image: none;
}
label {    
  float: left;    
  width: 10em;    
  margin-right: 1em;
  text-align: left;
}

fieldset fieldset {      
  margin-bottom: -2.5em;      
  border-style: none;      
  background-color: transparent;      
  background-image: none;      
}      
fieldset fieldset legend {      
  margin-left: 0;      
  font-weight: normal;      
}      
fieldset fieldset ol {      
  position: relative;      
  top: -1.5em;      
  margin: 0 0 0 11em;      
  padding: 0;      
}      
fieldset fieldset label {      
  float: none;
  width: auto;
  margin-right: auto;
  top: 0;  
}
</style>
</head>
<body>

<form action="#">
  <fieldset>
    <legend>Contact Details</legend>
    <ol>
      <li>
        <label for="name">Name:</label>
        <input id="name" name="name" class="text" type="text" />
      </li>
      <li>
        <fieldset>
          <legend>Occupation:</legend>
          <ol>
            <li>
              <input id="occupation1" name="occupation1" class="checkbox" type="checkbox" value="1" />
              <label for="occupation1">Doctor</label>
            </li>
            <li>
              <input id="occupation2" name="occupation2" class="checkbox" type="checkbox" value="1" />
              <label for="occupation2">Lawyer</label>
            </li>
            <li>
              <input id="occupation3" name="occupation3" class="checkbox" type="checkbox" value="1" />
              <label for="occupation3">Teacher</label>
            </li>
            <li>
              <input id="occupation4" name="occupation4" class="checkbox" type="checkbox" value="1" />
              <label for="occupation4">Web designer</label>
            </li>
          </ol>
        </fieldset>
      </li>
      <li>
        <label for="email">Email address:</label>
        <input id="email" name="email" class="text" type="text" />
      </li>
      <li>
        <label for="phone">Telephone:</label>
        <input id="phone" name="phone" class="text" type="text" />
      </li>
    </ol>
  </fieldset>
  <fieldset>
    <legend>Delivery Address</legend>
    <ol>
      <li>
        <label for="address1">Address 1:</label>
        <input id="address1" name="address1" class="text" type="text" />
      </li>
      <li>
        <label for="address2">Address 2:</label>
        <input id="address2" name="address2" class="text" type="text" />
      </li>
      <li>
        <label for="suburb">Suburb/Town:</label>
        <input id="suburb" name="suburb" class="text" type="text" />
      </li>
      <li>
        <label for="postcode">Postcode:</label>
        <input id="postcode" name="postcode" class="text textSmall" type="text" />
      </li>
      <li>
        <fieldset>
          <legend>Country:</legend>
          <ol>
            <li>
              <input id="country1" name="country" class="radio" type="radio" value="1" />
              <label for="country1">Germany</label>
            </li>
            <li>
              <input id="country2" name="country" class="radio" type="radio" value="1" />
              <label for="country2">Switzerland</label>
            </li>
            <li>
              <input id="country3" name="country" class="radio" type="radio" value="1" />
              <label for="country3">Austria</label>
            </li>
          </ol>
        </fieldset>
      </li>
    </ol>
  </fieldset>
  <fieldset class="submit">
    <input class="submit" type="submit" value="Begin download" />
  </fieldset>
</form>

</body>
</html>
Layouting (positioning of labels and form elements) is now complete. The following describes how to make the form look nice.

Problem: fieldset/legend issue in IE 6

Problem: the background color of the fieldset also renders legend and above.
Solution: separate IE6 stylesheet
Code:
<!--[if lte IE 7]>
<style type="text/css" media="all">@import "css/fieldset-styling-ie.css";</style>
<![endif]-->

legend {
  position: relative;
  left: -7px;
  top: -0.75em;
}
fieldset {
  position: relative;
}
fieldset ol {
  padding-top: 0.25em;
}

Aligned Legend and Fieldset background color (Code)

fieldset {     
  float: left;     
  clear: both;     
  width: 100%;     
  margin: 0 0 1.5em 0;     
  padding: 0;     
  border: 1px solid #BFBAB0;     
  background-color: #F2EFE9;
  background-image: url(images/vertical-gradient.png);
  background-repeat: repeat-x;  
}
legend {
  margin-left: 1em;     
  padding: 0;     
  color: #000;     
  font-weight: bold;    
} 
fieldset ol {   
  padding: 1em 1em 0 1em;   
  list-style: none;  
}  
fieldset li {    
  float: left;    
  clear: left;    
  width: 100%;    
  padding-bottom: 1em;   
} 
fieldset.submit {    
  float: none;    
  width: auto;    
  border: 0 none #FFF;    
  padding-left: 12em;
  background-color: transparent;
  background-image: none;
}
label {    
  float: left;    
  width: 10em;    
  margin-right: 1em;
  text-align: left;
}
Result just with color (without background-image, background-repeat):

Result with image (with  background-image, background-repeat):

Here is how to style required form fields.
We demonstrate two different styles:
  • textual marked fields
  • icon marked fields

Textual marked require fields

The text "Required" is placed below field label:
<html>
<head>
<!--[if lte IE 7]>    
<style type="text/css" media="all">@import "fieldset-styling-ie.css";</style>
<![endif]-->
<style type="text/css">
fieldset {     
  float: left;     
  clear: both;     
  width: 100%;     
  margin: 0 0 1.5em 0;     
  padding: 0;     
  border: 1px solid #BFBAB0;     
  background-color: #F2EFE9;
  //background-image: url(images/vertical-gradient.png);
  //background-repeat: repeat-x;  
}
legend {
  margin-left: 1em;     
  padding: 0;     
  color: #000;     
  font-weight: bold;    
} 
fieldset ol {   
  padding: 1em 1em 0 1em;   
  list-style: none;  
}  
fieldset li {    
  float: left;    
  clear: left;    
  width: 100%;    
  padding-bottom: 1em;   
} 
fieldset.submit {    
  float: none;    
  width: auto;    
  border: 0 none #FFF;    
  padding-left: 12em;
  background-color: transparent;
  //background-image: none;
}
label {    
  float: left;    
  width: 10em;    
  margin-right: 1em;
  text-align: left;
}

fieldset fieldset {      
  margin-bottom: -2.5em;      
  border-style: none;      
  background-color: transparent;      
  background-image: none;      
}      
fieldset fieldset legend {      
  margin-left: 0;      
  font-weight: normal;      
}      
fieldset fieldset ol {      
  position: relative;      
  top: -1.5em;      
  margin: 0 0 0 11em;      
  padding: 0;      
}      
fieldset fieldset label {      
  float: none;
  width: auto;
  margin-right: auto;
  top: 0;  
}
label em,legend em {        
  display: block;        
  color: #060;        
  font-size: 85%;        
  font-style: normal;        
  text-transform: uppercase;      
}
</style>
</head>
<body>

<form action="#">
  <fieldset>
    <legend>Contact Details</legend>
    <ol>
      <li>
        <label for="name">Name: <em>required</em></label>
        <input id="name" name="name" class="text" type="text" />
      </li>
      <li>
        <fieldset>
          <legend>Occupation: <em>required</em></legend>
          <ol>
            <li>
              <input id="occupation1" name="occupation1" class="checkbox" type="checkbox" value="1" />
              <label for="occupation1">Doctor</label>
            </li>
            <li>
              <input id="occupation2" name="occupation2" class="checkbox" type="checkbox" value="1" />
              <label for="occupation2">Lawyer</label>
            </li>
            <li>
              <input id="occupation3" name="occupation3" class="checkbox" type="checkbox" value="1" />
              <label for="occupation3">Teacher</label>
            </li>
            <li>
              <input id="occupation4" name="occupation4" class="checkbox" type="checkbox" value="1" />
              <label for="occupation4">Web designer</label>
            </li>
          </ol>
        </fieldset>
      </li>
      <li>
        <label for="email">Email address: <em>required</em></label>
        <input id="email" name="email" class="text" type="text" />
      </li>
      <li>
        <label for="phone">Telephone:</label>
        <input id="phone" name="phone" class="text" type="text" />
      </li>
    </ol>
  </fieldset>
  <fieldset class="submit">
    <input class="submit" type="submit" value="Begin download" />
  </fieldset>
</form>

</body>
</html>

Icon marked required fields

The following code marks required fields with an star icon

<html>
<html>
<head>
<!--[if lte IE 7]>    
<style type="text/css" media="all">@import "fieldset-styling-ie.css";</style>
<![endif]-->
<style type="text/css">
fieldset {     
  float: left;     
  clear: both;     
  width: 100%;     
  margin: 0 0 1.5em 0;     
  padding: 0;     
  border: 1px solid #BFBAB0;     
  background-color: #F2EFE9;
  //background-image: url(images/vertical-gradient.png);
  //background-repeat: repeat-x;  
}
legend {
  margin-left: 1em;     
  padding: 0;     
  color: #000;     
  font-weight: bold;    
} 
fieldset ol {   
  padding: 1em 1em 0 1em;   
  list-style: none;  
}  
fieldset li {    
  float: left;    
  clear: left;    
  width: 100%;    
  padding-bottom: 1em;   
} 
fieldset.submit {    
  float: none;    
  width: auto;    
  border: 0 none #FFF;    
  padding-left: 12em;
  background-color: transparent;
  //background-image: none;
}
label {    
  position: relative;        
  float: left;        
  width: 10em;        
  margin-right: 1em;
  text-align: left;
}

fieldset fieldset {      
  margin-bottom: -2.5em;      
  border-style: none;      
  background-color: transparent;      
  background-image: none;      
}      
fieldset fieldset legend {      
  margin-left: 0;      
  font-weight: normal;      
}      
fieldset fieldset ol {      
  position: relative;      
  top: -1.5em;      
  margin: 0 0 0 11em;      
  padding: 0;      
}      
fieldset fieldset label {      
  float: none;
  width: auto;
  margin-right: auto;
  top: 0;  
}
label em {        
  position: absolute;        
  left: 10em;        
  top: 0.4em;      
}
</style>
</head>
<body>

<p><small>Required fields are marked with <img src="icon-star-10x9.png" alt="required" />.</small></p>

<form action="#">
  <fieldset>
    <legend>Contact Details</legend>
    <ol>
      <li>
        <label for="name">Name: <em><img src="icon-star-10x9.png" alt="required" /></em></label>
        <input id="name" name="name" class="text" type="text" />
      </li>
      <li>
        <fieldset>
          <legend>Occupation: </legend>
          <ol>
            <li>
              <input id="occupation1" name="occupation1" class="checkbox" type="checkbox" value="1" />
              <label for="occupation1">Doctor</label>
            </li>
            <li>
              <input id="occupation2" name="occupation2" class="checkbox" type="checkbox" value="1" />
              <label for="occupation2">Lawyer</label>
            </li>
            <li>
              <input id="occupation3" name="occupation3" class="checkbox" type="checkbox" value="1" />
              <label for="occupation3">Teacher</label>
            </li>
            <li>
              <input id="occupation4" name="occupation4" class="checkbox" type="checkbox" value="1" />
              <label for="occupation4">Web designer</label>
            </li>
          </ol>
        </fieldset>
      </li>
      <li>
        <label for="email">Email address: <em><img src="icon-star-10x9.png" alt="required" /></em></label>
        <input id="email" name="email" class="text" type="text" />
      </li>
      <li>
        <label for="phone">Telephone:</label>
        <input id="phone" name="phone" class="text" type="text" />
      </li>
    </ol>
  </fieldset>
  <fieldset class="submit">
    <input class="submit" type="submit" value="Begin download" />
  </fieldset>
</form>

</body>
</html>
If you visit a bunch of websites, you will recognize a common layout style, that may contain the following page areas: header, menu, sidebar, main content and footer.
Here are some trackbacks to CSS-column layouts: 

JTrac is a webbased tool for tracking bugs and requirements of a software product.

Specification

  • Homepage: http://www.jtrac.info/
  • Version: 2.1.0
  • Download: http://sourceforge.net/projects/j-trac/files/jtrac/
  • File: jtrac-2.1.0.zip (17 MB)

Installation

# cd /usr/local/bin/
# unzip ~/DOWNLOADS/jtrac-2.1.0.zip
# cd jtrac/
# cp jtrac.war /opt/apache-tomcat-6.0.18/webapps/
# /etc/init.d/tomcat start

Configuration

Data-Directory

# mkdir /var/jtrac
# chown www-data:users /var/jtrac/
# cd /opt/apache-tomcat-6.0.18/webapps/jtrac/WEB-INF/classes/
# nano jtrac-init.properties
...
jtrac.home=/var/jtrac
# /etc/init.d/tomcat restart

Database

If nothing is changed, the embedded database HSQL is used:
database.driver=org.hsqldb.jdbcDriver
database.url=jdbc:hsqldb:file:${jtrac.home}/db/jtrac
database.username=sa
database.password=
hibernate.dialect=org.hibernate.dialect.HSQLDialect
hibernate.show_sql=false
For using another database, create the file ${jtrac.home}/jtrac.properties.
Example (for MySQL):
database.driver=com.mysql.jdbc.Driver
database.url=jdbc:mysql://localhost/jtrac
database.username=root
database.password=
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=false

Users

Admin

After installation login with admin/admin and change the admin's data in "Options - Edit own profile".

Adding other users

Other users can be maintained under "Options - Manage users"

Email Notification

Basic Settings

Under "Options - Settings":
mail.server.host = localhost
mail.from = <your.email.address>
jtrac.url.base = http://<server>/jtrac

Test

  • Call http://localhost:8080/jtrac.
  • Standard-User: admin/admin

Usage

Create a new project

Under "Options - Manage projects - [Create New Space]".

Customize it

After the first step of creating a new project, you can add custom fields, like "Type" (REQ, ISSUE, INFRA).

Add users

In the next step (leaving open/closed definition as is), you can allocate users to the project space.
This tutorial introduces Hudson as Continuus Integration (CI) server.
"Building/testing software projects continuously, just like CruiseControl or DamageControl. In a nutshell, Hudson provides an easy-to-use so-called continuous integration system, making it easier for developers to integrate changes to the project, and making it easier for users to obtain a fresh build. The automated, continuous build increases the productivity."

Specification

  • Homepage: http://hudson-ci.org/
  • Version: 1.337
  • Documentation: http://wiki.hudson-ci.org/display/HUDSON/Use+Hudson
  • Download: http://hudson-ci.org/download/war/
  • File(s): hudson.war (19 MB)

Installation

Debian GNU/Linux

# export http_proxy='http://<proxy_username>:<proxy_password>@<proxy_server>:<proxy_port>/'
# wget -O - http://hudson-ci.org/debian/hudson-ci.org.key | sudo apt-key add -
2009-12-15 14:35:48 http://hudson-ci.org/debian/hudsonci.org.key
...
2009-12-15 14:35:49 (1,81 MB/s) -- gespeichert [7060/7060]
OK
#
Then add the following entry in your /etc/apt/sources.list:
# nano /etc/apt/sources.list
...
deb http://hudson-ci.org/debian binary/
Update your local package index, then finally install Hudson:
# sudo apt-get update
# sudo apt-get install hudson

Configuration

Run as a Service

Debian GNU/Linux

After installing the Debian package of hudson:
    Hudson will be launched as a daemon up on start. See /etc/init.d/hudson for more details.
    The 'hudson' user is created to run this service.
    Log file will be placed in /var/log/hudson/hudson.log. Check this file if you are troubleshooting Hudson.
    /etc/default/hudson will capture configuration parameters for the launch. 

Run behind Apache (Port 80)

We want to see Hudson running on http:///hudson/.

The first step is to change the prefix hudson uses, so we get from "http://:8080/" to "http://:8080/hudson/". To do that, add "--prefix=/hudson" to the HUDSON_ARGS string in /etc/default/hudson:
# nano /etc/default/hudson
HUDSON_ARGS="-webroot=/var/run/hudson/war --httpPort=48080 --prefix=/hudson"
You may have noticed that we also added "--httpPort=48080" to change the port Hudson uses from 8080 to 48080 (for avoiding possible conflicts with a Tomcat instance, which also uses 8080 as default port...).

Restart Hudson with e.g.: sudo /etc/init.d/hudson force-reload
Test it under: http://<server_name>:48080/hudson/

Configure mod_proxy for Hudson (to get port 80 forward):
# nano /etc/apache2/mods-enabled/proxy.conf
<ifmodule mod_proxy.c>
  ...
  ProxyPass /hudson/ http://<server_name>:48080/hudson/
  ProxyPassReverse /hudson/ http://<server_name>:48080/hudson/
  ...
</ifmodule>

Reload Apache config:
# /etc/init.d/apache2 force-reload
Test it under: http:///hudson/

Usage

Start/Stop manually

# /etc/init.d/hudson start
# /etc/init.d/hudson stop

Logfile

# less /var/log/hudson/hudson.log

Securing Hudson / User Managment

Let Hudson maintain its own user database (where people can sign up to have their own accounts), and you as the administrator decides who can do what in Hudson.
  • Go to the system configuration screen (http://<server_name>/hudson/configure) and choose "Enable security".
  • Select "Hudson's own user database" as the security realm.
  • Select "Matrix-based security" as the authorization.
  • Give anonymous user the read access.
  • In the text box below the table, type in your user name (you'd be creating this later) and click "add".
  • Give yourself a full access by checking the entire row for your user name.
  • Scroll all the way to the bottom, click "save".
  • Create your user/Sign up with your username and new user data.

Set up build tools

Download JDK and unpack it:
sde@server-1:~$ mkdir BUILD-TOOLS
$ cd ~sde/BUILD-TOOLS/
$ sh ../jdk-6u13-linux-i586.bin
$ ls
jdk1.6.0_13
$
Download Apache Maven and unpack it:
sde@server-1:~$ (mkdir BUILD-TOOLS)
$ cd ~sde/BUILD-TOOLS/
$ unzip apache-maven-2.2.1-bin.zip
$ ls
apache-maven-2.2.1
$
Configure Maven's settings.xml to use internal Artifact Repository (if exists):
$ nano BUILD-TOOLS/apache-maven-2.2.1/conf/settings.xml
...
<mirrors>
...
  <mirror>
    <id>archiva.central</id>
    <mirrorof>central</mirrorof>
    <name>Archiva mirror of central Maven repository.</name>
    <url>http://server-2/archiva/repository/internal/</url>
  </mirror>
...
</mirrors>
...
Go to http://<server_name>/hudson/configure
  • Add Maven installation:
    • Maven - Maven installations - Add Maven - deactivate "Install automatically"
    • name: Maven 2.1.0
    • MAVEN_HOME: /home/sde/BUILD-TOOLS/apache-maven-2.1.0
  • Add JDK installation:
    • JDK - JDK installations - Add JDK - deactivate "Install automatically"
    • name: JDK 1.6.0-13
    • JAVA_HOME: /home/sde/BUILD-TOOLS/jdk1.6.0_13
    • Click "Save" at bottom of page

Set up Email Notification

  • Go to http://<server_name>/hudson/configure
  • Section "E-mail Notification":
    • SMTP server: (empty)
    • Default user e-mail suffix: (empty)
    • System Admin E-mail Address: <admin address="" email="" s="">
    • Hudson URL: change to "http://<server_name>/hudson/"
    • Click "Save" at bottom of page.
    • Choose menu "People", click on each username and configure the personal email addresses over the menu item "configure".

Set up Build for a project

Setting up the build for an existing project is described by the example project "PROJECT_NAME".
  • Go to http://<server_name>/hudson
  • New Job
    • Job name: PROJECT_NAME
      Build a maven2 project: Build a maven2 project. Hudson takes advantage of your POM files and drastically reduces the configuration.
    • OK
  • Fill in details:
    Project name: PROJECT_NAME (trunk)
    Description: This is the best project ever.
    Source Code Management:
    • Subversion
    • Modules: Repository URL: svn://<server_name>/REPO_NAME/PROJECT_NAME/trunk
    • Repository browser: WebSVN: URL: http://<server_name>/websvn/
    Build Triggers:
    • Build periodically: Schedule: 0 7 * * * (daily at 7 o'clock in the morning)
    • Poll SCM: 0,15,30,45 * * * * (every 15 minutes)
    Build:
    • Root POM: pom.xml
    • Goals and options: clean package
    Build Settings:
    • E-Mail Notification:
      Recipients: abc.def@xyz.com ...
      Check: Send e-mail for every unstable build, Send separate e-mails to individuals who broke the build
  • Save
  • Test: click "Build now"

Backup/Restore

Backup

All the settings, build logs, artifact archives are stored under the HUDSON_HOME directory. Simply archive this directory to make a backup. Backups can be taken without stopping the server.
  • In our installation HUDSON_HOME is "/var/lib/hudson" (see information in http://<server_name>/hudson/systemInfo). So we add an automatical backup for this directory to our cronjobs:
    # crontab -e
    ...
    25 6 * * * /usr/local/bin/backup-directory.sh -v \
    --scp sde@server-2:/var/backups/hudson \
    --identity ~sde/.ssh/sde\@server-2 /var/lib/hudson/
    
  • Create the target directory on "server-2":
    # mkdir /var/backups/hudson
    # chmod 777 /var/backups/hudson/
    
  • Test:
    server-1:~# /usr/local/bin/backup-directory.sh -v \
    --scp sde@server-2:/var/backups/hudson \
    --identity ~sde/.ssh/sde\@server-2 -/var/lib/hudson/
    ...
    server-2:~# ls -al /var/backups/hudson/
    insgesamt 8012
    drwxrwxrwx 2 root root  4096 15. Dez 14:00 .
    drwxr-xr-x 6 root root  4096 15. Dez 13:58 ..
    -rw-r--r-- 1 sde sde 8183075 15. Dez 14:00 backuphudson-091215-1802.tar.gz
    

Restore

# cd /
# tar xvfz backup-hudson-091215-1802.tar.gz
Per Sun's Java documentation, a Java enum "is a type whose fields consist of a fixed set of constants ... you should use enum types any time you need to represent a fixed set of constants."
  • Prior to Java 1.5, there were 2 basic ways to define new types: classes and interfaces
  • In some cases neither one of the options was sufficient, especially for a finite set of a specific type of data
  • Example of some finite sets include grades, planets, compass directions, countries, genders, and ethnicity types
  • These types of construct were possible prior to 1.5 but required a lot of work and were prone to issues.
  • Enums remove the need for public static final constants.

Defining an Enum

Defining an enum is as simple as creating any other class in Java:

public enum Gender {
  MALE, FEMALE, UNKNOWN
}
In this example, Gender is the enumeration type whereas MALE, FEMALE, and UNKNOWN are values for that type.

Note: The enumerated type identifiers are constants, therefore UPPERCASE lettering is the standard convention.

Three basic components (at minimum) to create an enumerated type are
  • The enum keyword
  • A name for the enumerated type (Gender)
  • A list of allowable values for the type (MALE, FEMALE, UKNNOWN)
In addition to the minimum requirements, an enumeration can also contain the following optional components
  • An interface or set of interfaces that the enum implements
  • Variable definitions
  • Method definitions
  • Value-specific class bodies

Referencing an Enum


Enumerations are referenced in the same manner as any other class because an enum is a class.  As a result you get all the benefits of a class such as type-safety, compile time checking, and the ability to use them in variable definitions.

public class Person {
  private String firstName;
  private String lastName;
  private Date dateOfBirth;
  private Gender gender;

  public Person(String fName, String lName) {
    this.firstName = fName;
    this.lastName = lName;
  }

  public void setFirstName(String firstName) {
    this.firstname = firstName;
  }

  public String getFirstName() {
    return firstName;
  }
  ...
  public void setGender(Gender gender) {
    this.gender = gender;
  }

  public Gender getGender() {
    return gender;
  }
}

As you can see, there is nothing complicated about this.  The way of defining and referencing an enumeration in a class is like any other JAVA POJO type.

Using an Enum


Continuing with our Gender and Person example above, let's see an example of how this enumeration can be used in a JAVA program.

public class EnumTester {
  public static void main(String[] args) {
    Person lisa = new Person ("Lisa", "Simpson");
    Person homer = new Person ("Homer", "Simpson");

    homer.setGender(Gender.MALE);
    lisa.setGender(Gender.FEMALE);

    System.out.println("Lisa's gender is: " + lisa.getGender());
    System.out.println("Homer's gender is: " + homer.getGender());
  }
}

The output produced from the above call is
Lisa's gender is FEMALE
Homers's gender is MALE

Conclusion


As previously noted, Java enumerations are classes therefore receive the benefits of a Java class (see above).
  • Enumerations implicitly extend java.lang.Enum
  • Each declared values is an instance of that enum class.
  • Enums have no public constructor. This prevents the ability to modify enums at run-time.
  • Enums values cannot be subclassed.  They are essentially final classes.
  • Enums can be compared using the == or equals() method.
  • Enums can be compared using the compareTo() method because they implement the java.lang.Comparable interface.
  • Enums override the toString() method. This method returns the name of the enumerated value.  This method is not final therefore can be overridden.
  • Enums provide a static valueOf() method which complements the toString() method.
  • Using the above example
    Gender.valueOf("MALE") returns Gender.MALE;
  • Although this shouldn't be used directly in your code, enums define a final instance method called ordinal() which returns the position (0 based) of the enumerated type.
  • Enums also provide a values() method used during the iteration of enumerations.

References

Introduction

Though written from scratch, Mutt's initial interface was based largely on the ELM mail client.

Specification

Installation

Debian Linux

# apt-cache search mutt
...
mutt -- text-based mailreader supporting MIME, GPG, PGP and threading
...
# apt-get install mutt

Test

Send email using mutt to your email account (e.g. xxx.yyy@zzz.com).
In this code example we style fields that have validation errors.
The validation error message is below the field label.

Screenshot:
HTML- and CSS-Code:
<html>
  <head>
    <!--[if lte IE 7]>
      <style type="text/css" media="all">@import "fieldset-styling-ie.css";</style>
    <![endif]-->
      <style type="text/css">
fieldset {
  float: left;
  clear: both;
  width: 100%;
  margin: 0 0 1.5em 0;
  padding: 0;
  border: 1px solid #BFBAB0;
  background-color: #F2EFE9;
  //background-image: url(images/vertical-gradient.png);
  //background-repeat: repeat-x;
}
legend {
  margin-left: 1em;
  padding: 0;
  color: #000;
  font-weight: bold;
}
fieldset ol {
  padding: 1em 1em 0 1em;
  list-style: none;
}
fieldset li {
  float: left;
  clear: left;
  width: 100%;
  padding-bottom: 1em;
}
fieldset.submit {
  float: none;
  width: auto;
  border: 0 none #FFF;
  padding-left: 12em;
  background-color: transparent;
  //background-image: none;
}
label {
  position: relative;
  float: left;
  width: 10em;
  margin-right: 1em;
  text-align: left;
}

fieldset fieldset {
  margin-bottom: -2.5em;
  border-style: none;
  background-color: transparent;
  background-image: none;
}
fieldset fieldset legend {
  margin-left: 0;
  font-weight: normal;
}
fieldset fieldset ol {
  position: relative;
  top: -1.5em;
  margin: 0 0 0 11em;
  padding: 0;
}
fieldset fieldset label {
  float: none;
  width: auto;
  margin-right: auto;
  top: 0;
}
label em {
  position: absolute;
  left: 10em;
  top: 0.4em;
}
label strong {
  display: block;
  color: #C00;
  font-size: 85%;
  font-weight: normal;
  text-transform: uppercase;
}
      </style>
</head>
<body>

<p><small>Required fields are marked with <img src="icon-star-10x9.png" alt="required" />.</small></p>

<form action="#">
  <fieldset>
    <legend>Contact Details</legend>
    <ol>
      <li>
        <label for="name">Name: <em><img src="icon-star-10x9.png" alt="required" /></em>
        <strong>This field is required</strong></label>
        <input id="name" name="name" class="text" type="text" />
      </li>
      <li>
        <fieldset>
          <legend>Occupation: </legend>
          <ol>
            <li>
              <input id="occupation1" name="occupation1" class="checkbox" type="checkbox" value="1" />
              <label for="occupation1">Doctor</label>
            </li>
            <li>
              <input id="occupation2" name="occupation2" class="checkbox" type="checkbox" value="1" />
              <label for="occupation2">Lawyer</label>
            </li>
            <li>
              <input id="occupation3" name="occupation3" class="checkbox" type="checkbox" value="1" />
              <label for="occupation3">Teacher</label>
            </li>
            <li>
              <input id="occupation4" name="occupation4" class="checkbox" type="checkbox" value="1" />
              <label for="occupation4">Web designer</label>
            </li>
          </ol>
        </fieldset>
      </li>
      <li>
        <label for="email">Email address: <em><img src="icon-star-10x9.png" alt="required" /></em>
        <strong>This must be a valid email address</strong></label>
        <input id="email" name="email" class="text" type="text" />
      </li>
      <li>
        <label for="phone">Telephone:</label>
        <input id="phone" name="phone" class="text" type="text" />
      </li>
    </ol>
  </fieldset>
  <fieldset class="submit">
    <input class="submit" type="submit" value="Begin download" />
  </fieldset>
</form>

</body>
</html>

This view is used to start and stop application servers / webapp containers.

Installation

Already installed in JEE-version of Eclipse.

Configuration

Activate View

Window – Show View – Servers

Adding a Tomcat Server

Context menu – New – Server:
Server’s host name: localhost
Select the server type: Apache – Tomcat v6.0 Server
Server name: Tomcat6.0.18
Next >
Name: Tomcat6.0.18
Tomcat installation directory: C:\Program Files\apache-tomcat-6.0.18
JRE: jdk1.6.0_13
Finish

Test

Start a Server

  • Start Tomcat (using context menu or start icon on the upper right).
  • Go to http://localhost:8080/ in your browser.
  • "404 Error" is ok, as there are no webapps published over Eclipse, but Tomcat is responding (see footer).

Stop a Server

Stop Tomcat (using context menu or stop icon on the upper right)

Specification

Installation

  • Menu "Help - Install New Software..."
  • Install dialog: "Add...":
    Name: http://m2eclipse.sonatype.org/sites/m2e"
    Location: "http://m2eclipse.sonatype.org/sites/m2e" - OK
  • Select all (if you are not sure what to select, I unchecked AJDT...) - Next > - Next >
  • Accept license - Finish
  • Restart Eclipse
Install additional "extras" from "http://m2eclipse.sonatype.org/sites/m2e-extras".

Configuration

Window – Preferences - Maven

Documentation

Specification

  • Homepage: http://jboss.org/tools/
  • Download: http://jboss.org/tools/download.html
  • Version: 3.1 (for Galileo)

Installation

  • Eclipse: "Help - Install New Software... - Add...": http://download.jboss.org/jbosstools/updates/stable/galileo/
  • Check e.g. "Hibernate Tools" and install it
Diver is a set of advanced tools for debugging and reverse engineering. If you ever wondered, "What did my program just do?", Diver will help you find the answer.
Diver Allows You To
  • Easily trace your Java programs
  • Visualize your program's runtime functionality (e.g. Sequence Diagrams)
  • Filter your IDE based on what occurs at runtime
  • See what code ran in your source code editors
  • And generally understand your software better

Specification

  • Homepage: http://diver.sourceforge.net
  • Version: 0.2.0
  • Download: http://diver.sourceforge.net/download.html

Installation

  • Menu "Help - Install New Software..."
  • Install dialog: "Add...":
    • Name: http://diver.svn.sourceforge.net/svnroot/diver/Release
    • Location: "http://diver.svn.sourceforge.net/svnroot/diver/Release" - OK
    • Select "Diver - All Features" - Next > - Next >
    • Accept license - Finish
    • Restart Eclipse
HSQLDB is a good DB during development phase as it can provide a database in memory.

Specification

  • Homepage: http://hsqldb.org/
  • Version: 1.8.1.1
  • Download: http://sourceforge.net/projects/hsqldb/files/

Installation

For using HSQLDB in an application, which is managed with Maven, you simple have to add this dependency entry into the projects "pom.xml":
...
<dependency>
  <groupId>hsqldb</groupId>
  <artifactId>hsqldb</artifactId>
  <version>1.8.1.1</version>
</dependency>
...

Configuration

Hibernate

The standard configuration for using HSQLDB with Hibernate, in file "hibernate.properties":
hibernate.dialect=org.hibernate.dialect.HSQLDialect
hibernate.connection.driver_class=org.hsqldb.jdbcDriver
hibernate.connection.url=jdbc:hsqldb:yourdbname;shutdown=true
hibernate.connection.username=sa
hibernate.connection.password=
hibernate.hbm2ddl.auto=update

Specification

  • Homepage: http://www.postgresql.org/
  • Download: http://www.postgresql.org/download/
  • File(s): postgresql-8.4.1-1-windows.exe (39 MB)

Installation

Windows

  1. Execute the one-click installer "postgresql-8.4.1-1-windows.exe"
  2. Install it into a suitable directory, e.g. "C:\Program Files\PostgreSQL\8.4"
  3. Select a suitable data directory, e.g. "D:\PostgreSQL\data"
  4. Enter a password for admin account "postgres"

Configuration

Port

Per default PostgreSQL is running on port 5432.

Trusted connections for all users only from localhost

To allow trusted connections for all users only from localhost, edit file "pg_hba.conf" (Windows: e.g. D:\PostgreSQL\data\pg_hba.conf) and uncomment the host line for 127.0.0.1:
...
# IPv4 local connections:
#host    all         all         127.0.0.1/32          md5
host    all         all         127.0.0.1/32          trust
...
Restart PostgreSQL:
  • As admin user "postgres": pg_ctl restart
  • As user "root": /etc/init.d/postgresql restart

Usage

PostgreSQL Shell

Windows

You can connect to the database with the pgAdmin tool (Start - Programs - PostgreSQL 8.4 - pgAdmin III) or use psql command shell.

Create a new user

psql=> create user <username> with password '<password>';

Create a new database

Example: Create database pg_liferay for Liferay Portal usage:
$ psql -U postgres -d template1 -c "CREATE DATABASE pg_liferay ENCODING='UNICODE';"
CREATE DATABASE
$

Grant all permissions for a database to an user

$ psql -U postgres -d template1 -c "GRANT ALL PRIVILEGES ON DATABASE <database_name> TO <username>;"
GRANT
$

Connect to a database

$ psql -d <database_name> -U <username> -W
...
<database_name>=>

Basic psql Usage

pg_liferay=> help
Dies ist psql, die Kommandozeilenschnittstelle für PostgreSQL.
Geben Sie ein:  \copyright für Urheberrechtsinformationen
                \h für Hilfe über SQL-Anweisungen
                \? für Hilfe über interne Anweisungen
                \g oder Semikolon, um eine Anfrage auszuführen
                \q um zu beenden
pg_liferay=>
Examples:
  • show all databases: \l
  • change database: \connect <other_database_name>
  • show all tables of a database: \dt
  • exit: \q
For developing/testing/running portlets a portal server is necessary. There are some opensource portals in the market: Liferay, Jetspeed, JBoss Portal Server, OpenPortal (Sun Java System Portal Server). Here we describe the setup of Liferay portal server.

Specification

  • Homepage: http://www.liferay.com/
  • Version: 5.2.3
  • Download: http://www.liferay.com/web/guest/downloads/portal
  • File(s): liferay-portal-tomcat-6.0-5.2.3.zip (139 MB)

Installation

Windows

Unzip file "liferay-portal-tomcat-6.0-5.2.3.zip" to a suitable folder. Do not use a path, which contains spaces! Otherwise you will get runtime errors. So use e.g. "D:\". New folder is then "D:\liferay-portal-5.2.3\".

Configuration

Connector Port

If you do not want the portal to run under the port 8080, you have to edit the tomcat configuration file "...\liferay-portal-5.2.3\tomcat-6.0.18\conf\server.xml", e.g. to use 18080 instead:
...
<Server port="18005" shutdown="SHUTDOWN">
  ...
  <Connector port="18080" protocol="HTTP/1.1" 
               connectionTimeout="20000"
               redirectPort="18443" URIEncoding="UTF-8" />
    ...
  <Connector port="18009" protocol="AJP/1.3"
               redirectPort="18443" URIEncoding="UTF-8" />
  ...
</Server>

Database

If you do want to change the database from the default (in memory) database to e.g. PostgreSQL, you have to create/edit this in the file "...\liferay-portal-5.2.3\tomcat-6.0.18\webapps\ROOT\WEB-INF\classes\portal-ext.properties":
...
#
# PostgreSQL
#
jdbc.default.driverClassName=org.postgresql.Driver
jdbc.default.url=jdbc:postgresql://localhost:5432/pg_liferay
jdbc.default.username=pg_liferay
jdbc.default.password=life1ray2
...
Hint: Copying of the PostgreSQL JDBC-driver to Liferay is not necessary, it's already there in "...\tomcat-6.0.18\lib\ext\".

Usage

Start Liferay Portal Server

You can start the enclosed Tomcat in the same way as you would if you had downloaded Tomcat separately. Tomcat is launched by way of a script which is found in its bin subfolder.

Windows

C:\> D:
D:\> cd "D:\liferay-portal-5.2.3\tomcat-6.0.18\bin"
D:\liferay-portal-5.2.3\tomcat-6.0.18\bin>startup.bat
Using CATALINA_BASE:   D:\liferay-portal-5.2.3\tomcat-6.0.18
Using CATALINA_HOME:   D:\liferay-portal-5.2.3\tomcat-6.0.18
Using CATALINA_TMPDIR: D:\liferay-portal-5.2.3\tomcat-6.0.18\temp
Using JRE_HOME:        D:\liferay-portal-5.2.3\tomcat-6.0.18/jre1.
5.0_17/win
After successful startup you can view the portal pages under: http://localhost:18080/ (depends on your configured port).
Be aware that Liferay is running on an In-Memory-Database unless you do not configure your own database! All changes will get lost.

Login

The default login should be "test@liferay.com / test" (admin handbook), but for some reason they changed it. Now the login is "bruno@7cogs.com / bruno".

Troubleshooting

  • CATALINA_BASE points to other Tomcat
    Problem: If the CATALINA_BASE is different from your installation (like in this example), the startup-script found a "CATALINA_HOME" environment variable for another tomcat installation. Solution: Remove the environment variable or change the startup-script ("startup.bat"):
    ...
    rem if not "%CATALINA_HOME%" == "" goto gotHome
    ...
    
For accessing servers over a network a SSH-protocol (Secure SHell) based client is recommended. For Windows the preferred client is "putty".

Specification

  • Homepage: http://www.chiark.greenend.org.uk/~sgtatham/putty
  • Version: 0.60
  • Download: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
  • File: putty-0.60-installer.exe (1.7 MB)

Installation

Execute the installer.
A Windows client application for file management on remote servers over a network using the SSH-protocol.

Specification

  • Homepage: http://winscp.net/
  • Version: 4.1.9
  • Download: http://winscp.net/eng/download.php
  • File: winscp419setup.exe (2.5 MB)

Installation

Execute the installer.

Installation

Debian Linux

# apt-cache search ssh -n
# apt-get install ssh -s
# apt-get install ssh

Configuration

Disable direct ssh-login for user "root"

For security reasons direct login (from outside/the network) for user "root" should never be allowed.

Debian Linux

# nano /etc/ssh/sshd_config
...
# Authentication:
LoginGraceTime 120
PermitRootLogin no
StrictModes yes
...
# /etc/init.d/ssh restart

Unattended remote login (without password)

Create keys on machine you want to login to (e.g. as user "sde" on "server-1"): Generate public/private keys for unattended login from other servers (which need (scp) access from shell scripts like backup scripts...):

Debian Linux

# su - sde
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/sde/.ssh/id_rsa):
Created directory '/home/sde/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/sde/.ssh/id_rsa.
Your public key has been saved in /home/sde/.ssh/id_rsa.pub.
The key fingerprint is:
f2:2e:9f:87:88:18:a4:2e:95:07:6a:97:ea:28:46:57 sde@server-1
The key's randomart image is:
+--[ RSA 2048]----+
|                 -|
|                 -|
|                 -|
| o E             -|
| + oo -. S        -|
|oo++. o          -|
|+.++ -. -...       -|
|++. -. o....      -|
|*. o+.           -|
+-----------------+
$ ls -al .ssh/
insgesamt 16
drwx------ 2 sde sde 4096 22. Jul 14:30 .
drwxr-xr-x 15 sde sde 4096 22. Jul 14:30 ..
-rw------- 1 sde sde 1675 22. Jul 14:30 id_rsa
-rw-r--r-- 1 sde sde 398 22. Jul 14:30 id_rsa.pub
$
Use empty passphrase.

Add public-key to “.ssh/authorized_keys” on machine we want to login to (server-1):
$ cat .ssh/id_rsa.pub >> .ssh/authorized_keys
Copy private-key to “.ssh/sde@server-1” on machine we want to login from (server-2):
On "server-2":
# su - sde
$ mkdir .ssh
On "server-1":
$ scp .ssh/id_rsa sde@server-2:~/.ssh/sde@server-1
sde@server-2's password:
id_rsa 100%
1675 1.6KB/s 00:00
$
Test (login unattended from “server-2” to “server-1")
sde@server-2:~$ ssh -i .ssh/sde\@server-1 sde@server-1
Linux enterprise-1 2.6.26-1-686 #1 SMP Sat Jan 10 18:29:31 UTC
2009 i686
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
sde@server-1:~$

Installation

On Unix-OSs installed by default.

Configuration

Notification email address

Add email-address where results of cronjobs should be sent to:
# crontab -e
MAILTO=xxx.yyy@zzz.com
2 1 * * * /etc/webmin/cron/tempdelete.pl
#

Activate Logging

# nano /etc/rsyslog.conf
...
cron.* /var/log/cron.log
...
# /etc/init.d/rsyslog restart
Stopping enhanced syslogd: rsyslogd.
Starting enhanced syslogd: rsyslogd.
#

Usage

# crontab –e
MAILTO=xxx.yyy@zzz.com
2 1 * * * /etc/webmin/cron/tempdelete.pl
#
Hints:
field        allowed values
-----        ---------------
minute       0-59
hour         0-23
day of month 1-31
month        1-12 (or names, see below)
day of week  0-7 (0 or 7 is Sun, or use names)

Specification

  • Homepage: http://www.courier-mta.org/

Installation

Debian GNU/Linux

# apt-get install courier-mta

Troubleshooting

Debian

On Debian per default Citadel MTA is installed. As Apache Continuum (Continuous Integration system) had problems with sending notification emails ("relay denied"), Citadel MTA was deinstalled and installed Courier MTA instead.
The Apache HTTP Server Project is an effort to develop and maintain an open-source HTTP server for modern operating systems including UNIX and Windows NT. The goal of this project is to provide a secure, efficient and extensible server that provides HTTP services in sync with the current HTTP standards.
Apache httpd has been the most popular web server on the Internet since April 1996.

Specification

  • Homepage: http://httpd.apache.org/
  • Version: 2.2.9
  • Download: http://httpd.apache.org/download.cgi

Installation

Debian GNU/Linux

(no installation needed, it is installed by default)
To start Apache Webserver by default:
$ sudo update-rc.d apache2 defaults

Off-Topic: Disable automatic start of MySql service:
$ sudo /usr/sbin/update-rc.d mysql disable
insserv: warning: current start runlevel(s) (empty) of script `mysql' overrides LSB defaults (2 3 4 5).
insserv: warning: current stop runlevel(s) (0 1 2 3 4 5 6) of script `mysql' overrides LSB defaults (0 1 6).

Configuration

The configuration files for the Apache Webserver reside in the directory “/etc/apache2”.
The default homepage files are in folder “/var/www”.
The default website (see below) gives instructions on further configuration:

This is the default welcome page used to test the correct operation of the Apache2 server after installation on Debian systems. If you can read this page, it means that the Apache HTTP server installed at this site is working properly. You should replace this file (located at /var/www/html/index.html) before continuing to operate your HTTP server.
If you are a normal user of this web site and don't know what this page is about, this probably means that the site is currently unavailable due to maintenance. If the problem persists, please contact the site's administrator.

Debian's Apache2 default configuration is different from the upstream default configuration, and split into several files optimized for interaction with Debian tools. The configuration system is fully documented in /usr/share/doc/apache2/README.Debian.gz. Refer to this for the full documentation. Documentation for the web server itself can be found by accessing the manual if the apache2-doc package was installed on this server.
The configuration layout for an Apache2 web server installation on Debian systems is as follows:
/etc/apache2/
|-- apache2.conf
|       `--  ports.conf
|-- mods-enabled
|       |-- *.load
|       `-- *.conf
|-- conf-enabled
|       `-- *.conf
|-- sites-enabled
|       `-- *.conf 
  • apache2.conf is the main configuration file. It puts the pieces together by including all remaining configuration files when starting up the web server.
  • ports.conf is always included from the main configuration file. It is used to determine the listening ports for incoming connections, and this file can be customized anytime.
  • Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/ directories contain particular configuration snippets which manage modules, global configuration fragments, or virtual host configurations, respectively.
  • They are activated by symlinking available configuration files from their respective *-available/ counterparts. These should be managed by using our helpers a2enmod, a2dismod, a2ensite, a2dissite, and a2enconf, a2disconf . See their respective man pages for detailed information.
  • The binary is called apache2. Due to the use of environment variables, in the default configuration, apache2 needs to be started/stopped with /etc/init.d/apache2 or apache2ctl.Calling /usr/bin/apache2 directly will not work with the default configuration.

Documentation roots

By default, Debian does not allow access through the web browser to any file apart of those located in /var/www, public_html directories (when enabled) and /usr/share (for web applications). If your site is using a web document root located elsewhere (such as in /srv) you may need to whitelist your document root directory in /etc/apache2/apache2.conf.
The default Debian document root is /var/www/html. You can make your own virtual hosts under /var/www. This is different to previous releases which provides better security out of the box.

Usage

After starting the webserver with
$ sudo service apache2 start

this default page (/var/www/html/index.html) is delivered upon request:
Default Website (Debian Apache2)
Stopping Apache:
$ sudo service apache2 stop
To direct all web application requests over Apache to the different Tomcat workers, we will have to configure "mod_jk" module.

Specification

  • Homepage: http://apache.mirror.clusters.cc/tomcat/tomcat-connectors/jk/binaries/
  • Version: 1.2.28
  • Download: http://apache.mirror.clusters.cc/tomcat/tomcat-connectors/jk/binaries/linux/jk-1.2.28/i586/
  • File: mod_jk-1.2.28-httpd-2.2.X.so (700 kB)

Installation

Debian

For Debian a prepared package exists:
# apt-cache search mod_jk
libapache2-mod-jk -- Apache 2 connector for the Tomcat Java servlet engine
# apt-get install libapache2-mod-jk
# /etc/init.d/apache2 restart

Configuration

Linux

File "/etc/apache/conf.d/mod_jk"

Apache mod_jk-module configuration (example):
# nano /etc/apache2/conf.d/mod_jk

# Where to find workers.properties
JkWorkersFile /etc/apache2/workers.properties

# Where to put jk shared memory
JkShmFile    /var/log/apache2/mod_jk.shm

# Where to put jk logs
JkLogFile    /var/log/apache2/mod_jk.log

# Set the jk log level [debug/error/info]
JkLogLevel debug

# Select the timestamp log format
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "

# Send contexts to workers
JkMountCopy all

#JkMount /portal/* worker1collaboration
JkMount /* worker1collaboration
JkMount /c worker1collaboration
JkMount /c/* worker1collaboration
JkMount /chat-portlet/* worker1collaboration
JkMount /flash/* worker1collaboration
JkMount /group/* worker1collaboration
JkMount /html/* worker1collaboration
JkMount /image/* worker1collaboration
JkMount /language/* worker1collaboration
JkMount /so-theme/* worker1collaboration
JkMount /tunnel-web/* worker1collaboration
JkMount /user/* worker1collaboration
JkMount /web/* worker1collaboration
#JkMount /*/web/guest/login worker1collaboration

JkUnMount /archiva/* worker1collaboration

File "/etc/apache2/workers.properties"

Apache workers configuration (example):
# nano -/etc/apache2/workers.properties
# Define workers
worker.list=worker1collaboration

# Set properties for worker1collaboration (ajp13)
worker.worker1collaboration.type=ajp13
worker.worker1collaboration.host=localhost
worker.worker1collaboration.port=28009
#worker.worker1collaboration.lbfactor=1
worker.worker1collaboration.connection_pool_timeout=600
worker.worker1collaboration.socket_keepalive=1
worker.worker1collaboration.socket_timeout=60
The Apache module "mod_proxy" implements a proxy/gateway for Apache. It implements proxying capability for AJP13 (Apache JServe Protocol version 1.3), FTP, CONNECT (for SSL), HTTP/0.9, HTTP/1.0, and HTTP/1.1. The module can be configured to connect to other proxy modules for these and other protocols.

Specification

  • Homepage: http://httpd.apache.org/
  • Download: -- (included in Apache HTTPd)
  • Documentation: http://httpd.apache.org/docs/2.2/mod/mod_proxy.html

Installation

The Apache module “mod_proxy” is installed by default with Apache HTTPd, but not activated.

Configuration

Linux

Example:
# nano /etc/apache2/mods-available/proxy.conf

<IfModule mod_proxy.c>
ProxyRequests On
ProxyPass /continuum/ http://<SERVER_NAME>:8080/continuum/
ProxyPassReverse /continuum/ http://<SERVER_NAME>:8080/continuum/
##ProxyPass /archiva/ http://<SERVER_NAME>:9080/archiva/
##ProxyPassReverse /archiva/ http://<SERVER_NAME>:9080/archiva/
</IfModule>
Activation:
# cd /etc/apache2/mods-enabled/
# ln -s ../mods-available/proxy.load proxy.load
# ln -s ../mods-available/proxy.conf proxy.conf
# ln -s ../mods-available/proxy_http.load proxy_http.load
# /etc/init.d/apache2 restart
The Apache module "dav_svn" provides WebDAV access to a subversion repository.

Installation

Debian GNU/Linux

# apt-get install libapache2-svn
...
Richte libapache2-svn ein (1.5.1dfsg1-2) ...
Considering dependency dav for dav_svn:
Enabling module dav.
Enabling module dav_svn.
Run '/etc/init.d/apache2 restart' to activate new configuration!
# /etc/init.d/apache2 restart
(enabled modules are: /etc/apache2/mods-enabled/dav.load, /etc/apache2/mods-enabled/dav_svn.load)

Configuration

Repository directory permissions

The repository directory needs the proper permissions for the apache user ("www-data") (under which Apache is running) and the other users. The apache user won't be put in the subversion group.
# groupadd subversion
...
# chown -R www-data:subversion /var/svn-repos/*
# chmod -R 770 /var/svn-repos/*

Activate URL-access

# nano /etc/apache2/mods-enabled/dav_svn.conf
...
<Location /svn>
  DAV svn
  SVNParentPath /var/svn-repos
</Location>
WARNING: At this point your repository is “anonymously” accessible to the world. WebDAV is not using the "passwd"-file of svnserve! Until you configure some authentication and authorization policies, the Subversion repositories that you make available via the Location directive will be generally accessible to everyone.

Authentication/Authorization

After activating the URL-access:
  • Anyone can use a Subversion client to check out a working copy of a repository URL (or any of its subdirectories).
  • Anyone can interactively browse the repository's latest revision simply by pointing a web browser to the repository URL.
  • Anyone can commit to the repository.
So we have to secure the WebDAV access independently from the svnserve-authentication/authorization. As we host several projects on one SVN-server, it would be possible to setup "Path-Based Authorization" (see: http://svnbook.red-bean.com/nightly/de/svn-book.html#svn.serverconfig.pathbasedauthz) like this:
<Location /svn>
  DAV svn
  SVNParentPath /var/svn-repos

  # our access control policy
  AuthzSVNAccessFile /path/to/access/file

  # only authenticated users may access the repository
  Require valid-user

  # how to authenticate a user
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /path/to/users/file
</Location>
HINT: The AuthzSVNAccessFile directive points to a file which also can be used by svnserve authzdb variable (within svnserve.conf).

But as mentioned in "Do You Really Need Path-Based Access Control?" in the above mentioned SVNBook this will cause a maintainance and performance overhead. So we decide to just setup an overall authentication/authorization for all projects. If someone writes in other's project, it can be tracked back and be undone.
<Location /svn>
  DAV svn
  SVNParentPath /var/svn-repos

  # how to authenticate a user
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /path/to/users/file

  # only authenticated users may access the repository
  ##Require valid-user
  # too strict, allow read:
  # For any operations other than these, require an authenticated user.
  <LimitExcept GET PROPFIND OPTIONS REPORT>
    Require valid-user
  </LimitExcept>
</Location>
WARNING: HTTP Basic Auth passwords pass in very nearly plain text over the network, and thus are extremely insecure.

Another option is to not use Basic authentication, but to use Digest authentication instead. Digest authentication allows the server to verify the client's identity without passing the plain-text password over the network.

Assuming that the client and server both know the user's password, they can verify that the password is the same by using it to apply a hashing function to a one-time bit of information. The server sends a small random-ish string to the client; the client uses the user's password to hash the string; the server then looks to see whether the hashed value is what it expected.

Configuring Apache for Digest authentication is also fairly easy, and only a small variation on our prior example. Be sure to consult Apache's documentation for full details.
# nano /etc/apache2/mods-enabled/dav_svn.conf
<Location /svn>
  DAV svn
  SVNParentPath /var/svn-repos

  # how to authenticate a user
  AuthType Digest
  AuthDigestDomain /svn/
  AuthName "Subversion repository"

  # /path/to/users/file:
  AuthUserFile /etc/subversion/.htdigest

  # only authenticated users may access the repository
  ##Require valid-user
  # too strict, allow read:
  # For any operations other than these, require an authenticated user.
  <LimitExcept GET PROPFIND OPTIONS REPORT>
    Require valid-user
  </LimitExcept>
  # FOR STRICT ACCESS (only valid users read/write): comment LimitExcept lines
</Location>
For Digest-Authentication/Authorization the Apache-Module "auth_digest" has to be activated:
# cd /etc/apache2/mods-enabled/
# ln -s ../mods-available/auth_digest.load auth_digest.load
Before restarting the server, the Users-file has to be created (see next section). After this has be done, reload the Apache Webserver:
# /etc/init.d/apache2 reload
Reloading web server config: apache2.
#

Usage

User-Management

For maintaining users/passwords for the AuthType = Digest, the Apache command "htdigest" is used. htdigest is used to create and update the flat-files used to store usernames, realm and password for digest authentication of HTTP users. Resources available from the Apache HTTP server can be restricted to just the users listed in the files created by htdigest.
Synopsis: htdigest [ -c ] passwdfile realm username
Options:
  • -c Create the passwdfile. If passwdfile already exists, it is deleted first!
  • passwdfile Name of the file to contain the username, realm and password. If -c is given, this file is created if it does not already exist, or deleted and recreated if it does exist.
  • realm The realm name to which the user name belongs.
  • username The user name to create or update in passwdfile. If username does not exist is this file, an entry is added. If it does exist, the password is changed.
  • Create Digest-file:
    # htdigest -c /etc/subversion/.htdigest "Subversion repository" johnny
    Adding password for johnny in realm Subversion repository.
    New password:
    Re-type new password:
     
  • Add/update new user:
    # htdigest /etc/subversion/.htdigest "Subversion repository" sepp
    Adding user sepp in realm Subversion repository
    New password:
    Re-type new password:
     

Test

  • Test 1: Open in browser: http://<server_name>/svn/<project_name>/
  • Test 2: Connect via Eclipse (subclipse) and import project into repository. After initial import (check in) of the project:
    # svnlook tree /var/svn-repos/<project_name>/
    ...
    
WebSVN is a webbased fronted for browsing a subversion repository.

Specification

  • Homepage: http://www.websvn.info/
  • Version: 2.0-4+lenny1 (on Debian)

Installation

Debian GNU/Linux

Installation with additional package "enscript" for syntax coloring.
# apt-get install enscript
# apt-get install -s websvn
...
Remv apache2-mpm-worker [2.2.9-10+lenny2] [apache2 -]
Inst apache2-mpm-prefork (2.2.9-10+lenny2 Debian:5.0.1/stable)
Inst php5-common (5.2.6.dfsg.1-1+lenny3 Debian-Security:5.0/ stable)
Inst libapache2-mod-php5 (5.2.6.dfsg.1-1+lenny3 Debian-Security:5.0/stable)
Inst websvn (2.0-4+lenny1 Debian:5.0.1/stable, Debian-Security:5.0/stable)
Conf apache2-mpm-prefork (2.2.9-10+lenny2 Debian:5.0.1/stable)
Conf php5-common (5.2.6.dfsg.1-1+lenny3 Debian-Security:5.0/stable)
Conf libapache2-mod-php5 (5.2.6.dfsg.1-1+lenny3 Debian-Security:5.0/stable)
Conf websvn (2.0-4+lenny1 Debian:5.0.1/stable, Debian-Security:5.0/stable)
# apt-get install websvn

Configuration

Access to repository

Debian GNU/Linux

# dpkg-reconfigure websvn
Websvn will first ask for which kind of server to configure, accept defaults. The next screens ask for a parent repository folder (“/var/svn-repos/” in this case) and specific repository folders, this will determine which repositories will show up in websvn. We will only enter a parent repository, all repositories created in this folder will show up in websvn for users to browse. If you want to show only specific repositories enter their full paths in the second screen and leave the parent path in the first screen blank.

As a result the file /etc/websvn/svn_deb_conf.inc will be written.

Syntax highlighting

# nano /etc/websvn/config.php
<?php
  ...
  // {{{ FILE CONTENT ---
  ...
  // $contentType['.c'] = 'text/plain'; // Create a new association
  // $contentType['.doc'] = 'text/plain'; // Modify an existing one
  // unset($contentType['.m']); // Remove a default association
  unset($contentType['.sh']);
    // Remove a default association -> .sh is regarded as a
    // binary file by default, needs to be unset

  ...

  // {{{ COLOURISATION ---
  ...
  $config->useEnscript();
  ...
  // $extEnscript['.pas'] = 'pascal';
  // php is default correctly colourized
  $extEnscript['.java'] = 'java';
  $extEnscript['.pl'] = 'perl';
  $extEnscript['.py'] = 'python';
  $extEnscript['.sql'] = 'sql';
  $extEnscript['.html'] = 'html';
  $extEnscript['.xml'] = 'html';
  $extEnscript['.thtml'] = 'html';
  $extEnscript['.tpl'] = 'html';
  $extEnscript['.sh'] = 'bash';

  ...

  // {{{ MISCELLANEOUS ---
  // Comment out this if you don't have the right to use it.
  // Be warned that you may need it however!
  set_time_limit(0);

  // Comment this line to turn off caching of repo information.
  // This will slow down your browsing.
  //$config->setCachingOn();

  ...
  // }}}
?>
<?php
if ( file_exists("/etc/websvn/svn_deb_conf.inc") ) {
  include("/etc/websvn/svn_deb_conf.inc");
}
?>

Access-URL

...using a relative address
# nano /etc/apache2/sites-available/default
<VirtualHost *:80>
  ServerAdmin xxx.yyy@zzz.com
  DocumentRoot /var/www/

  <Directory />
    Options FollowSymLinks
    AllowOverride None
  </Directory>
  ...
  Alias /websvn/ "/usr/share/websvn/"

  <Directory "/usr/share/websvn/">
    Options FollowSymLinks
    AllowOverride None
    order allow,deny
    allow from all

    #AuthType Basic
    #AuthName "Subversion Repository"
    #Require valid-user
    #AuthUserFile /etc/apache2/dav_svn.passwd

    <IfModule mod_php4.c>
      php_flag magic_quotes_gpc Off
      php_flag track_vars On
    </IfModule>
  </Directory>
</VirtualHost>

# /etc/init.d/apache2 restart
Restarting web server: apache2 ... waiting .
#
...using a subdomain
# nano /etc/apache2/sites-available/svn.server-2
<VirtualHost *:80>
  ServerAdmin xxx.yyy@zzz.com
  ServerName svn.server-2
  DocumentRoot /usr/share/websvn/

  <Location />
    Options FollowSymLinks
    #AllowOverride None
    order allow,deny
    allow from all
    #AuthType Basic
    #AuthName "Subversion Repository"
    #Require valid-user
    #AuthUserFile /etc/apache2/dav_svn.passwd

    <IfModule mod_php4.c>
      php_flag magic_quotes_gpc Off
      php_flag track_vars On
    </IfModule>
  </Location>
</VirtualHost>
# ln -s /etc/apache2/sites-available/svn.server-2 /etc/apache2/sites-enabled/010-svn.server-2
# /etc/init.d/apache2 restart

Test

Open in browser: http://<server_name>/websvn/

Usage

Open in browser: http://<server_name>/websvn/