суббота, 13 декабря 2008 г.

Global security in WAS 6.1over Active Directory

We need security over Active Directory in our enterprise application wich works on WebSphere Application Server v 6.1.x. When we test our application we use OpenDS(https://opends.dev.java.net/) to emulate Active Directory. But we must replace OpenDS with Active Directory. Every LDAP server has specific parameters. For fast test, I use ldapsearch from OpenDS. I spent more then two hours to get success result.

Success command is: ldapsearch.bat -b "dc=domain,dc=com" -D "cn=username,cn=users,dc=domain,dc=com" "(&(|(cn=username)(samAccountName=username))(objectclass=user))".

When I get user with username username, I move this settings to WebSphere Application Server. Also, user should be in group Domain Administrator.

We must set next settings in WAS(sorry me, but name of parameters are not exact, because I have russian version of WAS):

Administrator username: username

Host: localhost(or other if AD server installed on other host)

LDAP Server Type: Active Directory

Base DN: dc=domain, dc=com

Other DN: cn=username,cn=users,dc=domain,dc=com

Password for connect: domain password for user

In next step we should set filters(Additional Parameters for LDAP registry):

User Filter: (&(|(cn=%v)(samAccountName=%v))(objectclass=user))

Group Filter: (&(cn=%v)(objectcategory=group))

ID user map: user:sAMAccountName

ID group map: *:cn

And now you can set current global security as autonomous LDAP registry!

пятница, 5 декабря 2008 г.

SVN: Update only new folders in working copy

Hi all!
For example, you have working copy that looks like this:
foo/
bar/


And you know that someone added new folder, that called baz, in repository. You want get only this folder and you don't want to update all working copy. Solution is very simple:

C:\project\>svn update baz

That's all, now you have new folder in your working copy.

P.S. You can't do this, using popular frontend for svn - TortoiseSVN.

четверг, 20 ноября 2008 г.

Placeholder trick in Spring

Hello everyone! In the Spring Framework (I use Spring 2.5), we can use property placeholders in the spring xml-based configuration file. I wrote simple example that consist of four beans. Two of them are simple beans, one is a factory and one is a result bean that we want to get from factory bean.


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

    <bean id=”simpleFactory” class=”c om.blogger.dooman87.SimpleFactory”>
        <constructor-arg value=”$ {com.blogger.dooman87.resultBeanName}”>
    </bean>

    <bean id="resultBean" factory-bean=”s impleFactory”/>

    <bean id="simpleBeanFirst"
        class="com.blogger.dooman87.SimpleBeanFirst"/>

    <bean id="simpleBeanSecond"
        class="com.blogger.dooman87.SimpleBeanSecond"/>
</beans>


In this case, we should write additional class com.blogger.dooman87.SimpleFactory, that would instantiate result by first constructor argument. This class we can extend from AbstractFactoryBean. But as well we are able to replace the factory! This simple trick you can see below:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

    <alias name="${com.blogger.dooman87.resultBeanName}" alias="resultBean"/>

    <bean id="simpleBeanFirst"
        class="com.blogger.dooman87.SimpleBeanFirst"/>

    <bean id="simpleBeanSecond"
        class="com.blogger.dooman87.SimpleBeanSecond"/>
</beans>


We created alias for result bean, where the name is a placeholder value. That's all. Hope this post was interesting or you.

среда, 5 ноября 2008 г.

Reading from InputStream

Lately I've faced a simple problem: I needed to read all bytes from the InputStream. I didn't know type of the InputStream, so, I've spent more then two hours solving this problem without any success. I didn't want to read each byte from the stream. All evening I could think only about this problem. Solution turned to be very simple! I found a sample in the JDK installation directory($JAVA_HOME/sample/nio/). JDK 1.5(and higher) is a good API to work with streams over channels. The source code to read all bytes from the InputStream is rather simple:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

/**
 * @author Pokidov.Dmitry
 *         Date: 13.04.2009
 */
public class IOHelper {
 /*Block size that we want to read in one time.*/
 private static final int READ_BLOCK = 8192; 

 /*
  * Read all from stream, using nio.
  * @param is source stream.
  * @return result byte array that read from source
  * @throws IOException by {@code Channel.read()}
  */
 public static byte[] readToEnd(InputStream is) throws IOException {
  //create channel for input stream
  ReadableByteChannel bc = Channels.newChannel(is);
  ByteBuffer bb = ByteBuffer.allocate(READ_BLOCK);

  while (bc.read(bb) != -1) {
   bb = resizeBuffer(bb); //get new buffer for read
  }
  byte[] result = new byte[bb.position()];
  bb.position(0);
  bb.get(result);

  return result;
 }

 private static ByteBuffer resizeBuffer(ByteBuffer in) {
  ByteBuffer result = in;
  if (in.remaining() < READ_BLOCK) {
   //create new buffer
   result = ByteBuffer.allocate(in.capacity() * 2);
   //set limit to current position in buffer and set position to zero.
   in.flip();
   //put original buffer to new buffer
   result.put(in);
  }

  return result;
 }

Also I found an interesting book in which you can read about the nio package: get it here

понедельник, 6 октября 2008 г.

Using reflections for test equals.

Problem: test for equals two objects of the same class by all fields(deep equals).
For solve this problem I use reflection API from JDK. Package that store classes for reflection is java.lang.reflect. I wrote simple helper class with static methods.

You can find the complete realization at the and of the post.

First of all we should describe algorithm:
Input: two object that we need compare.
Steps:
1. Check objects references
obj1 == obj2

2.Check that names of classes for this objects are identically
c1.getName().compareTo(c2.getName()) == 0

3.While class is not java.lang.Object do steps from 4 to 8
while (!c1.getName().equals(Object.class.getName()))  {...}

4.Go through all fields in class

for (Field f1 : c1.getDeclaredFields())

5.Ignore inner classes, because they have cross references and we have infinity loop.
if (!f1.getName().contains("this$")) {...}

6.Get the same field from second class.
Field f2 = c2.getDeclaredField(f1.getName());

7.Turn off access checking(we want equals all:))
f1.setAccessible(true);
f2.setAccessible(true);

8.Call method that do test objects of these fields and if its result is fail return false.
if (!doObjectEquals(f1.get(obj1), f2.get(obj2))) {
    return false;
}

9.When process all fields, get the super classes of our objects, cast objects to superclass and go to step 4.
c1 = c1.getSuperclass();
c2 = c2.getSuperclass();
obj1 = c1.cast(obj1);
obj2 = c2.cast(obj2);

Now, we can write method that will be equals two objects. First of all, we should check this objects for nulls. If both objects are null, then we do nothing and return true. If one of this object is null...then we do nothing, too :), but return false. For equals two objects, we should try to find declared method equals(). If the object have this method, then we call it and return it's result, else we should recursively call first method for equals each field in this object. Also in this method we should process arrays and collections. In Java, Collections API have three kind of objects. There are Set, List and Map.  In Map we can compare Set of Map.Entry objects, that returns method Map.entrySet(). Notice, that these methods compare items in array without order.

I write some static helpers for equals collections using reflections.

Also, we should specially equals  fields of enum types.  We can check field using method Field.isEnumConstant(). If field is enum constant, we should simple equals() values .

Finally, helper class looks like this:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author : Pokidov.Dmitry
 * @date: 27.05.2008
 * 

* Class that help to test equals for two object. * For test use {@code weakEquals()} method. */ public class WeakEqualsHelper { private static ArrayList<String> errorLog = new ArrayList<String>(); private static Map<String, List<String>> fields; private enum CheckNullsResult { BOTH_NULLS, NOT_NULLS, ONE_NULL; } /** * Recursively compare object by its class and all superclasses. * To standalone test collections, arrays and maps use methods: * {@code equalsCollection(), equalsArray(), equalsMap()} * * @param o1 First object for compare * @param o2 Second object for compare * @return {@code true}, if objects are equals, else {@code false} */ public static boolean weakEquals(Object o1, Object o2) { return weakEquals(o1, o2, null); } /** * Recursively compare object by its class and all superclasses. * To standalone test collections, arrays and maps use methods: * {@code equalsCollection(), equalsArray(), equalsMap()} * * @param o1 First object for compare * @param o2 Second object for compare * @param notEqualsFields fields that will be ignore. Key is name of class, Value - list of field's name. * @return {@code true}, if objects are equals, else {@code false} */ public static boolean weakEquals(Object o1, Object o2, Map<String, List<String>> notEqualsFields) { fields = notEqualsFields; boolean ret = doEquals(o1, o2); if (!ret) { for (String error : errorLog) { System.out.println(error); } } return ret; } public boolean weakEquals(Object o) { if (o == null || !(o instanceof WeakEqualsHelper)) { return false; } return o == this || doEquals(this, o); } private static boolean needEqual(Field f, Map<String, List<String>> fields) { if (fields != null) { List<String> classFields = fields.get(f.getDeclaringClass().getName()); return !(classFields != null && classFields.contains(f.getName())); } return true; } public static boolean doEquals(Object obj1, Object obj2) { if (obj1 == obj2) { return true; } Class c1 = obj1.getClass(); Class c2 = obj2.getClass(); if (c1.getName().compareTo(c2.getName()) == 0) { while (!c1.getName().equals(Object.class.getName())) { for (Field f1 : c1.getDeclaredFields()) { if (needEqual(f1, fields)) { String errorMessage = "ERROR: Class " + obj1.getClass().getName() + " are not equal in field -->" + f1.getName() + "<--"; if (!f1.getName().contains("this$")) { try { Field f2 = c2.getDeclaredField(f1.getName()); f1.setAccessible(true); f2.setAccessible(true); errorLog.add("Current field-->" + f1.getName() + "<--"); if (f1.isEnumConstant()) { if (!f1.get(obj1).equals(f2.get(obj2))) { return false; } } else if (!doObjectEquals(f1.get(obj1), f2.get(obj2))) { errorLog.add(errorMessage + "[" + (f1.get(obj1) != null && f1.get(obj1).equals("null") ? "NULL" : f1.get(obj1)) + ":" + (f2.get(obj2) != null && f2.get(obj2).equals("null") ? "NULL" : f2.get(obj2)) + "]"); return false; } } catch (NoSuchFieldException nsme) { errorLog.add("ERROR: No such field " + f1.getName()); return false; } catch (IllegalAccessException e) { e.printStackTrace(); return false; } } else { errorLog.add("INFO: ignore field -->" + f1.getName() + "<--"); } } else { System.out.println("INFO: ignore field -->" + f1.getName() + "<--"); } } c1 = c1.getSuperclass(); c2 = c2.getSuperclass(); obj1 = c1.cast(obj1); obj2 = c2.cast(obj2); } } else { errorLog.add("Class names are not equals in field[" + c1.getName() + "," + c2.getName() + "]"); return false; } return true; } private static boolean doObjectEquals(Object o1, Object o2) { if (checkNulls(o1, o2) == CheckNullsResult.NOT_NULLS) { if (o1 instanceof Map.Entry) { Map.Entry e1 = (Map.Entry) o1; Map.Entry e2 = (Map.Entry) o2; return doObjectEquals(e1.getKey(), e2.getKey()) && doObjectEquals(e1.getValue(), e2.getValue()); } else if (o1 instanceof Map) { return equalsMap((Map) o1, (Map) o2); } else if (o1 instanceof Collection) { return equalsCollection((Collection) o1, (Collection) o2); } else if (o1.getClass().isArray()) { return equalsArray((Object[]) o1, (Object[]) o2); } else if (!o1.getClass().getName().equals(Object.class.getName())) { if (hasEquals(o1.getClass())) { if (!o1.equals(o2)) { if (o1 instanceof String && o2 instanceof String) { String s1 = ((String) o1).replaceAll("[\n\t\r ]", ""); String s2 = ((String) o2).replaceAll("[\n\t\r ]", ""); if (!s1.equals(s2)) { return false; } else { System.out.println("WARNING: Strings are not equals with escape symbols and whitespaces"); return true; } } System.out.println("Equals return false"); return false; } return true; } else { return doEquals(o1, o2); } } System.out.println("UNKNOWN TYPE: " + o1.getClass().getName()); } return equalsForNull(o1, o2); } private static CheckNullsResult checkNulls(Object object, Object otherObject) { if (object == null && otherObject == null) { return CheckNullsResult.BOTH_NULLS; } if (object != null && otherObject != null) { return CheckNullsResult.NOT_NULLS; } return CheckNullsResult.ONE_NULL; } private static boolean equalsForNull(Object object, Object otherObject) { return object == null && otherObject == null; } public static boolean equalsMap(Map map, Map otherMap) throws NullPointerException { return equalsCollection(map.entrySet(), otherMap.entrySet()); } public static boolean equalsCollection(Collection collection, Collection otherCollection) throws NullPointerException { return equalsArray(collection.toArray(), otherCollection.toArray()); } public static boolean equalsArray(Object[] array, Object[] otherArray) throws NullPointerException { if (array.length != otherArray.length) { errorLog.add("Array or Collection length are not equals[" + array.length + "," + otherArray.length + "]"); return false; } ArrayList<Integer> usedIndexes = new ArrayList<Integer>(); for (int i = 0; i < array.length; i++) { Object currObject = array[i]; boolean found = false; for (int k = 0; k < otherArray.length; k++) { if (!usedIndexes.contains(k)) { found = doObjectEquals(currObject, otherArray[k]); if (found) { usedIndexes.add(k); break; } } } if (!found) { return false; } } return true; } private static boolean hasEquals(Class c) { Method[] methods = c.getDeclaredMethods(); for (Method m : methods) { if (m.getName().equals("equals") && m.getParameterTypes().length == 1) { return true; } } return false; } /*------------TEST------------*/ public class TestClass { public class TestNestClass extends TestClass { public TestNestClass(int a, int b, ArrayList list) { super(a, b, list); } public void setD(int d) { this.d = d; } public void putMap(String s, Integer i) { map.put(s, i); } private int d; private Map<String, Integer> map = new HashMap<String, Integer>(); } private int a; private int b; private ArrayList list = new ArrayList(); private String c = "Hello!!!"; public TestClass(int a, int b, ArrayList list) { this.a = a; this.b = b; this.list = list; } public int getA() { return a; } public int getB() { return b; } public String getC() { return c; } public void setC(String c) { this.c = c; } public ArrayList getList() { return list; } public TestNestClass createNest() { return new TestNestClass(a, b, list); } } public TestClass createTestClass(int a, int b, ArrayList list) { return new TestClass(a, b, list); } public static void main(String[] args) { ArrayList ar1 = new ArrayList(); ar1.add(1); ar1.add(5); ar1.add(7); ArrayList ar2 = new ArrayList(); ar2.add(1); ar2.add(5); ar2.add(7); WeakEqualsHelper eh = new WeakEqualsHelper(); TestClass tc1 = eh.createTestClass(1, 15, ar1); TestClass tc2 = eh.createTestClass(1, 15, ar2); TestClass.TestNestClass tnc = tc1.createNest(); TestClass.TestNestClass tnc2 = tc2.createNest(); tnc.putMap("Hello", 1); tnc2.putMap("Hello", 1); tnc.putMap("goodbye", 1); tnc2.putMap("goodbye", 1); System.out.println("tc1.equals(tc2) == " + WeakEqualsHelper.doEquals(tnc, tnc2)); } }


I add some features in this implementation:
-I can pass Map<string, List<String>> that contains class name as key and list of fields name that will be ignored when equals
-If string are not equals, then its will be equals igonring escape symbols and whitespaces.
-I add simple test.

Usage: I use this class in unit testing when migrate from digester to castor. We need serialization of objects.
I rewrite over 1MB of mappings. I was in hell :)

UPD: do formatting, now you can simple copy class and use it.

воскресенье, 28 сентября 2008 г.

Connect to mysql 5 with Tomcat 6

When I try to solve this problem I read two docs: help in Netbeans 6(http://www.netbeans.org/kb/60/web/mysql-webapp.html#settingUpConnPool) and jndi help from tomcat.apache.org(http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html). But when I lookup InitialContext, application throws NamingException. I spent over four hours to solve this problem. As I've understood, when I create resource in context.xml which placed in web application, Tomcat dont put it in global resources and when I connect to this resource, I should write prefix java:comp/env/ before actual resource name. I replace this line:

Datasource ds = (Datasource)ic.lookup("jdbs/sambledb");

with this:

Datasource ds = (Datasource)ic.lookup("java:comp/env/jdbs/sambledb");

YES! Lookup result was successfull.

I use oficial recommended jconnector version 5.1 from mysql.com. I copy jar with connector in TOMCAT_HOME/lib/, but I get ClassNotFoundException.... after long four or five hours I hate Window Vista, Tomcat, Netbeans, Java, Computers and...my life :) . I cannt direct solve this problem. I have no ideas how services in Windows works, but when I uninstall Tomcat which I downloaded from link with name Windows Service Installer(http://www.sai.msu.su/apache/tomcat/tomcat-6/v6.0.18/bin/apache-tomcat-6.0.18.exe) and install simple zip version (http://www.sai.msu.su/apache/tomcat/tomcat-6/v6.0.18/bin/apache-tomcat-6.0.18.zip) all works ok(YEAH!) :)

Some tips:

-Don't use empty password in mysql to connect.

-In different cases Tomcat throws exception sounds like this - driver "com.mysql.jdbc.Driver" not found. You can reduce number of meanings if insert in your code this line - Class.forName("com.mysql.jdbc.Driver").

-DONT USE SERVICE INSTALLER VERSION OF TOMCAT!!!(I like init.d:))

Finally I have something like this:

web.xml:

<resource-ref>
<description>jdbc:mysql://localhost:3306/mynewdatabase</description>
  <res-ref-name>jdbc/mynewdatabase/<res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

context.xml:

<Resource name="jdbc/mynewdatabase" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="javauser" password="qwerty" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/mynewdatabase"/></resource>

sample method to test connection:
...
public String getEmployers() {
  try {
    InitialContext ic = new InitialContext();
    DataSource ds = (DataSource)   ic.lookup("java:comp/env/jdbc/mynewdatabase");
    Connection con = ds.getConnection(); //NO User and Password, we set it in Resource
    Statement st = con.createStatement();

    ResultSet rs = st.executeQuery("SELECT * FROM employers");

    String ret = "Employers ";
    while (rs.next()) {
      ret += rs.getString("name") + ",";
    }
    return ret;
  } catch (SQLException ex) {
    return ex.getMessage();
  } catch (NamingException ex) {
    return ex.getMessage();
  }
}
...

If you have troubles, write its in comments and I try to help you.

понедельник, 15 сентября 2008 г.

Wrapper for JComponent

Trouble: we have some JComponent. We need paint this component and remove all logic from it.

At the begining, I think that solution is very simple: override paint() method, and draw inner component in wrpapper's Graphics.

public class ComponentWrapper extends JComponent {
  private JComponent innerComponent;

  public ComponentWrapper(JComponent innerComponent) {
      this.innerComponent = innerComponent;
  }

  @Override
  public void paint(Graphics g)
  {
      if (innerComponent != null) {
          innerComponent.paint(g);
      }
  }

}

But I don't see innerComponent, because it hasn't bound. We should delegate methods that set sizes and bound on innerComponent. Now our wrapper looks like this:

public class ComponentWrapper extends JComponent {
  private JComponent innerComponent;

  public ComponentWrapper(JComponent innerComponent) {
      this.innerComponent = innerComponent;
  }

  @Override
  public void paint(Graphics g) {
      innerComponent.paint(g);
  }
   
  @Override
  public void setMaximumSize(Dimension maximumSize) {
      super.setMaximumSize(maximumSize);
      innerComponent.setMaximumSize(maximumSize);
  }

  @Override
  public void setMinimumSize(Dimension minimumSize) {
      super.setMinimumSize(minimumSize);
      innerComponent.setMinimumSize(minimumSize);
  }

  @Override
  public void setPreferredSize(Dimension preferredSize) {
      super.setPreferredSize(preferredSize);
      innerComponent.setPreferredSize(preferredSize);
  }

  @Override
  public void setBounds(Rectangle r) {
      super.setBounds(r);
      innerComponent.setBounds(r);
  }

  @Override
  public void setBounds(int x, int y, int width, int height) {
      super.setBounds(x, y, width, height);
      innerComponent.setBounds(x, y, width, height);
  }

  @Override
  public void setSize(int width, int height) {
      super.setSize(width, height);
      innerComponent.setSize(width, height);
  }
}


At first blush all is ok. But if we wrap JPanel with some layout, we dont see anything. This occurs because components in panel haven't sizes. We should apply layout on panel. JComponent have a wonderful method - doLayout(). Now, when our wrapper change size, we need call innerComponent.doLayout() and after this components in panel will have actual sizes. In paint method we should iterate over components in panel and paint its in translated coordinates. 

Final class:

public class ComponentWrapper extends JComponent {
  private JComponent innerComponent;

  public ComponentWrapper(JComponent innerComponent) {
      this.innerComponent = innerComponent;
  }

  @Override
  public void paint(Graphics g) {

      if (innerComponent instanceof JPanel) {
          for (Component comp : innerComponent.getComponents()) {
              Graphics gnew = g.create();
              Point location = comp.getLocation();
              gnew.translate((int)location.getX(), (int)location.getY());
             comp.paint(gnew);

         }
      } else innerComponent.paint(g);
  }
   
  @Override
  public void setMaximumSize(Dimension maximumSize) {
      super.setMaximumSize(maximumSize);
      innerComponent.setMaximumSize(maximumSize);

      innerComponent.doLayout();
  }

  @Override
  public void setMinimumSize(Dimension minimumSize) {
      super.setMinimumSize(minimumSize);
      innerComponent.setMinimumSize(minimumSize);

      innerComponent.doLayout();
  }

  @Override
  public void setPreferredSize(Dimension preferredSize) {
      super.setPreferredSize(preferredSize);
      innerComponent.setPreferredSize(preferredSize);

      innerComponent.doLayout();
  }

  @Override
  public void setBounds(Rectangle r) {
      super.setBounds(r);
      innerComponent.setBounds(r);

      innerComponent.doLayout();
  }

  @Override
  public void setBounds(int x, int y, int width, int height) {
      super.setBounds(x, y, width, height);
      innerComponent.setBounds(x, y, width, height);

      innerComponent.doLayout();
  }

  @Override
  public void setSize(int width, int height) {
      super.setSize(width, height);
      innerComponent.setSize(width, height);

      innerComponent.doLayout();
  }
}

P.S.(Intro to my blog): Hi all, I hope that my tips help you. But my English is very bad and I want to do it better. If you can, correct me in comments, please.

Most popular

Authors