/******************************************************************************* * Copyright (c) 2010 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.databoard.accessor.binary; import java.io.IOException; import org.simantics.databoard.Bindings; import org.simantics.databoard.accessor.Accessor; import org.simantics.databoard.accessor.StringAccessor; import org.simantics.databoard.accessor.error.AccessorConstructionException; import org.simantics.databoard.accessor.error.AccessorException; import org.simantics.databoard.accessor.error.ReferenceException; import org.simantics.databoard.accessor.event.Event; import org.simantics.databoard.accessor.event.ValueAssigned; import org.simantics.databoard.accessor.file.FileStringAccessor; import org.simantics.databoard.accessor.impl.AccessorParams; import org.simantics.databoard.accessor.impl.ListenerEntry; import org.simantics.databoard.accessor.interestset.StringInterestSet; import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.StringBinding; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.type.StringType; import org.simantics.databoard.util.binary.Blob; import org.simantics.databoard.util.binary.Endian; import org.simantics.databoard.util.binary.UTF8; public class BinaryString extends BinaryObject implements StringAccessor, FileStringAccessor { public BinaryString(BinaryObject parent, Blob blob, StringType type, AccessorParams params) throws AccessorConstructionException { super(parent, blob, type, params); } @Override public StringType type() { return (StringType) type; } @Override Event applyLocal(Event e, boolean makeRollback) throws AccessorException { Event rollback = makeRollback ? new ValueAssigned( Bindings.STRING, getValue() ) : null; if (e instanceof ValueAssigned) { ValueAssigned va = (ValueAssigned) e; if (va.newValue == null) throw new AccessorException("String value expected, got null"); setValueNoflush(va.newValue.getBinding(), va.newValue.getValue()); return rollback; } else { throw new AccessorException("Cannot apply "+e.getClass().getName()+" to String"); } } @SuppressWarnings("unchecked") @Override public T getComponent(ChildReference reference) throws AccessorConstructionException { if (reference==null) return (T) this; throw new ReferenceException(reference.getClass()+" is not a subreference of StringType"); } @Override public Object getValue(Binding binding) throws AccessorException { try { StringBinding bb = (StringBinding) binding; String v = getValue(); return bb.create(v); } catch(BindingException e) { throw new AccessorException(e); } } // MODIFIED UTF-8 @Override public String getValue() throws AccessorException { assert b.isOpen(); readLock(); try { b.position(0L); int utflen = Endian.readDynamicUInt32(b); return UTF8.readModifiedUTF(b, utflen); } catch (IOException e) { throw new AccessorException(e); } finally { readUnlock(); } } public void setValueNoflush(String string) throws AccessorException { assert b.isOpen(); writeLock(); try { // Write b.position(0); int strlen = UTF8.getModifiedUTF8EncodingByteLength(string); int lenlen = Endian.getDynamicUInt32Length(strlen); b.setLength(strlen+lenlen); Endian.writeDynamicUInt32(b, strlen); UTF8.writeModifiedUTF(b, string); // Notify ListenerEntry le = listeners; while (le!=null) { StringInterestSet is = le.getInterestSet(); if (is.inNotifications()) { Event e = new ValueAssigned( Bindings.STRING, is.inValues() ? string : null ); emitEvent(le, e); } le = le.next; } } catch (IOException e) { throw new AccessorException(e); } finally { writeUnlock(); } } /* REAL UTF-8 @Override public String getValue() throws AccessorException { readLock(); try { b.position(0L); int length = UTF8StringSerializer.getLength(b); byte[] bytes = new byte[length]; b.readFully(bytes); return new String(bytes, UTF8StringSerializer.UTF8); } catch (IOException e) { throw new AccessorException(e); } finally { readUnlock(); } } public void setValueNoflush(String string) throws AccessorException { writeLock(); try { // Write int stringByteLength = UTF8StringSerializer.getUTF8EncodingByteLength( string ); int lengthLength = UTF8StringSerializer.getSizeOfPutLength( stringByteLength ); int len = stringByteLength + lengthLength; b.position(0); b.setLength(len); byte[] bytes = string.getBytes( UTF8StringSerializer.UTF8 ); UTF8StringSerializer.putLength(b, bytes.length); b.put(bytes); // Notify ListenerEntry le = listeners; while (le!=null) { StringInterestSet is = le.getInterestSet(); if (is.inNotifications()) { Event e = new ValueAssigned( Bindings.STRING, is.inValues() ? string : null ); emitEvent(le, e); } le = le.next; } } catch (IOException e) { throw new AccessorException(e); } finally { writeUnlock(); } } */ @Override public void setValue(String string) throws AccessorException { assert b.isOpen(); writeLock(); try { setValueNoflush(string); b.flush(); } catch (IOException e) { throw new AccessorException(e); } finally { writeUnlock(); } } @Override public void setValueNoflush(Binding binding, Object newValue) throws AccessorException { try { String nv = ((StringBinding)binding).getValue(newValue); setValueNoflush(nv); } catch (BindingException e) { throw new AccessorException(e); } } }