| /* |
| * Copyright (c) 2010-2013, 2015 Eike Stepper (Berlin, Germany) and others. |
| * 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: |
| * Simon McDuff - initial API and implementation |
| * Ibrahim Sallam - code refactoring for CDO 3.0 |
| */ |
| package org.eclipse.emf.cdo.server.internal.objectivity.schema; |
| |
| import org.eclipse.emf.cdo.common.revision.CDORevision; |
| import org.eclipse.emf.cdo.server.internal.objectivity.bundle.OM; |
| import org.eclipse.emf.cdo.server.internal.objectivity.db.ObjyClass; |
| import org.eclipse.emf.cdo.server.internal.objectivity.db.ObjySchema; |
| import org.eclipse.emf.cdo.server.internal.objectivity.mapper.ITypeMapper; |
| |
| import org.eclipse.net4j.util.om.trace.ContextTracer; |
| |
| import com.objy.as.app.Class_Object; |
| import com.objy.as.app.Numeric_Value; |
| import com.objy.as.app.Proposed_Class; |
| import com.objy.as.app.String_Value; |
| import com.objy.as.app.VArray_Object; |
| import com.objy.as.app.d_Access_Kind; |
| import com.objy.as.app.d_Module; |
| import com.objy.as.app.ooBaseType; |
| import com.objy.db.app.ooId; |
| import com.objy.db.app.ooObj; |
| |
| /** |
| * @author Simon McDuff |
| */ |
| /*** |
| * This class we use VArray of fixed array of Strings, otherwise we have to create strigns as objects, which is |
| * expensive. |
| */ |
| public class ObjyArrayListString |
| { |
| private static final ContextTracer TRACER_DEBUG = new ContextTracer(OM.DEBUG, ObjyArrayListString.class); |
| |
| public static String ClassName = "ObjyArrayListString"; |
| |
| // embedded class parts. |
| private static String embeddedClassName = "oo_StringElement"; |
| |
| private static String embeddedAttributeName = "value"; |
| |
| private static String embeddedAttributeNull = "isNull"; |
| |
| // fixed array class parts. |
| private static String FixedArrayClassName = "ObjyFixedStringArray"; |
| |
| private static String FixedElementsName = "elements"; |
| |
| private static final long FixedElementsSize = 10; |
| |
| protected Class_Object classObject; |
| |
| private VArray_Object vArray; |
| |
| transient long cacheSize = -1; |
| |
| transient long position; |
| |
| public static void buildSchema() |
| { |
| d_Module top_mod = ObjySchema.getTopModule(); |
| |
| if (top_mod.resolve_class(ObjyArrayListString.ClassName) == null) |
| { |
| |
| if (TRACER_DEBUG.isEnabled()) |
| { |
| TRACER_DEBUG.trace("Schema not found for ooArrayListString. Adding ooArrayListString"); |
| } |
| |
| boolean inProcess = top_mod.proposed_classes().hasNext(); |
| |
| // using embedded class (string, isNull) |
| // Proposed_Class embeddedClass = new Proposed_Class(embeddedClassName); |
| Proposed_Class embeddedClass = top_mod.propose_new_class(embeddedClassName); |
| |
| embeddedClass.add_embedded_class_attribute(com.objy.as.app.d_Module.LAST, d_Access_Kind.d_PUBLIC, // Access kind |
| embeddedAttributeName, // Attribute name |
| 1, // # elements in fixed-size array |
| "ooUtf8String" // Type of numeric data |
| ); // Default value |
| |
| embeddedClass.add_basic_attribute(com.objy.as.app.d_Module.LAST, d_Access_Kind.d_PUBLIC, // Access kind |
| embeddedAttributeNull, // Attribute name |
| 1, // # elements in fixed-size array |
| ooBaseType.ooBOOLEAN // Type of numeric data |
| ); // Default value |
| |
| // top_mod.propose_new_class(embeddedClass); |
| |
| // first the child class. |
| // Proposed_Class fixedArrayClass = new Proposed_Class(ooArrayListString.FixedArrayClassName); |
| Proposed_Class fixedArrayClass = top_mod.propose_new_class(ObjyArrayListString.FixedArrayClassName); |
| |
| fixedArrayClass.add_base_class(com.objy.as.app.d_Module.LAST, com.objy.as.app.d_Access_Kind.d_PUBLIC, "ooObj"); |
| |
| fixedArrayClass.add_embedded_class_attribute(com.objy.as.app.d_Module.LAST, d_Access_Kind.d_PUBLIC, // Access kind |
| ObjyArrayListString.FixedElementsName, // Attribute name |
| ObjyArrayListString.FixedElementsSize, // # elements in fixed-size array |
| embeddedClassName // Type of numeric data |
| ); // Default value |
| |
| // top_mod.propose_new_class(fixedArrayClass); |
| |
| // Proposed_Class StringArrayClass = new Proposed_Class(ooArrayListString.ClassName); |
| Proposed_Class StringArrayClass = top_mod.propose_new_class(ObjyArrayListString.ClassName); |
| |
| StringArrayClass.add_base_class(com.objy.as.app.d_Module.LAST, com.objy.as.app.d_Access_Kind.d_PUBLIC, "ooObj"); |
| |
| StringArrayClass.add_basic_attribute(com.objy.as.app.d_Module.LAST, d_Access_Kind.d_PUBLIC, // Access kind |
| ObjyArrayList.sizeName, // Attribute name |
| 1, // # elements in fixed-size array |
| ooBaseType.ooINT32 // Type of numeric data |
| ); // Default value |
| |
| StringArrayClass.add_varray_attribute(com.objy.as.app.d_Module.LAST, d_Access_Kind.d_PUBLIC, // Access kind |
| ObjyArrayList.arrayName, // Attribute name |
| 1, false, ObjyArrayListString.FixedArrayClassName); |
| |
| // top_mod.propose_new_class(StringArrayClass); |
| if (!inProcess) |
| { |
| top_mod.activate_proposals(true, true); |
| } |
| |
| if (TRACER_DEBUG.isEnabled()) |
| { |
| TRACER_DEBUG.trace("SCHEMA changed : ooArrayListString added"); |
| } |
| } |
| } |
| |
| public static void initObject(Class_Object classObject) |
| { |
| // set the size to 0; |
| classObject.nset_numeric(ObjyArrayList.sizeName, new Numeric_Value(0)); |
| } |
| |
| public ObjyArrayListString(Class_Object classObject) |
| { |
| this.classObject = classObject; |
| } |
| |
| // TODO - there is no check if the index is out of bound. |
| protected void setValue(long index, String newValue) |
| { |
| // find the chunk. |
| long chunkItem = index / FixedElementsSize; |
| long chunkIndex = index % FixedElementsSize; |
| Class_Object chunkObject = getVArray().get_class_obj(chunkItem); |
| // String_Value value = chunkObject.nget_string(FixedElementsName, chunkIndex); |
| Class_Object embeddedElement = chunkObject.nget_class_obj(FixedElementsName, chunkIndex); |
| // TODO - I don't like using magic numbers!!! we are using "1" to index into the embedded object. |
| embeddedElement.set_numeric(1, newValue == null ? ITypeMapper.numericTrue : ITypeMapper.numericFalse); |
| // String_Value value = embeddedElement.get_string(0); // TODO - I don't like using magic numbers!!! |
| String_Value value = embeddedElement.nget_string(embeddedAttributeName); |
| value.update(); |
| if (newValue == null) |
| { |
| newValue = ""; |
| } |
| value.set(newValue); |
| } |
| |
| protected String getValue(long index) |
| { |
| // find the chunk. |
| long chunkItem = index / FixedElementsSize; |
| long chunkIndex = index % FixedElementsSize; |
| Class_Object chunkObject = getVArray().get_class_obj(chunkItem); |
| // String_Value value = chunkObject.nget_string(FixedElementsName, chunkIndex); |
| Class_Object embeddedElement = chunkObject.nget_class_obj(FixedElementsName, chunkIndex); // TODO - I don't like |
| // using magic numbers!!! |
| String_Value value = embeddedElement.nget_string(embeddedAttributeName); |
| Numeric_Value isNull = embeddedElement.get_numeric(1); |
| return isNull == ITypeMapper.numericTrue ? null : value.toString(); |
| } |
| |
| public String[] getAll(int index, int chunkSize) |
| { |
| int size = (int)cachedSize(); |
| |
| if (chunkSize != CDORevision.UNCHUNKED) |
| { |
| size = Math.min(size, chunkSize); |
| } |
| |
| String[] strings = new String[size]; |
| Class_Object currentChunkObject = null; |
| long currentChunkItem = -1; |
| |
| for (int i = 0; i < size; i++) |
| { |
| // find the chunk. |
| long chunkItem = (i + index) / FixedElementsSize; |
| long chunkIndex = (i + index) % FixedElementsSize; |
| if (currentChunkItem != chunkItem) |
| { |
| currentChunkItem = chunkItem; |
| currentChunkObject = getVArray().get_class_obj(currentChunkItem); |
| } |
| Class_Object embeddedElement = currentChunkObject.nget_class_obj(FixedElementsName, chunkIndex); |
| String_Value value = embeddedElement.nget_string(embeddedAttributeName); |
| Numeric_Value isNull = embeddedElement.get_numeric(1); |
| if (isNull == ITypeMapper.numericTrue) |
| { |
| strings[i] = null; |
| } |
| else |
| { |
| strings[i] = value.toString(); |
| } |
| } |
| return strings; |
| } |
| |
| public void clear() |
| { |
| // remove all the fixed array objects... |
| for (int i = 0; i < getVArray().size(); i++) |
| { |
| ooId oid = getVArray().get_ooId(i); |
| ooObj.create_ooObj(oid).delete(); |
| } |
| getVArray().resize(0); |
| cacheSize = 0; |
| saveSize(); |
| } |
| |
| private void shiftRight(int index) |
| { |
| shiftRight(index, 1); |
| } |
| |
| private void shiftRight(int index, int sizeToShift) |
| { |
| long size = cachedSize(); |
| |
| for (long i = size - 1; i >= index; i--) |
| { |
| setValue(i + sizeToShift, getValue(i)); |
| } |
| |
| cacheSize += sizeToShift; |
| } |
| |
| private void shiftLeft(int index) |
| { |
| long size = cachedSize(); |
| for (long i = index; i < size - 1; i++) |
| { |
| setValue(i, getValue(i + 1)); |
| } |
| |
| cacheSize--; |
| |
| saveSize(); |
| } |
| |
| /** |
| * |
| */ |
| private void grow(int numToAdd) |
| { |
| long arraySize = cachedSize(); |
| long numChunks = (numToAdd + (int)arraySize) / FixedElementsSize + 1; |
| long newChunks = numChunks - arraySize; |
| if (newChunks > 0) |
| { |
| getVArray().resize(numChunks); |
| // TODO - this could be cached somewhere... |
| ObjyClass chunkClass = ObjySchema.getObjyClass(FixedArrayClassName); |
| for (int i = 0; i < newChunks; i++) |
| { |
| // create a new chunk. |
| Class_Object newChunk = Class_Object.new_persistent_object(chunkClass.getASClass(), classObject.objectID(), |
| false); |
| getVArray().set_ooId(arraySize + i, newChunk.objectID()); |
| } |
| cacheSize = -1; |
| } |
| } |
| |
| /** |
| * |
| */ |
| private void prepareToInsert(int numberToAdd) |
| { |
| long size = cachedSize(); |
| getVArray().update(); |
| |
| if (size + numberToAdd > getVArray().size()) |
| { |
| grow(numberToAdd); |
| } |
| } |
| |
| protected VArray_Object getVArray() |
| { |
| if (vArray == null) |
| { |
| vArray = classObject.nget_varray(ObjyArrayList.arrayName); |
| } |
| return vArray; |
| } |
| |
| public void add(int index, String newValue) |
| { |
| prepareToInsert(1); |
| |
| shiftRight(index); |
| |
| basicSet(index, newValue); |
| |
| saveSize(); |
| } |
| |
| public void addAll(int index, Object[] newValue) |
| { |
| prepareToInsert(newValue.length); |
| shiftRight(index, newValue.length); |
| |
| for (int i = 0; i < newValue.length; i++) |
| { |
| basicSet(index + i, (String)newValue[i]); |
| } |
| |
| saveSize(); |
| } |
| |
| public void remove(int index) |
| { |
| shiftLeft(index); |
| } |
| |
| public void add(String newValue) |
| { |
| long size = cachedSize(); |
| |
| prepareToInsert(1); |
| |
| setValue(size, newValue); |
| |
| cacheSize++; |
| |
| saveSize(); |
| } |
| |
| public void set(long index, String newValue) |
| { |
| basicSet(index, newValue); |
| cacheSize = -1; |
| } |
| |
| protected void basicSet(long index, String newValue) |
| { |
| if (index >= cachedSize()) |
| { |
| throw new ArrayIndexOutOfBoundsException(); |
| } |
| |
| getVArray().update(); |
| |
| setValue(index, newValue); |
| } |
| |
| public String get(long index) |
| { |
| if (index >= size()) |
| { |
| throw new ArrayIndexOutOfBoundsException(); |
| } |
| |
| return getValue(index); |
| } |
| |
| private void saveSize() |
| { |
| classObject.nset_numeric(ObjyArrayList.sizeName, new Numeric_Value(cacheSize)); |
| cacheSize = -1; |
| } |
| |
| public long cachedSize() |
| { |
| if (cacheSize == -1) |
| { |
| cacheSize = classObject.nget_numeric(ObjyArrayList.sizeName).longValue(); |
| } |
| return cacheSize; |
| } |
| |
| public long size() |
| { |
| return classObject.nget_numeric(ObjyArrayList.sizeName).longValue(); |
| } |
| |
| } |