blob: 9d2cc188f3462c48b2acd73d893dff3fa319aa3a [file] [log] [blame]
/*
* Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// James Sutherland (Oracle) - initial API and implementation
// // 30/05/2012-2.4 Guy Pelletier
// - 354678: Temp classloader is still being used during metadata processing
package org.eclipse.persistence.descriptors.partitioning;
import java.lang.reflect.Constructor;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedClassForName;
import org.eclipse.persistence.internal.security.PrivilegedGetConstructorFor;
import org.eclipse.persistence.internal.security.PrivilegedInvokeConstructor;
/**
* PUBLIC:
* Represent a specific range partition.
* Values {@literal >=} startValue and {@literal <=} endValue will be routed to the connection pool.
* @author James Sutherland
* @since EclipseLink 2.2
*/
public class RangePartition {
protected String endValueName;
protected String startValueName;
protected String partitionValueTypeName;
protected String connectionPool;
protected Class<?> partitionValueType;
protected Comparable startValue;
protected Comparable endValue;
public RangePartition() {}
/**
* INTERNAL:
* COnstructor used from metadata processing to avoid classloader
* dependencies. Class names are converted/initialized in the
* convertClassNamesToClasses method.
*/
public RangePartition(String connectionPool, String partitionValueTypeName, String startValueName, String endValueName) {
this.connectionPool = connectionPool;
this.endValue = null;
this.endValueName = endValueName;
this.startValue = null;
this.startValueName = startValueName;
this.partitionValueTypeName = partitionValueTypeName;
}
/**
* PUBLIC:
* Create the partition for the connectionPool and start/end values.
*/
public RangePartition(String connectionPool, Comparable startValue, Comparable endValue) {
this.connectionPool = connectionPool;
this.startValue = startValue;
this.endValue = endValue;
}
/**
* INTERNAL:
* Convert all the class-name-based settings to actual class-based settings.
* This method is used when converting a project that has been built with
* class names to a project with classes.
*/
public void convertClassNamesToClasses(ClassLoader classLoader) {
if (partitionValueType == null && partitionValueTypeName != null) {
try {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
try {
partitionValueType = AccessController.doPrivileged(new PrivilegedClassForName<>(partitionValueTypeName, true, classLoader));
} catch (PrivilegedActionException e) {
throw ValidationException.classNotFoundWhileConvertingClassNames(partitionValueTypeName, e.getException());
}
} else {
partitionValueType = org.eclipse.persistence.internal.security.PrivilegedAccessHelper.getClassForName(partitionValueTypeName, true, classLoader);
}
} catch (Exception exception) {
throw ValidationException.classNotFoundWhileConvertingClassNames(partitionValueTypeName, exception);
}
}
// Once we know we have a partition value type we can convert our partition ranges.
if (partitionValueType != null) {
if (startValueName != null) {
startValue = (Comparable) initObject(partitionValueType, startValueName);
}
if (endValueName != null) {
endValue = (Comparable) initObject(partitionValueType, endValueName);
}
}
}
/**
* PUBLIC:
* Return the range start value. Values greater or equal to this value are part of this partition.
*/
public Comparable getStartValue() {
return startValue;
}
/**
* INTERNAL:
* TODO: clean up the exception handling.
*/
@SuppressWarnings({"unchecked"})
protected <T> T initObject(Class<T> type, String value) {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
try {
Constructor<T> constructor = AccessController.doPrivileged(new PrivilegedGetConstructorFor<>(type, new Class<?>[] {String.class}, false));
return AccessController.doPrivileged(new PrivilegedInvokeConstructor<>(constructor, new Object[] {value}));
} catch (PrivilegedActionException exception) {
//throwInitObjectException(exception, type, value, isData);
}
} else {
try {
Constructor<T> constructor = PrivilegedAccessHelper.getConstructorFor(type, new Class<?>[] {String.class}, false);
return PrivilegedAccessHelper.invokeConstructor(constructor, new Object[] {value});
} catch (Exception exception) {
//throwInitObjectException(exception, type, value, isData);
}
}
return (T) value;
}
/**
* PUBLIC:
* Set the range start value. Values greater or equal to this value are part of this partition.
*/
public void setStartValue(Comparable startValue) {
this.startValue = startValue;
}
/**
* PUBLIC:
* Return the range end value. Values less than or equal this value are part of this partition.
*/
public Comparable getEndValue() {
return endValue;
}
/**
* PUBLIC:
* Set the range end value. Values less than or equal this value are part of this partition.
*/
public void setEndValue(Comparable endValue) {
this.endValue = endValue;
}
/**
* PUBLIC:
* Return the connection pool to use for this partition.
*/
public String getConnectionPool() {
return connectionPool;
}
/**
* PUBLIC:
* Return the connection pool to use for this partition.
*/
public void setConnectionPool(String connectionPool) {
this.connectionPool = connectionPool;
}
/**
* INTERNAL:
* Return if the value is in the partitions range.
*/
public boolean isInRange(Object value) {
if ((this.startValue != null) && (this.startValue.compareTo(value) > 0)) {
return false;
}
if ((this.endValue != null) && (this.endValue.compareTo(value) < 0)) {
return false;
}
return true;
}
}