blob: bcdb256f3b198ecf976f38426f352f8b62fcf945 [file] [log] [blame]
/*
* 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();
}
}