/* * BeanAssembler.java Copyright (c) 2005 by University of Hamburg. All Rights * Reserved. Departament of Informatics. Distributed Systems and Information * Systems. Created by walczak on Jan 16, 2006. Last revision $Revision: 6926 $ * by: $Author: braubach $ on $Date: 2008-09-28 22:16:58 +0200 (So, 28 Sep 2008) * $. */ package nuggets; import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import nuggets.IReader.Buffer; /** * BeanAssembler * * @author walczak * @since Jan 16, 2006 */ public class BeanAssembler implements IAssembler { private static final int OBJECT_ARRAY_LENGTH = 512; private Object[] objects = new Object[OBJECT_ARRAY_LENGTH]; private final ArrayList delayed = new ArrayList(); private IReader reader; private String pack; /** * @param reader */ public void setReader(IReader reader) { this.reader = reader; } /** * @param rdr * @return the object with id == 0 */ public Object assemble(Reader rdr, ClassLoader classloader) { try { clear(); parse(rdr, classloader); perform_delayed(); } catch(Exception e) { e.printStackTrace(); throw new PersistenceException(e); } return get(1); } /** * remove all chached objects from this one */ public void clear() { delayed.clear(); Arrays.fill(objects, null); } // ------------ IAssembler ----------------- /** * @param attribute * @return the value of the attribute including null if not available yet */ public Object getAttributeValue(String attribute) { int i = reader.getAttributeIndex(attribute); if(i < 0) return null; if(!reader.isReferenceAttribute(i)) return reader.getAttributeValue(i); String str_id = reader.getAttributeValue(i); int id = Integer.parseInt(str_id, 16); if(has(id)) return get(id); // else delay(new AttributeSetOperation(delegate, object, attribute, str_id)); return null; } /** buffer for reader text */ protected Buffer buffer; /** the offset of next token - space separated */ protected int token_offset; private IDelegate delegate; private Object object; /** * @return the text of an element * @see nuggets.IAssembler#getText() */ public String getText() { if(buffer == null) { buffer = reader.getText(); if(buffer == null) return null; // no more tokens from reader for } return reader.decodeText(buffer.chars, buffer.start, buffer.len); } /** * @return return the byte array from the text data * @see nuggets.IAssembler#getData() */ public byte[] getData() { return reader.getData(); } /** * It assumes that there is only one text content per element * * @return the next token from character stream * @see nuggets.IAssembler#nextToken() */ public String nextToken() { if(buffer == null) { buffer = reader.getText(); if(buffer == null) return null; // no more tokens from reader for // this element token_offset = buffer.start; } int end = buffer.start + buffer.len; for(int i = token_offset; i < end; i++) { char c = buffer.chars[i]; if(c == ' ') { if(i > token_offset) { String ret = new String(buffer.chars, token_offset, i - token_offset); token_offset = i + 1; return ret; } token_offset = i + 1; } } if(end > token_offset) { String ret = new String(buffer.chars, token_offset, end - token_offset); token_offset = end; return ret; } return null; } /** * @param sid * @return the object with id * @throws InstanceNotAvailableException */ public Object getValue(String sid) throws InstanceNotAvailableException { try { int id = Integer.parseInt(sid, 16); if(id == 0) return null; Object ret = objects[id]; if(ret == null) { throw new InstanceNotAvailableException(sid); } return ret; } catch(NumberFormatException nfe) { throw new PersistenceException(nfe); } } /** * @param op * @see nuggets.IAssembler#delay(nuggets.IDelayedOperation) */ public void delay(IDelayedOperation op) { delayed.add(op); } /** * @return the reader used to read the document * @see nuggets.IAssembler#getReader() */ public IReader getReader() { return reader; } // ---------------------------------------------------------------- /** * @param id * @return tests if the object with this id is read */ private boolean has(int id) { return id == 0 || id < objects.length && objects[id] != null; } /** * @param id * @return tests if the object with this id is read */ private Object get(int id) { return id < objects.length ? objects[id] : null; } /** * @param rdr * @throws Exception */ private void parse(Reader rdr, ClassLoader classloader) throws Exception { reader.start(rdr); this.pack = reader.getAttributeValue("xmlns"); String tag; while((tag = reader.nextElement()) != null) { buffer = null; int id = Integer.parseInt(reader.getID(), 16); Class clazz = getClass(tag, classloader); delegate = PersistenceHelper.getDelegate(clazz, classloader); object = delegate.getInstance(clazz, this); set(id, object); delegate.assemble(object, this); } } /** * @param id * @param obj */ private void set(int id, Object obj) { if(objects.length <= id) { Object[] tmp = new Object[Math.max(id + 64, objects.length << 1)]; System.arraycopy(objects, 0, tmp, 0, objects.length); objects = tmp; } objects[id] = obj; } /** * performs all delayed operations */ private void perform_delayed() { int len = delayed.size(); for(int i = 0; i < len; i++) { IDelayedOperation l = (IDelayedOperation)delayed.get(i); try { l.perform(this); } catch(Exception e) { e.printStackTrace(); } } delayed.clear(); } /** * @param tag * @return the class for this tag * * Java Bug with classloader.loadClass() fails in JDK6 for array types. * http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=8ba64503affecffffffffb6789c3d861677d?bug_id=6434149 */ private Class getClass(String tag, ClassLoader classloader) { // In case no classloader is set use current or context classloader? if(classloader==null) { // classloader = BeanAssembler.class.getClassLoader(); classloader = Thread.currentThread().getContextClassLoader(); } if(tag.startsWith("array")) { tag = reader.getAttributeValue("type"); } try { if(pack != null && tag.indexOf('.') < 0) return Class.forName(pack + '.' + tag, true, classloader); // return classloader.loadClass(pack + '.' + tag); } catch(ClassNotFoundException e1) { /* NOP */ } try { return Class.forName(tag, true, classloader); // return classloader.loadClass(tag); } catch(ClassNotFoundException e) { throw new PersistenceException(e); } } }