Skip to content

Instantly share code, notes, and snippets.

@smolinari
Last active September 22, 2016 06:28
Show Gist options
  • Save smolinari/609335f498c456bd97c3ff86ad6136db to your computer and use it in GitHub Desktop.
Save smolinari/609335f498c456bd97c3ff86ad6136db to your computer and use it in GitHub Desktop.
Example ODB Cluster to Shard Code Change
/*
*
* * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
* *
* * For more information: http://www.orientechnologies.com
*
*/
package com.orientechnologies.orient.core.metadata.schema;
import com.orientechnologies.common.exception.OException;
import com.orientechnologies.common.listener.OProgressListener;
import com.orientechnologies.common.log.OLogManager;
import com.orientechnologies.common.util.OArrays;
import com.orientechnologies.common.util.OCommonConst;
import com.orientechnologies.orient.core.annotation.OBeforeSerialization;
import com.orientechnologies.orient.core.command.OCommandResultListener;
import com.orientechnologies.orient.core.db.ODatabaseDocumentInternal;
import com.orientechnologies.orient.core.db.ODatabaseInternal;
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.db.OScenarioThreadLocal;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.db.record.ORecordElement;
import com.orientechnologies.orient.core.exception.ODatabaseException;
import com.orientechnologies.orient.core.exception.OSchemaException;
import com.orientechnologies.orient.core.exception.OSecurityAccessException;
import com.orientechnologies.orient.core.exception.OSecurityException;
import com.orientechnologies.orient.core.id.ORecordId;
import com.orientechnologies.orient.core.index.*;
import com.orientechnologies.orient.core.metadata.schema.shardselection.OShardSelectionStrategy;
import com.orientechnologies.orient.core.metadata.security.ORole;
import com.orientechnologies.orient.core.metadata.security.ORule;
import com.orientechnologies.orient.core.metadata.security.OSecurityShared;
import com.orientechnologies.orient.core.metadata.security.OSecurityUser;
import com.orientechnologies.orient.core.record.ORecord;
import com.orientechnologies.orient.core.record.ORecordInternal;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.serialization.serializer.record.ORecordSerializerFactory;
import com.orientechnologies.orient.core.serialization.serializer.record.string.ORecordSerializerSchemaAware2CSV;
import com.orientechnologies.orient.core.sharding.auto.OAutoShardingShardSelectionStrategy;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.orientechnologies.orient.core.sql.query.OSQLAsynchQuery;
import com.orientechnologies.orient.core.storage.*;
import com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage;
import com.orientechnologies.orient.core.type.ODocumentWrapper;
import com.orientechnologies.orient.core.type.ODocumentWrapperNoClass;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.Callable;
/**
* Schema Class implementation.
*
* @author Luca Garulli (l.garulli--at--orientechnologies.com)
*/
@SuppressWarnings("unchecked") public class OClassImpl extends ODocumentWrapperNoClass implements OClass {
private static final long serialVersionUID = 1L;
private static final int NOT_EXISTENT_SHARD_ID = -1;
final OSchemaShared owner;
private final Map<String, OProperty> properties = new HashMap<String, OProperty>();
private int defaultShardId = NOT_EXISTENT_SHARD_ID;
private String name;
private String description;
private int[] shardIds;
private List<OClassImpl> superClasses = new ArrayList<OClassImpl>();
private int[] polymorphicShardIds;
private List<OClass> subclasses;
private float overSize = 0f;
private String shortName;
private boolean strictMode = false; // @SINCE v1.0rc8
private boolean abstractClass = false; // @SINCE v1.2.0
private Map<String, String> customFields;
private volatile OShardSelectionStrategy shardSelection; // @SINCE 1.7
private volatile int hashCode;
private static Set<String> reserved = new HashSet<String>();
static {
// reserved.add("select");
reserved.add("traverse");
reserved.add("insert");
reserved.add("update");
reserved.add("delete");
reserved.add("from");
reserved.add("where");
reserved.add("skip");
reserved.add("limit");
reserved.add("timeout");
}
/**
* Constructor used in unmarshalling.
*/
protected OClassImpl(final OSchemaShared iOwner, final String iName) {
this(iOwner, new ODocument().setTrackingChanges(false), iName);
}
protected OClassImpl(final OSchemaShared iOwner, final String iName, final int[] iShardIds) {
this(iOwner, iName);
setShardIds(iShardIds);
defaultShardId = iShardIds[0];
if (defaultShardId == NOT_EXISTENT_SHARD_ID)
abstractClass = true;
if (abstractClass)
setPolymorphicShardIds(OCommonConst.EMPTY_INT_ARRAY);
else
setPolymorphicShardIds(iShardIds);
shardSelection = owner.getShardSelectionFactory().newInstanceOfDefaultClass();
}
/**
* Constructor used in unmarshalling.
*/
protected OClassImpl(final OSchemaShared iOwner, final ODocument iDocument, final String iName) {
name = iName;
document = iDocument;
owner = iOwner;
}
public static int[] readableShards(final ODatabaseDocument iDatabase, final int[] iShardIds) {
List<Integer> listOfReadableIds = new ArrayList<Integer>();
boolean all = true;
for (int shardId : iShardIds) {
try {
final String shardName = iDatabase.getShardNameById(shardId);
iDatabase.checkSecurity(ORule.ResourceGeneric.SHARD, ORole.PERMISSION_READ, shardName);
listOfReadableIds.add(shardId);
} catch (OSecurityAccessException securityException) {
all = false;
// if the shard is inaccessible it's simply not processed in the list.add
}
}
if (all)
// JUST RETURN INPUT ARRAY (FASTER)
return iShardIds;
final int[] readableShardIds = new int[listOfReadableIds.size()];
int index = 0;
for (int shardId : listOfReadableIds) {
readableShardIds[index++] = shardId;
}
return readableShardIds;
}
@Override public OShardSelectionStrategy getShardSelection() {
acquireSchemaReadLock();
try {
return shardSelection;
} finally {
releaseSchemaReadLock();
}
}
@Override public OClass setShardSelection(final OShardSelectionStrategy shardSelection) {
return setShardSelection(shardSelection.getName());
}
@Override public OClass setShardSelection(final String value) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` shardselection '%s'", name, value);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("alter class `%s` shardselection '%s'", name, value);
OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
setShardSelectionInternal(value);
} else
setShardSelectionInternal(value);
return this;
} finally {
releaseSchemaWriteLock();
}
}
@Override public <RET extends ODocumentWrapper> RET reload() {
return (RET) owner.reload();
}
public String getCustom(final String iName) {
acquireSchemaReadLock();
try {
if (customFields == null)
return null;
return customFields.get(iName);
} finally {
releaseSchemaReadLock();
}
}
public OClassImpl setCustom(final String name, final String value) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` custom %s=%s", getName(), name, value);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("alter class `%s` custom %s=%s", getName(), name, value);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
setCustomInternal(name, value);
} else
setCustomInternal(name, value);
return this;
} finally {
releaseSchemaWriteLock();
}
}
public Map<String, String> getCustomInternal() {
acquireSchemaReadLock();
try {
if (customFields != null)
return Collections.unmodifiableMap(customFields);
return null;
} finally {
releaseSchemaReadLock();
}
}
public void removeCustom(final String name) {
setCustom(name, null);
}
public void clearCustom() {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` custom clear", getName());
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("alter class `%s` custom clear", getName());
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
clearCustomInternal();
} else
clearCustomInternal();
} finally {
releaseSchemaWriteLock();
}
}
public Set<String> getCustomKeys() {
acquireSchemaReadLock();
try {
if (customFields != null)
return Collections.unmodifiableSet(customFields.keySet());
return new HashSet<String>();
} finally {
releaseSchemaReadLock();
}
}
@Override public boolean hasShardId(final int shardId) {
return Arrays.binarySearch(shardIds, shardId) >= 0;
}
@Override public boolean hasPolymorphicShardId(final int shardId) {
return Arrays.binarySearch(polymorphicShardIds, shardId) >= 0;
}
@Override
@Deprecated
public OClass getSuperClass() {
acquireSchemaReadLock();
try {
return superClasses.isEmpty() ? null : superClasses.get(0);
} finally {
releaseSchemaReadLock();
}
}
@Override
@Deprecated
public OClass setSuperClass(OClass iSuperClass) {
setSuperClasses(iSuperClass != null ? Arrays.asList(iSuperClass) : Collections.EMPTY_LIST);
return this;
}
public String getName() {
acquireSchemaReadLock();
try {
return name;
} finally {
releaseSchemaReadLock();
}
}
@Override public List<OClass> getSuperClasses() {
acquireSchemaReadLock();
try {
return Collections.unmodifiableList((List<? extends OClass>) superClasses);
} finally {
releaseSchemaReadLock();
}
}
@Override public boolean hasSuperClasses() {
acquireSchemaReadLock();
try {
return !superClasses.isEmpty();
} finally {
releaseSchemaReadLock();
}
}
@Override public List<String> getSuperClassesNames() {
acquireSchemaReadLock();
try {
List<String> superClassesNames = new ArrayList<String>(superClasses.size());
for (OClassImpl superClass : superClasses) {
superClassesNames.add(superClass.getName());
}
return superClassesNames;
} finally {
releaseSchemaReadLock();
}
}
public OClass setSuperClassesByNames(List<String> classNames) {
if (classNames == null)
classNames = Collections.EMPTY_LIST;
final List<OClass> classes = new ArrayList<OClass>(classNames.size());
final OSchema schema = getDatabase().getMetadata().getSchema();
for (String className : classNames) {
classes.add(schema.getClass(decodeClassName(className)));
}
return setSuperClasses(classes);
}
@Override public OClass setSuperClasses(final List<? extends OClass> classes) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
if (classes != null) {
List<OClass> toCheck = new ArrayList<OClass>(classes);
toCheck.add(this);
checkParametersConflict(toCheck);
}
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
final StringBuilder sb = new StringBuilder();
if (classes != null && classes.size() > 0) {
for (OClass superClass : classes) {
sb.append('`').append(superClass.getName()).append("`,");
}
sb.deleteCharAt(sb.length() - 1);
} else
sb.append("null");
final String cmd = String.format("alter class `%s` superclasses %s", name, sb);
if (storage instanceof OStorageProxy) {
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
setSuperClassesInternal(classes);
} else
setSuperClassesInternal(classes);
} finally {
releaseSchemaWriteLock();
}
return this;
}
void setSuperClassesInternal(final List<? extends OClass> classes) {
acquireSchemaWriteLock();
try {
List<OClassImpl> newSuperClasses = new ArrayList<OClassImpl>();
OClassImpl cls;
for (OClass superClass : classes) {
if (superClass instanceof OClassAbstractDelegate)
cls = (OClassImpl) ((OClassAbstractDelegate) superClass).delegate;
else
cls = (OClassImpl) superClass;
if (newSuperClasses.contains(cls)) {
throw new OSchemaException("Duplicated superclass '" + cls.getName() + "'");
}
newSuperClasses.add(cls);
}
List<OClassImpl> toAddList = new ArrayList<OClassImpl>(newSuperClasses);
toAddList.removeAll(superClasses);
List<OClassImpl> toRemoveList = new ArrayList<OClassImpl>(superClasses);
toRemoveList.removeAll(newSuperClasses);
for (OClassImpl toRemove : toRemoveList) {
toRemove.removeBaseClassInternal(this);
}
for (OClassImpl addTo : toAddList) {
addTo.addBaseClass(this);
}
superClasses.clear();
superClasses.addAll(newSuperClasses);
} finally {
releaseSchemaWriteLock();
}
}
@Override public OClass addSuperClass(final OClass superClass) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
checkParametersConflict(superClass);
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String
.format("alter class `%s` superclass +`%s`", name, superClass != null ? superClass.getName() : null);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String
.format("alter class `%s` superclass +`%s`", name, superClass != null ? superClass.getName() : null);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
addSuperClassInternal(superClass);
} else
addSuperClassInternal(superClass);
} finally {
releaseSchemaWriteLock();
}
return this;
}
void addSuperClassInternal(final OClass superClass) {
acquireSchemaWriteLock();
try {
final OClassImpl cls;
if (superClass instanceof OClassAbstractDelegate)
cls = (OClassImpl) ((OClassAbstractDelegate) superClass).delegate;
else
cls = (OClassImpl) superClass;
if (cls != null) {
// CHECK THE USER HAS UPDATE PRIVILEGE AGAINST EXTENDING CLASS
final OSecurityUser user = getDatabase().getUser();
if (user != null)
user.allow(ORule.ResourceGeneric.CLASS, cls.getName(), ORole.PERMISSION_UPDATE);
if (superClasses.contains(superClass)) {
throw new OSchemaException(
"Class: '" + this.getName() + "' already has the class '" + superClass.getName() + "' as superclass");
}
cls.addBaseClass(this);
superClasses.add(cls);
}
} finally {
releaseSchemaWriteLock();
}
}
@Override public OClass removeSuperClass(OClass superClass) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String
.format("alter class `%s` superclass -`%s`", name, superClass != null ? superClass.getName() : null);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String
.format("alter class `%s` superclass -`%s`", name, superClass != null ? superClass.getName() : null);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
removeSuperClassInternal(superClass);
} else
removeSuperClassInternal(superClass);
} finally {
releaseSchemaWriteLock();
}
return this;
}
void removeSuperClassInternal(final OClass superClass) {
acquireSchemaWriteLock();
try {
final OClassImpl cls;
if (superClass instanceof OClassAbstractDelegate)
cls = (OClassImpl) ((OClassAbstractDelegate) superClass).delegate;
else
cls = (OClassImpl) superClass;
if (superClasses.contains(cls)) {
if (cls != null)
cls.removeBaseClassInternal(this);
superClasses.remove(superClass);
}
} finally {
releaseSchemaWriteLock();
}
}
public OClass setName(final String name) {
if (getName().equals(name))
return this;
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
final Character wrongCharacter = OSchemaShared.checkClassNameIfValid(name);
OClass oClass = getDatabase().getMetadata().getSchema().getClass(name);
if (oClass != null) {
String error = String.format("Cannot rename class %s to %s. A Class with name %s exists", this.name, name, name);
throw new OSchemaException(error);
}
if (wrongCharacter != null)
throw new OSchemaException(
"Invalid class name found. Character '" + wrongCharacter + "' cannot be used in class name '" + name + "'");
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` name `%s`", this.name, name);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("alter class `%s` name `%s`", this.name, name);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
setNameInternal(name);
} else
setNameInternal(name);
} finally {
releaseSchemaWriteLock();
}
return this;
}
public long getSize() {
acquireSchemaReadLock();
try {
long size = 0;
for (int shardId : shardIds)
size += getDatabase().getShardRecordSizeById(shardId);
return size;
} finally {
releaseSchemaReadLock();
}
}
public String getShortName() {
acquireSchemaReadLock();
try {
return shortName;
} finally {
releaseSchemaReadLock();
}
}
public OClass setShortName(String shortName) {
if (shortName != null) {
shortName = shortName.trim();
if (shortName.isEmpty())
shortName = null;
}
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` shortname %s", name, shortName);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("alter class `%s` shortname %s", name, shortName);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
setShortNameInternal(shortName);
} else
setShortNameInternal(shortName);
} finally {
releaseSchemaWriteLock();
}
return this;
}
public String getDescription() {
acquireSchemaReadLock();
try {
return description;
} finally {
releaseSchemaReadLock();
}
}
public OClass setDescription(String iDescription) {
if (iDescription != null) {
iDescription = iDescription.trim();
if (iDescription.isEmpty())
iDescription = null;
}
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` description %s", name, shortName);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("alter class `%s` description %s", name, shortName);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
setDescriptionInternal(iDescription);
} else
setDescriptionInternal(iDescription);
} finally {
releaseSchemaWriteLock();
}
return this;
}
public String getStreamableName() {
acquireSchemaReadLock();
try {
return shortName != null ? shortName : name;
} finally {
releaseSchemaReadLock();
}
}
public Collection<OProperty> declaredProperties() {
acquireSchemaReadLock();
try {
return Collections.unmodifiableCollection(properties.values());
} finally {
releaseSchemaReadLock();
}
}
public Map<String, OProperty> propertiesMap() {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_READ);
acquireSchemaReadLock();
try {
final Map<String, OProperty> props = new HashMap<String, OProperty>(20);
propertiesMap(props, true);
return props;
} finally {
releaseSchemaReadLock();
}
}
private void propertiesMap(Map<String, OProperty> propertiesMap, boolean keepCase) {
for (OProperty p : properties.values()) {
String propName = p.getName();
if (!keepCase)
propName = propName.toLowerCase();
if (!propertiesMap.containsKey(propName))
propertiesMap.put(propName, p);
}
for (OClassImpl superClass : superClasses) {
superClass.propertiesMap(propertiesMap, keepCase);
}
}
public Collection<OProperty> properties() {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_READ);
acquireSchemaReadLock();
try {
final Collection<OProperty> props = new ArrayList<OProperty>();
properties(props);
return props;
} finally {
releaseSchemaReadLock();
}
}
private void properties(Collection<OProperty> properties) {
properties.addAll(this.properties.values());
for (OClassImpl superClass : superClasses) {
superClass.properties(properties);
}
}
public void getIndexedProperties(Collection<OProperty> indexedProperties) {
for (OProperty p : properties.values())
if (areIndexed(p.getName()))
indexedProperties.add(p);
for (OClassImpl superClass : superClasses) {
superClass.getIndexedProperties(indexedProperties);
}
}
@Override public Collection<OProperty> getIndexedProperties() {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_READ);
acquireSchemaReadLock();
try {
Collection<OProperty> indexedProps = new HashSet<OProperty>();
getIndexedProperties(indexedProps);
return indexedProps;
} finally {
releaseSchemaReadLock();
}
}
public OProperty getProperty(String propertyName) {
acquireSchemaReadLock();
try {
propertyName = propertyName.toLowerCase();
OProperty p = properties.get(propertyName);
if (p != null)
return p;
for (int i = 0; i < superClasses.size() && p == null; i++) {
p = superClasses.get(i).getProperty(propertyName);
}
return p;
} finally {
releaseSchemaReadLock();
}
}
public OProperty createProperty(final String iPropertyName, final OType iType) {
return addProperty(iPropertyName, iType, null, null, false);
}
public OProperty createProperty(final String iPropertyName, final OType iType, final OClass iLinkedClass) {
if (iLinkedClass == null)
throw new OSchemaException("Missing linked class");
return addProperty(iPropertyName, iType, null, iLinkedClass, false);
}
public OProperty createProperty(final String iPropertyName, final OType iType, final OClass iLinkedClass, final boolean unsafe) {
if (iLinkedClass == null)
throw new OSchemaException("Missing linked class");
return addProperty(iPropertyName, iType, null, iLinkedClass, unsafe);
}
public OProperty createProperty(final String iPropertyName, final OType iType, final OType iLinkedType) {
return addProperty(iPropertyName, iType, iLinkedType, null, false);
}
public OProperty createProperty(final String iPropertyName, final OType iType, final OType iLinkedType, final boolean unsafe) {
return addProperty(iPropertyName, iType, iLinkedType, null, unsafe);
}
@Override public boolean existsProperty(String propertyName) {
acquireSchemaReadLock();
try {
propertyName = propertyName.toLowerCase();
boolean result = properties.containsKey(propertyName);
if (result)
return true;
for (OClassImpl superClass : superClasses) {
result = superClass.existsProperty(propertyName);
if (result)
return true;
}
return false;
} finally {
releaseSchemaReadLock();
}
}
public void dropProperty(final String propertyName) {
if (getDatabase().getTransaction().isActive())
throw new IllegalStateException("Cannot drop a property inside a transaction");
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_DELETE);
final String lowerName = propertyName.toLowerCase();
acquireSchemaWriteLock();
try {
if (!properties.containsKey(lowerName))
throw new OSchemaException("Property '" + propertyName + "' not found in class " + name + "'");
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
database.command(new OCommandSQL("drop property " + name + '.' + propertyName)).execute();
} else if (isDistributedCommand()) {
final OCommandSQL commandSQL = new OCommandSQL("drop property " + name + '.' + propertyName);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
OScenarioThreadLocal.executeAsDistributed(new Callable<OProperty>() {
@Override public OProperty call() throws Exception {
dropPropertyInternal(propertyName);
return null;
}
});
} else
OScenarioThreadLocal.executeAsDistributed(new Callable<OProperty>() {
@Override public OProperty call() throws Exception {
dropPropertyInternal(propertyName);
return null;
}
});
} finally {
releaseSchemaWriteLock();
}
}
@Override public void fromStream() {
subclasses = null;
superClasses.clear();
name = document.field("name");
if (document.containsField("shortName"))
shortName = document.field("shortName");
else
shortName = null;
if (document.containsField("description"))
description = document.field("description");
else
description = null;
defaultShardId = document.field("defaultShardId");
if (document.containsField("strictMode"))
strictMode = document.field("strictMode");
else
strictMode = false;
if (document.containsField("abstract"))
abstractClass = document.field("abstract");
else
abstractClass = false;
if (document.field("overSize") != null)
overSize = document.field("overSize");
else
overSize = 0f;
final Object cc = document.field("shardIds");
if (cc instanceof Collection<?>) {
final Collection<Integer> coll = document.field("shardIds");
shardIds = new int[coll.size()];
int i = 0;
for (final Integer item : coll)
shardIds[i++] = item;
} else
shardIds = (int[]) cc;
Arrays.sort(shardIds);
if (shardIds.length == 1 && shardIds[0] == -1)
setPolymorphicShardIds(OCommonConst.EMPTY_INT_ARRAY);
else
setPolymorphicShardIds(shardIds);
// READ PROPERTIES
OPropertyImpl prop;
final Map<String, OProperty> newProperties = new HashMap<String, OProperty>();
final Collection<ODocument> storedProperties = document.field("properties");
if (storedProperties != null)
for (OIdentifiable id : storedProperties) {
ODocument p = id.getRecord();
prop = new OPropertyImpl(this, p);
prop.fromStream();
if (properties.containsKey(prop.getName())) {
prop = (OPropertyImpl) properties.get(prop.getName().toLowerCase());
prop.fromStream(p);
}
newProperties.put(prop.getName().toLowerCase(), prop);
}
properties.clear();
properties.putAll(newProperties);
customFields = document.field("customFields", OType.EMBEDDEDMAP);
shardSelection = owner.getShardSelectionFactory().getStrategy((String) document.field("shardSelection"));
}
@Override @OBeforeSerialization public ODocument toStream() {
document.setInternalStatus(ORecordElement.STATUS.UNMARSHALLING);
try {
document.field("name", name);
document.field("shortName", shortName);
document.field("description", description);
document.field("defaultShardId", defaultShardId);
document.field("shardIds", shardIds);
document.field("shardSelection", shardSelection.getName());
document.field("overSize", overSize);
document.field("strictMode", strictMode);
document.field("abstract", abstractClass);
final Set<ODocument> props = new LinkedHashSet<ODocument>();
for (final OProperty p : properties.values()) {
props.add(((OPropertyImpl) p).toStream());
}
document.field("properties", props, OType.EMBEDDEDSET);
if (superClasses.isEmpty()) {
// Single super class is deprecated!
document.field("superClass", null, OType.STRING);
document.field("superClasses", null, OType.EMBEDDEDLIST);
} else {
// Single super class is deprecated!
document.field("superClass", superClasses.get(0).getName(), OType.STRING);
List<String> superClassesNames = new ArrayList<String>();
for (OClassImpl superClass : superClasses) {
superClassesNames.add(superClass.getName());
}
document.field("superClasses", superClassesNames, OType.EMBEDDEDLIST);
}
document.field("customFields", customFields != null && customFields.size() > 0 ? customFields : null, OType.EMBEDDEDMAP);
} finally {
document.setInternalStatus(ORecordElement.STATUS.LOADED);
}
return document;
}
@Override public int getShardForNewInstance(final ODocument doc) {
acquireSchemaReadLock();
try {
return shardSelection.getShard(this, doc);
} finally {
releaseSchemaReadLock();
}
}
public int getDefaultShardId() {
acquireSchemaReadLock();
try {
return defaultShardId;
} finally {
releaseSchemaReadLock();
}
}
public void setDefaultShardId(final int defaultShardId) {
acquireSchemaWriteLock();
try {
checkEmbedded();
this.defaultShardId = defaultShardId;
} finally {
releaseSchemaWriteLock();
}
}
public int[] getShardIds() {
acquireSchemaReadLock();
try {
return shardIds;
} finally {
releaseSchemaReadLock();
}
}
public int[] getPolymorphicShardIds() {
acquireSchemaReadLock();
try {
return Arrays.copyOf(polymorphicShardIds, polymorphicShardIds.length);
} finally {
releaseSchemaReadLock();
}
}
private void setPolymorphicShardIds(final int[] iShardIds) {
Set<Integer> set = new TreeSet<Integer>();
for (int iShardId : iShardIds) {
set.add(iShardId);
}
polymorphicShardIds = new int[set.size()];
int i = 0;
for (Integer shardId : set) {
polymorphicShardIds[i] = shardId;
i++;
}
}
public void renameProperty(final String iOldName, final String iNewName) {
final OProperty p = properties.remove(iOldName.toLowerCase());
if (p != null)
properties.put(iNewName.toLowerCase(), p);
}
public OClass addShardId(final int shardId) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
if (isAbstract()) {
throw new OSchemaException("Impossible to associate a shard to an abstract class class");
}
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` addshard %d", name, shardId);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("alter class `%s` addshard %d", name, shardId);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
addShardIdInternal(shardId);
} else
addShardIdInternal(shardId);
} finally {
releaseSchemaWriteLock();
}
return this;
}
public static OClass addShards(final OClass cls, final int iShards) {
final String shardBase = cls.getName().toLowerCase() + "_";
for (int i = 1; i < iShards; ++i) {
cls.addShard(shardBase + i);
}
return cls;
}
@Override public OClass addShard(final String shardNameOrId) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
if (isAbstract()) {
throw new OSchemaException("Impossible to associate a shard to an abstract class class");
}
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` addshard `%s`", name, shardNameOrId);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final int shardId = owner.createShardIfNeeded(shardNameOrId);
addShardIdInternal(shardId);
final String cmd = String.format("alter class `%s` addshard `%s`", name, shardNameOrId);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
} else {
final int shardId = owner.createShardIfNeeded(shardNameOrId);
addShardIdInternal(shardId);
}
} finally {
releaseSchemaWriteLock();
}
return this;
}
/**
* {@inheritDoc}
*/
@Override public OClass truncateShard(String shardName) {
getDatabase().checkSecurity(ORule.ResourceGeneric.CLASS, ORole.PERMISSION_DELETE, name);
acquireSchemaReadLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("truncate shard %s", shardName);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("truncate shard %s", shardName);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
truncateShardInternal(shardName, storage);
} else
truncateShardInternal(shardName, storage);
} finally {
releaseSchemaReadLock();
}
return this;
}
private void truncateShardInternal(final String shardName, final OStorage storage) {
final OShard shard = storage.getShardByName(shardName);
if (shard == null) {
throw new ODatabaseException("Shard with name " + shardName + " does not exist");
}
try {
shard.truncate();
} catch (IOException e) {
throw OException.wrapException(new ODatabaseException("Error during truncate of shard " + shardName), e);
}
for (OIndex index : getIndexes()) {
index.rebuild();
}
}
public OClass removeShardId(final int shardId) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
if (shardIds.length == 1 && shardId == shardIds[0])
throw new ODatabaseException(" Impossible to remove the last shard of class '" + getName() + "' drop the class instead");
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` removeshard %d", name, shardId);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("alter class `%s` removeshard %d", name, shardId);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
removeShardIdInternal(shardId);
} else
removeShardIdInternal(shardId);
} finally {
releaseSchemaWriteLock();
}
return this;
}
public Collection<OClass> getSubclasses() {
acquireSchemaReadLock();
try {
if (subclasses == null || subclasses.size() == 0)
return Collections.emptyList();
return Collections.unmodifiableCollection(subclasses);
} finally {
releaseSchemaReadLock();
}
}
public Collection<OClass> getAllSubclasses() {
acquireSchemaReadLock();
try {
final Set<OClass> set = new HashSet<OClass>();
if (subclasses != null) {
set.addAll(subclasses);
for (OClass c : subclasses)
set.addAll(c.getAllSubclasses());
}
return set;
} finally {
releaseSchemaReadLock();
}
}
@Deprecated
public Collection<OClass> getBaseClasses() {
return getSubclasses();
}
@Deprecated
public Collection<OClass> getAllBaseClasses() {
return getAllSubclasses();
}
@Override
public Collection<OClass> getAllSuperClasses() {
Set<OClass> ret = new HashSet<OClass>();
getAllSuperClasses(ret);
return ret;
}
private void getAllSuperClasses(Set<OClass> set) {
set.addAll(superClasses);
for (OClassImpl superClass : superClasses) {
superClass.getAllSuperClasses(set);
}
}
OClass removeBaseClassInternal(final OClass baseClass) {
acquireSchemaWriteLock();
try {
checkEmbedded();
if (subclasses == null)
return this;
if (subclasses.remove(baseClass))
removePolymorphicShardIds((OClassImpl) baseClass);
return this;
} finally {
releaseSchemaWriteLock();
}
}
public float getOverSize() {
acquireSchemaReadLock();
try {
if (overSize > 0)
// CUSTOM OVERSIZE SET
return overSize;
// NO OVERSIZE by default
float maxOverSize = 0;
float thisOverSize;
for (OClassImpl superClass : superClasses) {
thisOverSize = superClass.getOverSize();
if (thisOverSize > maxOverSize)
maxOverSize = thisOverSize;
}
return maxOverSize;
} finally {
releaseSchemaReadLock();
}
}
public OClass setOverSize(final float overSize) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
// FORMAT FLOAT LOCALE AGNOSTIC
final String cmd = String.format("alter class `%s` oversize %s", name, new Float(overSize).toString());
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
// FORMAT FLOAT LOCALE AGNOSTIC
final String cmd = String.format("alter class `%s` oversize %s", name, new Float(overSize).toString());
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
setOverSizeInternal(overSize);
} else
setOverSizeInternal(overSize);
} finally {
releaseSchemaWriteLock();
}
return this;
}
@Override public float getClassOverSize() {
acquireSchemaReadLock();
try {
return overSize;
} finally {
releaseSchemaReadLock();
}
}
public boolean isAbstract() {
acquireSchemaReadLock();
try {
return abstractClass;
} finally {
releaseSchemaReadLock();
}
}
public OClass setAbstract(boolean isAbstract) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` abstract %s", name, isAbstract);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("alter class `%s` abstract %s", name, isAbstract);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
setAbstractInternal(isAbstract);
} else
setAbstractInternal(isAbstract);
} finally {
releaseSchemaWriteLock();
}
return this;
}
public boolean isStrictMode() {
acquireSchemaReadLock();
try {
return strictMode;
} finally {
releaseSchemaReadLock();
}
}
public OClass setStrictMode(final boolean isStrict) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` strictmode %s", name, isStrict);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("alter class `%s` strictmode %s", name, isStrict);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
setStrictModeInternal(isStrict);
} else
setStrictModeInternal(isStrict);
} finally {
releaseSchemaWriteLock();
}
return this;
}
@Override public String toString() {
acquireSchemaReadLock();
try {
return name;
} finally {
releaseSchemaReadLock();
}
}
@Override public boolean equals(Object obj) {
acquireSchemaReadLock();
try {
if (this == obj)
return true;
if (obj == null)
return false;
if (!OClass.class.isAssignableFrom(obj.getClass()))
return false;
final OClass other = (OClass) obj;
if (name == null) {
if (other.getName() != null)
return false;
} else if (!name.equals(other.getName()))
return false;
return true;
} finally {
releaseSchemaReadLock();
}
}
@Override public int hashCode() {
int sh = hashCode;
if (sh != 0)
return sh;
acquireSchemaReadLock();
try {
sh = hashCode;
if (sh != 0)
return sh;
calculateHashCode();
return hashCode;
} finally {
releaseSchemaReadLock();
}
}
public int compareTo(final OClass o) {
acquireSchemaReadLock();
try {
return name.compareTo(o.getName());
} finally {
releaseSchemaReadLock();
}
}
public long count() {
return count(true);
}
public long count(final boolean isPolymorphic) {
acquireSchemaReadLock();
try {
if (isPolymorphic)
return getDatabase().countShardElements(readableShards(getDatabase(), polymorphicShardIds));
return getDatabase().countShardElements(readableShards(getDatabase(), shardIds));
} finally {
releaseSchemaReadLock();
}
}
/**
* Truncates all the shards the class uses.
*
* @throws IOException
*/
public void truncate() throws IOException {
getDatabase().checkSecurity(ORule.ResourceGeneric.CLASS, ORole.PERMISSION_UPDATE);
if (isSubClassOf(OSecurityShared.RESTRICTED_CLASSNAME)) {
throw new OSecurityException(
"Class '" + getName() + "' cannot be truncated because has record level security enabled (extends '"
+ OSecurityShared.RESTRICTED_CLASSNAME + "')");
}
final OStorage storage = getDatabase().getStorage();
acquireSchemaReadLock();
try {
for (int id : shardIds)
storage.getShardById(id).truncate();
for (OIndex<?> index : getClassIndexes())
index.clear();
Set<OIndex<?>> superclassIndexes = new HashSet<OIndex<?>>();
superclassIndexes.addAll(getIndexes());
superclassIndexes.removeAll(getClassIndexes());
for (OIndex index : superclassIndexes) {
index.rebuild();
}
} finally {
releaseSchemaReadLock();
}
}
/**
* Check if the current instance extends specified schema class.
*
* @param iClassName of class that should be checked
* @return Returns true if the current instance extends the passed schema class (iClass)
* @see #isSuperClassOf(OClass)
*/
public boolean isSubClassOf(final String iClassName) {
acquireSchemaReadLock();
try {
if (iClassName == null)
return false;
if (iClassName.equalsIgnoreCase(getName()) || iClassName.equalsIgnoreCase(getShortName()))
return true;
for (OClassImpl superClass : superClasses) {
if (superClass.isSubClassOf(iClassName))
return true;
}
return false;
} finally {
releaseSchemaReadLock();
}
}
/**
* Check if the current instance extends specified schema class.
*
* @param clazz to check
* @return true if the current instance extends the passed schema class (iClass)
* @see #isSuperClassOf(OClass)
*/
public boolean isSubClassOf(final OClass clazz) {
acquireSchemaReadLock();
try {
if (clazz == null)
return false;
if (equals(clazz))
return true;
for (OClassImpl superClass : superClasses) {
if (superClass.isSubClassOf(clazz))
return true;
}
return false;
} finally {
releaseSchemaReadLock();
}
}
/**
* Returns true if the passed schema class (iClass) extends the current instance.
*
* @param clazz to check
* @return Returns true if the passed schema class extends the current instance
* @see #isSubClassOf(OClass)
*/
public boolean isSuperClassOf(final OClass clazz) {
return clazz != null && clazz.isSubClassOf(this);
}
public Object get(final ATTRIBUTES iAttribute) {
if (iAttribute == null)
throw new IllegalArgumentException("attribute is null");
switch (iAttribute) {
case NAME:
return getName();
case SHORTNAME:
return getShortName();
case SUPERCLASS:
return getSuperClass();
case SUPERCLASSES:
return getSuperClasses();
case OVERSIZE:
return getOverSize();
case STRICTMODE:
return isStrictMode();
case ABSTRACT:
return isAbstract();
case SHARDSELECTION:
return getShardSelection();
case CUSTOM:
return getCustomInternal();
case DESCRIPTION:
return getDescription();
}
throw new IllegalArgumentException("Cannot find attribute '" + iAttribute + "'");
}
public OClass set(final ATTRIBUTES attribute, final Object iValue) {
if (attribute == null)
throw new IllegalArgumentException("attribute is null");
final String stringValue = iValue != null ? iValue.toString() : null;
final boolean isNull = stringValue == null || stringValue.equalsIgnoreCase("NULL");
switch (attribute) {
case NAME:
setName(decodeClassName(stringValue));
break;
case SHORTNAME:
setShortName(decodeClassName(stringValue));
break;
case SUPERCLASS:
if (stringValue == null)
throw new IllegalArgumentException("Superclass is null");
if (stringValue.startsWith("+")) {
addSuperClass(getDatabase().getMetadata().getSchema().getClass(decodeClassName(stringValue.substring(1))));
} else if (stringValue.startsWith("-")) {
removeSuperClass(getDatabase().getMetadata().getSchema().getClass(decodeClassName(stringValue.substring(1))));
} else {
setSuperClass(getDatabase().getMetadata().getSchema().getClass(decodeClassName(stringValue)));
}
break;
case SUPERCLASSES:
setSuperClassesByNames(stringValue != null ? Arrays.asList(stringValue.split(",\\s*")) : null);
break;
case OVERSIZE:
setOverSize(Float.parseFloat(stringValue));
break;
case STRICTMODE:
setStrictMode(Boolean.parseBoolean(stringValue));
break;
case ABSTRACT:
setAbstract(Boolean.parseBoolean(stringValue));
break;
case ADDSHARD: {
addShard(stringValue);
break;
}
case REMOVESHARD:
int clId = owner.getShardId(stringValue);
if (clId == NOT_EXISTENT_SHARD_ID)
throw new IllegalArgumentException("Shard id '" + stringValue + "' cannot be removed");
removeShardId(clId);
break;
case SHARDSELECTION:
setShardSelection(stringValue);
break;
case CUSTOM:
int indx = stringValue != null ? stringValue.indexOf('=') : -1;
if (indx < 0) {
if (isNull || "clear".equalsIgnoreCase(stringValue)) {
clearCustom();
} else
throw new IllegalArgumentException("Syntax error: expected <name> = <value> or clear, instead found: " + iValue);
} else {
String customName = stringValue.substring(0, indx).trim();
String customValue = stringValue.substring(indx + 1).trim();
if (isQuoted(customValue)) {
customValue = removeQuotes(customValue);
}
if (customValue.isEmpty())
removeCustom(customName);
else
setCustom(customName, customValue);
}
break;
case DESCRIPTION:
setDescription(stringValue);
break;
case ENCRYPTION:
setEncryption(stringValue);
break;
}
return this;
}
private String removeQuotes(String s) {
s = s.trim();
return s.substring(1, s.length() - 1);
}
private boolean isQuoted(String s) {
s = s.trim();
if (s.startsWith("\"") && s.endsWith("\""))
return true;
if (s.startsWith("'") && s.endsWith("'"))
return true;
if (s.startsWith("`") && s.endsWith("`"))
return true;
return false;
}
public OClassImpl setEncryption(final String iValue) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
final String cmd = String.format("alter class `%s` encryption %s", name, iValue);
database.command(new OCommandSQL(cmd)).execute();
} else if (isDistributedCommand()) {
final String cmd = String.format("alter class `%s` encryption %s", name, iValue);
final OCommandSQL commandSQL = new OCommandSQL(cmd);
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
setEncryptionInternal(iValue);
} else
setEncryptionInternal(iValue);
} finally {
releaseSchemaWriteLock();
}
return this;
}
protected void setEncryptionInternal(final String iValue) {
for (int cl : getShardIds()) {
final OShard c = getDatabase().getStorage().getShardById(cl);
if (c != null)
try {
c.set(OShard.ATTRIBUTES.ENCRYPTION, iValue);
} catch (IOException e) {
}
}
}
public OPropertyImpl addPropertyInternal(final String name, final OType type, final OType linkedType, final OClass linkedClass,
final boolean unsafe) {
if (name == null || name.length() == 0)
throw new OSchemaException("Found property name null");
if (!unsafe)
checkPersistentPropertyType(getDatabase(), name, type);
final String lowerName = name.toLowerCase();
final OPropertyImpl prop;
// This check are doubled becouse used by sql commands
if (linkedType != null)
OPropertyImpl.checkLinkTypeSupport(type);
if (linkedClass != null)
OPropertyImpl.checkSupportLinkedClass(type);
acquireSchemaWriteLock();
try {
checkEmbedded();
if (properties.containsKey(lowerName))
throw new OSchemaException("Class '" + this.name + "' already has property '" + name + "'");
OGlobalProperty global = owner.findOrCreateGlobalProperty(name, type);
prop = new OPropertyImpl(this, global);
properties.put(lowerName, prop);
if (linkedType != null)
prop.setLinkedTypeInternal(linkedType);
else if (linkedClass != null)
prop.setLinkedClassInternal(linkedClass);
} finally {
releaseSchemaWriteLock();
}
if (prop != null && !unsafe)
fireDatabaseMigration(getDatabase(), name, type);
return prop;
}
public OIndex<?> createIndex(final String iName, final INDEX_TYPE iType, final String... fields) {
return createIndex(iName, iType.name(), fields);
}
public OIndex<?> createIndex(final String iName, final String iType, final String... fields) {
return createIndex(iName, iType, null, null, fields);
}
public OIndex<?> createIndex(final String iName, final INDEX_TYPE iType, final OProgressListener iProgressListener,
final String... fields) {
return createIndex(iName, iType.name(), iProgressListener, null, fields);
}
public OIndex<?> createIndex(String iName, String iType, OProgressListener iProgressListener, ODocument metadata,
String... fields) {
return createIndex(iName, iType, iProgressListener, metadata, null, fields);
}
public OIndex<?> createIndex(final String name, String type, final OProgressListener progressListener, ODocument metadata,
String algorithm, final String... fields) {
if (type == null)
throw new IllegalArgumentException("Index type is null");
type = type.toUpperCase();
if (fields.length == 0) {
throw new OIndexException("List of fields to index cannot be empty.");
}
final String localName = this.name;
final int[] localPolymorphicShardIds = polymorphicShardIds;
for (final String fieldToIndex : fields) {
final String fieldName = decodeClassName(OIndexDefinitionFactory.extractFieldName(fieldToIndex));
if (!fieldName.equals("@rid") && !existsProperty(fieldName))
throw new OIndexException(
"Index with name '" + name + "' cannot be created on class '" + localName + "' because the field '" + fieldName
+ "' is absent in class definition");
}
final OIndexDefinition indexDefinition = OIndexDefinitionFactory
.createIndexDefinition(this, Arrays.asList(fields), extractFieldTypes(fields), null, type, algorithm);
return getDatabase().getMetadata().getIndexManager()
.createIndex(name, type, indexDefinition, localPolymorphicShardIds, progressListener, metadata, algorithm);
}
public boolean areIndexed(final String... fields) {
return areIndexed(Arrays.asList(fields));
}
public boolean areIndexed(final Collection<String> fields) {
final OIndexManager indexManager = getDatabase().getMetadata().getIndexManager();
acquireSchemaReadLock();
try {
final boolean currentClassResult = indexManager.areIndexed(name, fields);
if (currentClassResult)
return true;
for (OClassImpl superClass : superClasses) {
if (superClass.areIndexed(fields))
return true;
}
return false;
} finally {
releaseSchemaReadLock();
}
}
public Set<OIndex<?>> getInvolvedIndexes(final String... fields) {
return getInvolvedIndexes(Arrays.asList(fields));
}
public Set<OIndex<?>> getInvolvedIndexes(final Collection<String> fields) {
acquireSchemaReadLock();
try {
final Set<OIndex<?>> result = new HashSet<OIndex<?>>(getClassInvolvedIndexes(fields));
for (OClassImpl superClass : superClasses) {
result.addAll(superClass.getInvolvedIndexes(fields));
}
return result;
} finally {
releaseSchemaReadLock();
}
}
public Set<OIndex<?>> getClassInvolvedIndexes(final Collection<String> fields) {
final OIndexManager indexManager = getDatabase().getMetadata().getIndexManager();
acquireSchemaReadLock();
try {
return indexManager.getClassInvolvedIndexes(name, fields);
} finally {
releaseSchemaReadLock();
}
}
public Set<OIndex<?>> getClassInvolvedIndexes(final String... fields) {
return getClassInvolvedIndexes(Arrays.asList(fields));
}
public OIndex<?> getClassIndex(final String name) {
acquireSchemaReadLock();
try {
return getDatabase().getMetadata().getIndexManager().getClassIndex(this.name, name);
} finally {
releaseSchemaReadLock();
}
}
public Set<OIndex<?>> getClassIndexes() {
acquireSchemaReadLock();
try {
final OIndexManagerProxy idxManager = getDatabase().getMetadata().getIndexManager();
if (idxManager == null)
return new HashSet<OIndex<?>>();
return idxManager.getClassIndexes(name);
} finally {
releaseSchemaReadLock();
}
}
@Override public void getClassIndexes(final Collection<OIndex<?>> indexes) {
acquireSchemaReadLock();
try {
final OIndexManagerProxy idxManager = getDatabase().getMetadata().getIndexManager();
if (idxManager == null)
return;
idxManager.getClassIndexes(name, indexes);
} finally {
releaseSchemaReadLock();
}
}
@Override public OIndex<?> getAutoShardingIndex() {
final ODatabaseDocumentInternal db = ODatabaseRecordThreadLocal.INSTANCE.getIfDefined();
return db != null ? db.getMetadata().getIndexManager().getClassAutoShardingIndex(name) : null;
}
@Override public boolean isEdgeType() {
return isSubClassOf(EDGE_CLASS_NAME);
}
@Override public boolean isVertexType() {
return isSubClassOf(VERTEX_CLASS_NAME);
}
public void onPostIndexManagement() {
final OIndex<?> autoShardingIndex = getAutoShardingIndex();
if (autoShardingIndex != null) {
if (!getDatabase().getStorage().isRemote()) {
// OVERRIDE SHARD SELECTION
acquireSchemaWriteLock();
try {
this.shardSelection = new OAutoShardingShardSelectionStrategy(this, autoShardingIndex);
} finally {
releaseSchemaWriteLock();
}
}
} else if (shardSelection instanceof OAutoShardingShardSelectionStrategy) {
// REMOVE AUTO SHARDING SHARD SELECTION
acquireSchemaWriteLock();
try {
this.shardSelection = owner.getShardSelectionFactory().newInstanceOfDefaultClass();
} finally {
releaseSchemaWriteLock();
}
}
}
@Override public void getIndexes(final Collection<OIndex<?>> indexes) {
acquireSchemaReadLock();
try {
getClassIndexes(indexes);
for (OClass superClass : superClasses) {
superClass.getIndexes(indexes);
}
} finally {
releaseSchemaReadLock();
}
}
public Set<OIndex<?>> getIndexes() {
final Set<OIndex<?>> indexes = new HashSet<OIndex<?>>();
getIndexes(indexes);
return indexes;
}
public void acquireSchemaReadLock() {
owner.acquireSchemaReadLock();
}
public void releaseSchemaReadLock() {
owner.releaseSchemaReadLock();
}
public void acquireSchemaWriteLock() {
owner.acquireSchemaWriteLock();
}
public void releaseSchemaWriteLock() {
releaseSchemaWriteLock(true);
}
public void releaseSchemaWriteLock(final boolean iSave) {
calculateHashCode();
owner.releaseSchemaWriteLock(iSave);
}
public void checkEmbedded() {
owner.checkEmbedded(getDatabase().getStorage().getUnderlying().getUnderlying());
}
public void setShardSelectionInternal(final String shardSelection) {
// AVOID TO CHECK THIS IN LOCK TO AVOID RE-GENERATION OF IMMUTABLE SCHEMAS
if (this.shardSelection.getName().equals(shardSelection))
// NO CHANGES
return;
acquireSchemaWriteLock();
try {
checkEmbedded();
this.shardSelection = owner.getShardSelectionFactory().newInstance(shardSelection);
} finally {
releaseSchemaWriteLock();
}
}
public void setShardSelectionInternal(final OShardSelectionStrategy iShardSelection) {
// AVOID TO CHECK THIS IN LOCK TO AVOID RE-GENERATION OF IMMUTABLE SCHEMAS
if (this.shardSelection.getClass().equals(iShardSelection.getClass()))
// NO CHANGES
return;
acquireSchemaWriteLock();
try {
checkEmbedded();
this.shardSelection = iShardSelection;
} finally {
releaseSchemaWriteLock();
}
}
public void fireDatabaseMigration(final ODatabaseDocument database, final String propertyName, final OType type) {
final boolean strictSQL = ((ODatabaseInternal) database).getStorage().getConfiguration().isStrictSql();
database.query(new OSQLAsynchQuery<Object>(
"select from " + getEscapedName(name, strictSQL) + " where " + getEscapedName(propertyName, strictSQL) + ".type() <> \""
+ type.name() + "\"", new OCommandResultListener() {
@Override public boolean result(Object iRecord) {
final ODocument record = ((OIdentifiable) iRecord).getRecord();
record.field(propertyName, record.field(propertyName), type);
database.save(record);
return true;
}
@Override public void end() {
}
@Override public Object getResult() {
return null;
}
}));
}
public void firePropertyNameMigration(final ODatabaseDocument database, final String propertyName, final String newPropertyName,
final OType type) {
final boolean strictSQL = ((ODatabaseInternal) database).getStorage().getConfiguration().isStrictSql();
database.query(new OSQLAsynchQuery<Object>(
"select from " + getEscapedName(name, strictSQL) + " where " + getEscapedName(propertyName, strictSQL) + " is not null ",
new OCommandResultListener() {
@Override public boolean result(Object iRecord) {
final ODocument record = ((OIdentifiable) iRecord).getRecord();
record.setFieldType(propertyName, type);
record.field(newPropertyName, record.field(propertyName), type);
database.save(record);
return true;
}
@Override public void end() {
}
@Override public Object getResult() {
return null;
}
}));
}
public void checkPersistentPropertyType(final ODatabaseInternal<ORecord> database, final String propertyName, final OType type) {
final boolean strictSQL = database.getStorage().getConfiguration().isStrictSql();
final StringBuilder builder = new StringBuilder(256);
builder.append("select count(*) from ");
builder.append(getEscapedName(name, strictSQL));
builder.append(" where ");
builder.append(getEscapedName(propertyName, strictSQL));
builder.append(".type() not in [");
final Iterator<OType> cur = type.getCastable().iterator();
while (cur.hasNext()) {
builder.append('"').append(cur.next().name()).append('"');
if (cur.hasNext())
builder.append(",");
}
builder.append("] and ").append(getEscapedName(propertyName, strictSQL)).append(" is not null ");
if (type.isMultiValue())
builder.append(" and ").append(getEscapedName(propertyName, strictSQL)).append(".size() <> 0 limit 1");
final List<ODocument> res = database.command(new OCommandSQL(builder.toString())).execute();
if (((Long) res.get(0).field("count")) > 0)
throw new OSchemaException("The database contains some schema-less data in the property '" + name + "." + propertyName
+ "' that is not compatible with the type " + type + ". Fix those records and change the schema again");
}
protected String getEscapedName(final String iName, final boolean iStrictSQL) {
if (iStrictSQL)
// ESCAPE NAME
return "`" + iName + "`";
return iName;
}
public OSchemaShared getOwner() {
return owner;
}
private void calculateHashCode() {
int result = super.hashCode();
result = 31 * result + (name != null ? name.hashCode() : 0);
hashCode = result;
}
private void setOverSizeInternal(final float overSize) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
checkEmbedded();
this.overSize = overSize;
} finally {
releaseSchemaWriteLock();
}
}
private void setCustomInternal(final String name, final String value) {
acquireSchemaWriteLock();
try {
checkEmbedded();
if (customFields == null)
customFields = new HashMap<String, String>();
if (value == null || "null".equalsIgnoreCase(value))
customFields.remove(name);
else
customFields.put(name, value);
} finally {
releaseSchemaWriteLock();
}
}
private void clearCustomInternal() {
acquireSchemaWriteLock();
try {
checkEmbedded();
customFields = null;
} finally {
releaseSchemaWriteLock();
}
}
private void setNameInternal(final String name) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
checkEmbedded();
final String oldName = this.name;
owner.changeClassName(this.name, name, this);
this.name = name;
ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (!database.getStorageVersions().classesAreDetectedByShardId()) {
for (int shardId : shardIds) {
long[] range = storage.getShardDataRange(shardId);
OPhysicalPosition[] positions = storage.ceilingPhysicalPositions(shardId, new OPhysicalPosition(range[0]));
do {
for (OPhysicalPosition position : positions) {
final ORecordId identity = new ORecordId(shardId, position.shardPosition);
final ORawBuffer record = storage.readRecord(identity, null, true, null).getResult();
if (record.recordType == ODocument.RECORD_TYPE) {
final ORecordSerializerSchemaAware2CSV serializer = (ORecordSerializerSchemaAware2CSV) ORecordSerializerFactory
.instance().getFormat(ORecordSerializerSchemaAware2CSV.NAME);
String persName = new String(record.buffer, "UTF-8");
if (serializer.getClassName(persName).equalsIgnoreCase(name)) {
final ODocument document = new ODocument();
document.setLazyLoad(false);
document.fromStream(record.buffer);
ORecordInternal.setVersion(document, record.version);
ORecordInternal.setIdentity(document, identity);
document.setClassName(name);
document.setDirty();
document.save();
}
}
if (positions.length > 0)
positions = storage.higherPhysicalPositions(shardId, positions[positions.length - 1]);
}
} while (positions.length > 0);
}
}
renameShard(oldName, this.name);
} catch (UnsupportedEncodingException e) {
throw OException.wrapException(new OSchemaException("Error reading schema"), e);
} finally {
releaseSchemaWriteLock();
}
}
private void renameShard(String oldName, String newName) {
oldName = oldName.toLowerCase();
newName = newName.toLowerCase();
final ODatabaseDocumentInternal database = getDatabase();
final OStorage storage = database.getStorage();
if (storage.getShardIdByName(newName) != -1)
return;
final int shardId = storage.getShardIdByName(oldName);
if (shardId == -1)
return;
if (!hasShardId(shardId))
return;
database.command(new OCommandSQL("alter shard `" + oldName + "` name `" + newName + "`")).execute();
}
private void setShortNameInternal(final String iShortName) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
checkEmbedded();
String oldName = null;
if (this.shortName != null)
oldName = this.shortName;
owner.changeClassName(oldName, iShortName, this);
this.shortName = iShortName;
} finally {
releaseSchemaWriteLock();
}
}
private void setDescriptionInternal(final String iDescription) {
acquireSchemaWriteLock();
try {
checkEmbedded();
this.description = iDescription;
} finally {
releaseSchemaWriteLock();
}
}
private void dropPropertyInternal(final String iPropertyName) {
if (getDatabase().getTransaction().isActive())
throw new IllegalStateException("Cannot drop a property inside a transaction");
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_DELETE);
acquireSchemaWriteLock();
try {
checkEmbedded();
final OProperty prop = properties.remove(iPropertyName.toLowerCase());
if (prop == null)
throw new OSchemaException("Property '" + iPropertyName + "' not found in class " + name + "'");
} finally {
releaseSchemaWriteLock();
}
}
private OClass addShardIdInternal(final int shardId) {
acquireSchemaWriteLock();
try {
checkEmbedded();
owner.checkShardCanBeAdded(shardId, this);
for (int currId : shardIds)
if (currId == shardId)
// ALREADY ADDED
return this;
shardIds = OArrays.copyOf(shardIds, shardIds.length + 1);
shardIds[shardIds.length - 1] = shardId;
Arrays.sort(shardIds);
addPolymorphicShardId(shardId);
if (defaultShardId == NOT_EXISTENT_SHARD_ID)
defaultShardId = shardId;
owner.addShardForClass(shardId, this);
return this;
} finally {
releaseSchemaWriteLock();
}
}
private void addPolymorphicShardId(int shardId) {
if (Arrays.binarySearch(polymorphicShardIds, shardId) >= 0)
return;
polymorphicShardIds = OArrays.copyOf(polymorphicShardIds, polymorphicShardIds.length + 1);
polymorphicShardIds[polymorphicShardIds.length - 1] = shardId;
Arrays.sort(polymorphicShardIds);
addShardIdToIndexes(shardId);
for (OClassImpl superClass : superClasses) {
superClass.addPolymorphicShardId(shardId);
}
}
private OClass removeShardIdInternal(final int shardToRemove) {
acquireSchemaWriteLock();
try {
checkEmbedded();
boolean found = false;
for (int shardId : shardIds) {
if (shardId == shardToRemove) {
found = true;
break;
}
}
if (found) {
final int[] newShardIds = new int[shardIds.length - 1];
for (int i = 0, k = 0; i < shardIds.length; ++i) {
if (shardIds[i] == shardToRemove)
// JUMP IT
continue;
newShardIds[k] = shardIds[i];
k++;
}
shardIds = newShardIds;
removePolymorphicShardId(shardToRemove);
}
if (defaultShardId == shardToRemove) {
if (shardIds.length >= 1)
defaultShardId = shardIds[0];
else
defaultShardId = NOT_EXISTENT_SHARD_ID;
}
owner.removeShardForClass(shardToRemove, this);
} finally {
releaseSchemaWriteLock();
}
return this;
}
private void setAbstractInternal(final boolean isAbstract) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
if (isAbstract) {
// SWITCH TO ABSTRACT
if (defaultShardId != NOT_EXISTENT_SHARD_ID) {
// CHECK
if (count() > 0)
throw new IllegalStateException("Cannot set the class as abstract because contains records.");
tryDropShard(defaultShardId);
for (int shardId : getShardIds()) {
tryDropShard(shardId);
removePolymorphicShardId(shardId);
owner.removeShardForClass(shardId, this);
}
setShardIds(new int[] { NOT_EXISTENT_SHARD_ID });
defaultShardId = NOT_EXISTENT_SHARD_ID;
}
} else {
if (!abstractClass)
return;
int shardId = getDatabase().getShardIdByName(name);
if (shardId == -1)
shardId = getDatabase().addShard(name);
this.defaultShardId = shardId;
this.shardIds[0] = this.defaultShardId;
this.polymorphicShardIds = Arrays.copyOf(shardIds, shardIds.length);
for (OClass clazz : getAllSubclasses()) {
if (clazz instanceof OClassImpl) {
addPolymorphicShardIds((OClassImpl) clazz);
} else {
OLogManager.instance().warn(this, "Warning: cannot set polymorphic shard IDs for class " + name);
}
}
}
this.abstractClass = isAbstract;
} finally {
releaseSchemaWriteLock();
}
}
private void setStrictModeInternal(final boolean iStrict) {
getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
acquireSchemaWriteLock();
try {
checkEmbedded();
this.strictMode = iStrict;
} finally {
releaseSchemaWriteLock();
}
}
private OProperty addProperty(final String propertyName, final OType type, final OType linkedType, final OClass linkedClass,
final boolean unsafe) {
if (type == null)
throw new OSchemaException("Property type not defined.");
if (propertyName == null || propertyName.length() == 0)
throw new OSchemaException("Property name is null or empty");
if (getDatabase().getStorage().getConfiguration().isStrictSql()) {
validatePropertyName(propertyName);
}
if (getDatabase().getTransaction().isActive())
throw new OSchemaException("Cannot create property '" + propertyName + "' inside a transaction");
final ODatabaseDocumentInternal database = getDatabase();
database.checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);
if (linkedType != null)
OPropertyImpl.checkLinkTypeSupport(type);
if (linkedClass != null)
OPropertyImpl.checkSupportLinkedClass(type);
acquireSchemaWriteLock();
try {
final StringBuilder cmd = new StringBuilder("create property ");
// CLASS.PROPERTY NAME
if (getDatabase().getStorage().getConfiguration().isStrictSql())
cmd.append('`');
cmd.append(name);
if (getDatabase().getStorage().getConfiguration().isStrictSql())
cmd.append('`');
cmd.append('.');
if (getDatabase().getStorage().getConfiguration().isStrictSql())
cmd.append('`');
cmd.append(propertyName);
if (getDatabase().getStorage().getConfiguration().isStrictSql())
cmd.append('`');
// TYPE
cmd.append(' ');
cmd.append(type.name);
if (linkedType != null) {
// TYPE
cmd.append(' ');
cmd.append(linkedType.name);
} else if (linkedClass != null) {
// TYPE
cmd.append(' ');
if (getDatabase().getStorage().getConfiguration().isStrictSql())
cmd.append('`');
cmd.append(linkedClass.getName());
if (getDatabase().getStorage().getConfiguration().isStrictSql())
cmd.append('`');
}
if (unsafe)
cmd.append(" unsafe ");
final OStorage storage = database.getStorage();
if (storage instanceof OStorageProxy) {
database.command(new OCommandSQL(cmd.toString())).execute();
reload();
return getProperty(propertyName);
} else if (isDistributedCommand()) {
final OCommandSQL commandSQL = new OCommandSQL(cmd.toString());
commandSQL.addExcludedNode(((OAutoshardedStorage) storage).getNodeId());
database.command(commandSQL).execute();
return (OProperty) OScenarioThreadLocal.executeAsDistributed(new Callable<OProperty>() {
@Override public OProperty call() throws Exception {
return addPropertyInternal(propertyName, type, linkedType, linkedClass, unsafe);
}
});
} else
return (OProperty) OScenarioThreadLocal.executeAsDistributed(new Callable<OProperty>() {
@Override public OProperty call() throws Exception {
return addPropertyInternal(propertyName, type, linkedType, linkedClass, unsafe);
}
});
} finally {
releaseSchemaWriteLock();
}
}
private void validatePropertyName(final String propertyName) {
}
private int getShardId(final String stringValue) {
int clId;
if (!stringValue.isEmpty() && Character.isDigit(stringValue.charAt(0)))
try {
clId = Integer.parseInt(stringValue);
} catch (NumberFormatException e) {
clId = getDatabase().getShardIdByName(stringValue);
}
else
clId = getDatabase().getShardIdByName(stringValue);
return clId;
}
private void addShardIdToIndexes(int iId) {
if (getDatabase().getStorage().getUnderlying() instanceof OAbstractPaginatedStorage) {
final String shardName = getDatabase().getShardNameById(iId);
final List<String> indexesToAdd = new ArrayList<String>();
for (OIndex<?> index : getIndexes())
indexesToAdd.add(index.getName());
final OIndexManager indexManager = getDatabase().getMetadata().getIndexManager();
for (String indexName : indexesToAdd)
indexManager.addShardToIndex(shardName, indexName);
}
}
/**
* Adds a base class to the current one. It adds also the base class shard ids to the polymorphic shard ids array.
*
* @param iBaseClass The base class to add.
*/
private OClass addBaseClass(final OClassImpl iBaseClass) {
checkRecursion(iBaseClass);
if (subclasses == null)
subclasses = new ArrayList<OClass>();
if (subclasses.contains(iBaseClass))
return this;
subclasses.add(iBaseClass);
addPolymorphicShardIdsWithInheritance(iBaseClass);
return this;
}
private void checkParametersConflict(final OClass baseClass) {
final Collection<OProperty> baseClassProperties = baseClass.properties();
for (OProperty property : baseClassProperties) {
OProperty thisProperty = getProperty(property.getName());
if (thisProperty != null && !thisProperty.getType().equals(property.getType())) {
throw new OSchemaException(
"Cannot add base class '" + baseClass.getName() + "', because of property conflict: '" + thisProperty + "' vs '"
+ property + "'");
}
}
}
protected static void checkParametersConflict(List<OClass> classes) {
final Map<String, OProperty> comulative = new HashMap<String, OProperty>();
final Map<String, OProperty> properties = new HashMap<String, OProperty>();
for (OClass superClass : classes) {
if (superClass == null)
continue;
OClassImpl impl;
if (superClass instanceof OClassAbstractDelegate)
impl = (OClassImpl) ((OClassAbstractDelegate) superClass).delegate;
else
impl = (OClassImpl) superClass;
impl.propertiesMap(properties, false);
for (Map.Entry<String, OProperty> entry : properties.entrySet()) {
if (comulative.containsKey(entry.getKey())) {
final String property = entry.getKey();
final OProperty existingProperty = comulative.get(property);
if (!existingProperty.getType().equals(entry.getValue().getType())) {
throw new OSchemaException("Properties conflict detected: '" + existingProperty + "] vs [" + entry.getValue() + "]");
}
}
}
comulative.putAll(properties);
properties.clear();
}
}
private void checkRecursion(final OClass baseClass) {
if (isSubClassOf(baseClass)) {
throw new OSchemaException("Cannot add base class '" + baseClass.getName() + "', because of recursion");
}
}
private void removePolymorphicShardIds(final OClassImpl iBaseClass) {
for (final int shardId : iBaseClass.polymorphicShardIds)
removePolymorphicShardId(shardId);
}
private void removePolymorphicShardId(final int shardId) {
final int index = Arrays.binarySearch(polymorphicShardIds, shardId);
if (index < 0)
return;
if (index < polymorphicShardIds.length - 1)
System.arraycopy(polymorphicShardIds, index + 1, polymorphicShardIds, index, polymorphicShardIds.length - (index + 1));
polymorphicShardIds = Arrays.copyOf(polymorphicShardIds, polymorphicShardIds.length - 1);
removeShardFromIndexes(shardId);
for (OClassImpl superClass : superClasses) {
superClass.removePolymorphicShardId(shardId);
}
}
private void removeShardFromIndexes(final int iId) {
if (getDatabase().getStorage().getUnderlying() instanceof OAbstractPaginatedStorage) {
final String shardName = getDatabase().getShardNameById(iId);
final List<String> indexesToRemove = new ArrayList<String>();
for (final OIndex<?> index : getIndexes())
indexesToRemove.add(index.getName());
final OIndexManager indexManager = getDatabase().getMetadata().getIndexManager();
for (final String indexName : indexesToRemove)
indexManager.removeShardFromIndex(shardName, indexName);
}
}
private void tryDropShard(final int defaultShardId) {
if (name.toLowerCase().equals(getDatabase().getShardNameById(defaultShardId))) {
// DROP THE DEFAULT SHARD CALLED WITH THE SAME NAME ONLY IF EMPTY
if (getDatabase().getShardRecordSizeById(defaultShardId) == 0)
getDatabase().dropShard(defaultShardId, true);
}
}
private ODatabaseDocumentInternal getDatabase() {
return ODatabaseRecordThreadLocal.INSTANCE.get();
}
/**
* Add different shard id to the "polymorphic shard ids" array.
*/
private void addPolymorphicShardIds(final OClassImpl iBaseClass) {
Set<Integer> shards = new TreeSet<Integer>();
for (int shardId : polymorphicShardIds) {
shards.add(shardId);
}
for (int shardId : iBaseClass.polymorphicShardIds) {
if (shards.add(shardId)) {
try {
addShardIdToIndexes(shardId);
} catch (RuntimeException e) {
OLogManager.instance().warn(this, "Error adding shardId '%d' to index of class '%s'", e, shardId, getName());
shards.remove(shardId);
}
}
}
polymorphicShardIds = new int[shards.size()];
int i = 0;
for (Integer shard : shards) {
polymorphicShardIds[i] = shard;
i++;
}
}
private void addPolymorphicShardIdsWithInheritance(final OClassImpl iBaseClass) {
addPolymorphicShardIds(iBaseClass);
for (OClassImpl superClass : superClasses) {
superClass.addPolymorphicShardIdsWithInheritance(iBaseClass);
}
}
public List<OType> extractFieldTypes(final String[] fieldNames) {
final List<OType> types = new ArrayList<OType>(fieldNames.length);
for (String fieldName : fieldNames) {
if (!fieldName.equals("@rid"))
types.add(getProperty(decodeClassName(OIndexDefinitionFactory.extractFieldName(fieldName)).toLowerCase()).getType());
else
types.add(OType.LINK);
}
return types;
}
private OClass setShardIds(final int[] iShardIds) {
shardIds = iShardIds;
Arrays.sort(shardIds);
return this;
}
private boolean isDistributedCommand() {
return getDatabase().getStorage() instanceof OAutoshardedStorage && !OScenarioThreadLocal.INSTANCE.isRunModeDistributed();
}
public static String decodeClassName(String s) {
if (s == null) {
return null;
}
s = s.trim();
if (s.startsWith("`") && s.endsWith("`")) {
return s.substring(1, s.length() - 1);
}
return s;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment