Compare commits

..

1 commit

Author SHA1 Message Date
Greg Burd
6b0daebb93 WIP: working toward storing entity instances in a session-local cache. 2017-08-02 12:08:29 -04:00
316 changed files with 13432 additions and 20635 deletions

5
.gitignore vendored
View file

@ -1,8 +1,3 @@
.gradle/
build/
gradle/
gradlew
gradlew.bat
*.iml *.iml
.idea .idea
infer-out infer-out

View file

@ -3,6 +3,7 @@
<component name="EclipseCodeFormatterProjectSettings"> <component name="EclipseCodeFormatterProjectSettings">
<option name="projectSpecificProfile"> <option name="projectSpecificProfile">
<ProjectSpecificProfile> <ProjectSpecificProfile>
<option name="formatter" value="ECLIPSE" />
<option name="pathToConfigFileJava" value="$PROJECT_DIR$/../newton/formatting/onshape-eclipse-general-preferences.epf" /> <option name="pathToConfigFileJava" value="$PROJECT_DIR$/../newton/formatting/onshape-eclipse-general-preferences.epf" />
</ProjectSpecificProfile> </ProjectSpecificProfile>
</option> </option>

202
NOTES
View file

@ -1,202 +0,0 @@
Operation/
|-- AbstractStatementOperation
| |-- AbstractOperation
| | |-- AbstractFilterOperation
| | | |-- CountOperation
| | | |-- DeleteOperation
| | | `-- UpdateOperation
| | |-- BoundOperation
| | `-- InsertOperation
| |-- AbstractOptionalOperation
| | |-- AbstractFilterOptionalOperation
| | | |-- SelectFirstOperation
| | | `-- SelectFirstTransformingOperation
| | `-- BoundOptionalOperation
| `-- AbstractStreamOperation
| |-- AbstractFilterStreamOperation
| | |-- SelectOperation
| | `-- SelectTransformingOperation
| `-- BoundStreamOperation
|-- PreparedOperation
|-- PreparedOptionalOperation
`-- PreparedStreamOperation
----
@CompoundIndex()
create a new col in the same table called __idx_a_b_c that the hash of the concatenated values in that order is stored, create a normal index for that (CREATE INDEX ...)
if a query matches that set of columns then use that indexed col to fetch the desired results from that table
could also work with .in() query if materialized view exists
----
// TODO(gburd): create a statement that matches one that wasn't prepared
//String key =
// "use " + preparedStatement.getQueryKeyspace() + "; " + preparedStatement.getQueryString();
//for (Object param : params) {
// key = key.replaceFirst(Pattern.quote("?"), param.toString());
//}
primitive types have default values, (e.g. boolean, int, ...) but primative wrapper classes do not and can be null (e.g. Boolean, Integer, ...)
create table wal {
id timeuuid,
follows timeuuid,
read <Counting Quotient Filter, Set<{keyspace, col, schema generation, timestamp}>>
write <Counting Quotient Filter, Set<{keyspace, col, schema generation, timestamp}>>
primary key (id, follows)
}
begin:
- insert into wal (timeuuid, parent timeuuid,
// NOTE: Update operations have no meaning when they only contain primary key components, so
// given that `properties` is ordered with the keys first if we find that the last element
// is either a partition key or clustering column then we know we should just skip this operation.
ColumnType ct = ((HelenusProperty) properties.toArray()[properties.size() - 1]).getColumnType();
if (ct != ColumnType.PARTITION_KEY && ct != ColumnType.CLUSTERING_COLUMN) {
return;
}
public Stream<E> sync() {
ListenableFuture<Stream<E>> future = async();
Futures.addCallback(future, new FutureCallback<String>() {
@Override
public void onSuccess(String contents) {
//...process web site contents
}
@Override
public void onFailure(Throwable throwable) {
log.error("Exception in task", throwable);
}
});
}
-------
private mergeCache(Map<String, Set<Object>>
private static <E> Iterable<E> concat(
Iterable<? extends E> i1,
Iterable<? extends E> i2) {
return new Iterable<E>() {
public Iterator<E> iterator() {
return new Iterator<E>() {
Iterator<? extends E> listIterator = i1.iterator();
Boolean checkedHasNext;
E nextValue;
private boolean startTheSecond;
void theNext() {
if (listIterator.hasNext()) {
checkedHasNext = true;
nextValue = listIterator.next();
} else if (startTheSecond)
checkedHasNext = false;
else {
startTheSecond = true;
listIterator = i2.iterator();
theNext();
}
}
public boolean hasNext() {
if (checkedHasNext == null)
theNext();
return checkedHasNext;
}
public E next() {
if (!hasNext())
throw new NoSuchElementException();
checkedHasNext = null;
return nextValue;
}
public void remove() {
listIterator.remove();
}
};
}
};
}
----------------------------------
if ("ttl".equals(methodName) && method.getParameterCount() == 1 && method.getReturnType() == int.class) {
Getter getter = (Getter) args[0];
if (getter == null) {
return false;
}
HelenusProperty prop = MappingUtil.resolveMappingProperty(getter).getProperty();
String getterName = prop.getPropertyName();
String ttlKeyForProperty = prop.getColumnName().toCql() + "_ttl";
if (src.containsKey(ttlKeyForProperty)) {
return src.get(ttlKeyForProperty);
} else {
return 0;
}
}
if ("written".equals(methodName) && method.getParameterCount() == 1 && method.getReturnType() == int.class) {
Getter getter = (Getter) args[0];
if (getter == null) {
return false;
}
HelenusProperty prop = MappingUtil.resolveMappingProperty(getter).getProperty();
String getterName = prop.getPropertyName();
String ttlKeyForProperty = prop.getColumnName().toCql() + "_ttl";
if (src.containsKey(ttlKeyForProperty)) {
return src.get(ttlKeyForProperty);
} else {
return 0;
}
}
-----------------
/*else {
Cache<String, Object> cache = session.getSessionCache();
Map<String, Object> rowMap = this.cache.rowMap();
for (String rowKey : rowMap.keySet()) {
String keys = flattenFacets(facets);
for (String key : keys) {
Object value = cache.getIfPresent(key);
if (value != null) {
result = Optional.of(value);
break;
}
}
}
cache.put
}
*/
------------------
InsertOperation
Class<?> iface = entity.getMappingInterface();
boolean includesNonIdentityValues = values.stream().map(t -> {
ColumnType type = t._1.getProperty().getColumnType();
return !((type == ColumnType.PARTITION_KEY) || (type == ColumnType.CLUSTERING_COLUMN));
})
.reduce(false, (acc, t) -> acc || t);
if (resultType == iface) {
if (values.size() > 0 && includesNonIdentityValues) {
boolean immutable = iface.isAssignableFrom(Drafted.class);
-------------------
final Object value;
if (method.getParameterCount() == 1 && args[0] instanceof Boolean && src instanceof ValueProviderMap) {
value = ((ValueProviderMap)src).get(methodName, (Boolean)args[0]);
} else {
value = src.get(methodName);
}
--------------------

View file

@ -1,5 +1,5 @@
# Helenus # Helenus
Fast and easy, functional style cutting edge Java 8 Cassandra client for C* 3.x Fast and easy, functional style cutting edge Java 8 and Scala 2.11 Cassandra client for C* 3.x
### Features ### Features
@ -9,13 +9,14 @@ Fast and easy, functional style cutting edge Java 8 Cassandra client for C* 3.x
* Reactive asynchronous and synchronous API * Reactive asynchronous and synchronous API
* Provides Java mapping for Tables, Tuples, UDTs (User Defined Type), Collections, UDT Collections, Tuple Collections * Provides Java mapping for Tables, Tuples, UDTs (User Defined Type), Collections, UDT Collections, Tuple Collections
* Uses lazy mapping in all cases where possible * Uses lazy mapping in all cases where possible
* Supports Java 8 Futures and Guava ListenableFuture * Supports Guava ListenableFuture and Scala Future
### Requirements ### Requirements
* JVM 8 * JVM 8
* Datastax Driver 3.x * Datastax Driver 3.x
* Cassandra 3.x * Cassandra 3.x
* Scala 2.11+
* Maven * Maven
### Maven ### Maven
@ -31,6 +32,27 @@ Latest release dependency:
</dependencies> </dependencies>
``` ```
Active development dependency for Scala 2.11:
```
<dependencies>
<dependency>
<groupId>net.helenus</groupId>
<artifactId>helenus-core</artifactId>
<version>1.2.0_2.11-SNAPSHOT</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>oss-sonatype</id>
<name>oss-sonatype</name>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
```
### Simple Example ### Simple Example
@ -110,6 +132,7 @@ public interface AbstractRepository {
Account repository: Account repository:
``` ```
import scala.concurrent.Future;
public interface AccountRepository extends AbstractRepository { public interface AccountRepository extends AbstractRepository {

View file

@ -1,3 +0,0 @@
#!/usr/bin/env bash
mvn clean jar:jar javadoc:jar source:jar deploy -Prelease

View file

@ -1,14 +0,0 @@
#!/usr/bin/env bash
if [ "X$1" == "Xall" ]; then
for f in $(find ./src -name \*.java); do
echo Formatting $f
java -jar ./lib/google-java-format-1.3-all-deps.jar --replace $f
done
else
for file in $(git status --short | awk '{print $2}'); do
echo $file
java -jar ./lib/google-java-format-1.3-all-deps.jar --replace $file
done
fi

3
deploy.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
mvn clean jar:jar javadoc:jar source:jar deploy -Prelease

View file

@ -11,7 +11,10 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: com.datastax.cassandra:cassandra-driver-core:3.3.2" level="project" /> <orderEntry type="library" name="Maven: com.github.ben-manes.caffeine:caffeine:2.5.3" level="project" />
<orderEntry type="library" name="Maven: io.dropwizard.metrics:metrics-core:3.2.3" level="project" />
<orderEntry type="library" name="Maven: org.scala-lang:scala-library:2.13.0-M1" level="project" />
<orderEntry type="library" name="Maven: com.datastax.cassandra:cassandra-driver-core:3.3.0" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.0.47.Final" level="project" /> <orderEntry type="library" name="Maven: io.netty:netty-handler:4.0.47.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.0.47.Final" level="project" /> <orderEntry type="library" name="Maven: io.netty:netty-buffer:4.0.47.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-common:4.0.47.Final" level="project" /> <orderEntry type="library" name="Maven: io.netty:netty-common:4.0.47.Final" level="project" />
@ -28,15 +31,14 @@
<orderEntry type="library" name="Maven: com.github.jnr:jnr-x86asm:1.0.2" level="project" /> <orderEntry type="library" name="Maven: com.github.jnr:jnr-x86asm:1.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.jnr:jnr-posix:3.0.27" level="project" /> <orderEntry type="library" name="Maven: com.github.jnr:jnr-posix:3.0.27" level="project" />
<orderEntry type="library" name="Maven: com.github.jnr:jnr-constants:0.9.0" level="project" /> <orderEntry type="library" name="Maven: com.github.jnr:jnr-constants:0.9.0" level="project" />
<orderEntry type="library" name="Maven: com.datastax.cassandra:cassandra-driver-extras:3.3.2" level="project" /> <orderEntry type="library" name="Maven: org.aspectj:aspectjrt:1.8.10" level="project" />
<orderEntry type="library" name="Maven: com.diffplug.durian:durian:3.4.0" level="project" />
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.8.10" level="project" /> <orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.8.10" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.6" level="project" /> <orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:4.3.10.RELEASE" level="project" /> <orderEntry type="library" name="Maven: org.springframework:spring-core:4.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" /> <orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" />
<orderEntry type="library" name="Maven: javax.cache:cache-api:1.1.0" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:20.0" level="project" /> <orderEntry type="library" name="Maven: com.google.guava:guava:20.0" level="project" />
<orderEntry type="library" name="Maven: io.dropwizard.metrics:metrics-core:3.2.2" level="project" /> <orderEntry type="library" name="Maven: com.github.ben-manes.caffeine:caffeine:2.5.3" level="project" />
<orderEntry type="library" name="Maven: io.dropwizard.metrics:metrics-core:3.2.3" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.0.CR3" level="project" /> <orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.0.CR3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.codehaus.jackson:jackson-mapper-asl:1.9.13" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.codehaus.jackson:jackson-mapper-asl:1.9.13" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.anthemengineering.mojo:infer-maven-plugin:0.1.0" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: com.anthemengineering.mojo:infer-maven-plugin:0.1.0" level="project" />
@ -112,11 +114,10 @@
<orderEntry type="library" scope="TEST" name="Maven: org.fusesource:sigar:1.6.4" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.fusesource:sigar:1.6.4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jdt.core.compiler:ecj:4.4.2" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jdt.core.compiler:ecj:4.4.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.caffinitas.ohc:ohc-core:0.4.4" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.caffinitas.ohc:ohc-core:0.4.4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.github.ben-manes.caffeine:caffeine:2.2.6" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.jctools:jctools-core:1.2.1" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.jctools:jctools-core:1.2.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: ca.exprofesso:guava-jcache:1.0.4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: commons-io:commons-io:2.5" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: commons-io:commons-io:2.5" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.github.stephenc:jamm:0.2.5" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-library:1.3" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-library:1.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:2.8.47" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:2.8.47" level="project" />

69
pom.xml
View file

@ -4,8 +4,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>net.helenus</groupId> <groupId>net.helenus</groupId>
<artifactId>helenus-net-core</artifactId> <artifactId>helenus-core</artifactId>
<version>2.1</version> <version>2.0.5-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>helenus</name> <name>helenus</name>
@ -40,9 +40,6 @@
<properties> <properties>
<dist.id>helenus</dist.id> <dist.id>helenus</dist.id>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties> </properties>
<repositories> <repositories>
@ -106,22 +103,22 @@
<dependencies> <dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.13.0-M1</version>
</dependency>
<dependency> <dependency>
<groupId>com.datastax.cassandra</groupId> <groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId> <artifactId>cassandra-driver-core</artifactId>
<version>3.3.2</version> <version>3.3.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.datastax.cassandra</groupId> <groupId>org.aspectj</groupId>
<artifactId>cassandra-driver-extras</artifactId> <artifactId>aspectjrt</artifactId>
<version>3.3.2</version> <version>1.8.10</version>
</dependency>
<dependency>
<groupId>com.diffplug.durian</groupId>
<artifactId>durian</artifactId>
<version>3.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@ -142,23 +139,25 @@
<version>4.3.10.RELEASE</version> <version>4.3.10.RELEASE</version>
</dependency> </dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.0</version>
</dependency>
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>20.0</version> <version>20.0</version>
</dependency> </dependency>
<!-- Caching -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.5.3</version>
</dependency>
<!-- Metrics --> <!-- Metrics -->
<!-- https://mvnrepository.com/artifact/io.dropwizard.metrics/metrics-core -->
<dependency> <dependency>
<groupId>io.dropwizard.metrics</groupId> <groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId> <artifactId>metrics-core</artifactId>
<version>3.2.2</version> <version>3.2.3</version>
</dependency> </dependency>
<!-- Validation --> <!-- Validation -->
@ -211,24 +210,6 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>ca.exprofesso</groupId>
<artifactId>guava-jcache</artifactId>
<version>1.0.4</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
<exclusion>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>commons-io</groupId> <groupId>commons-io</groupId>
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
@ -243,6 +224,13 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.github.stephenc</groupId>
<artifactId>jamm</artifactId>
<version>0.2.5</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.hamcrest</groupId> <groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId> <artifactId>hamcrest-library</artifactId>
@ -277,6 +265,7 @@
<version>1.7.1</version> <version>1.7.1</version>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -1,3 +1,3 @@
#!/usr/bin/env bash #!/bin/bash
mvn clean jar:jar javadoc:jar source:jar install -Prelease mvn clean jar:jar javadoc:jar source:jar install -Prelease

View file

@ -5,19 +5,18 @@ import java.util.List;
public class DefaultMetadata extends Metadata { public class DefaultMetadata extends Metadata {
public DefaultMetadata() { public DefaultMetadata() { super(null); }
super(null);
}
private DefaultMetadata(Cluster.Manager cluster) { private DefaultMetadata(Cluster.Manager cluster) {
super(cluster); super(cluster);
} }
public TupleType newTupleType(DataType... types) { public TupleType newTupleType(DataType... types) {
return newTupleType(Arrays.asList(types)); return newTupleType(Arrays.asList(types));
} }
public TupleType newTupleType(List<DataType> types) {
return new TupleType(types, ProtocolVersion.NEWEST_SUPPORTED, CodecRegistry.DEFAULT_INSTANCE);
}
public TupleType newTupleType(List<DataType> types) {
return new TupleType(types, ProtocolVersion.NEWEST_SUPPORTED, CodecRegistry.DEFAULT_INSTANCE);
}
} }

View file

@ -1,49 +0,0 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package com.datastax.driver.core.querybuilder;
import com.datastax.driver.core.CodecRegistry;
import java.util.List;
public class IsNotNullClause extends Clause {
final String name;
public IsNotNullClause(String name) {
this.name = name;
}
@Override
String name() {
return name;
}
@Override
Object firstValue() {
return null;
}
@Override
void appendTo(StringBuilder sb, List<Object> variables, CodecRegistry codecRegistry) {
Utils.appendName(name, sb).append(" IS NOT NULL");
}
@Override
boolean containsBindMarker() {
return false;
}
}

View file

@ -1,155 +1,132 @@
package com.datastax.driver.core.schemabuilder; package com.datastax.driver.core.schemabuilder;
import static com.datastax.driver.core.schemabuilder.SchemaStatement.*;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import static com.datastax.driver.core.schemabuilder.SchemaStatement.STATEMENT_START;
import static com.datastax.driver.core.schemabuilder.SchemaStatement.validateNotEmpty;
import static com.datastax.driver.core.schemabuilder.SchemaStatement.validateNotKeyWord;
public class CreateCustomIndex extends CreateIndex { public class CreateCustomIndex extends CreateIndex {
private String indexName; private String indexName;
private boolean ifNotExists = false; private boolean ifNotExists = false;
private Optional<String> keyspaceName = Optional.absent(); private Optional<String> keyspaceName = Optional.absent();
private String tableName; private String tableName;
private String columnName; private String columnName;
private boolean keys; private boolean keys;
CreateCustomIndex(String indexName) { CreateCustomIndex(String indexName) {
super(indexName); super(indexName);
validateNotEmpty(indexName, "Index name"); validateNotEmpty(indexName, "Index name");
validateNotKeyWord( validateNotKeyWord(indexName, String.format("The index name '%s' is not allowed because it is a reserved keyword", indexName));
indexName, this.indexName = indexName;
String.format(
"The index name '%s' is not allowed because it is a reserved keyword", indexName));
this.indexName = indexName;
}
/**
* Add the 'IF NOT EXISTS' condition to this CREATE INDEX statement.
*
* @return this CREATE INDEX statement.
*/
public CreateIndex ifNotExists() {
this.ifNotExists = true;
return this;
}
/**
* Specify the keyspace and table to create the index on.
*
* @param keyspaceName the keyspace name.
* @param tableName the table name.
* @return a {@link CreateIndex.CreateIndexOn} that will allow the specification of the column.
*/
public CreateIndex.CreateIndexOn onTable(String keyspaceName, String tableName) {
validateNotEmpty(keyspaceName, "Keyspace name");
validateNotEmpty(tableName, "Table name");
validateNotKeyWord(
keyspaceName,
String.format(
"The keyspace name '%s' is not allowed because it is a reserved keyword",
keyspaceName));
validateNotKeyWord(
tableName,
String.format(
"The table name '%s' is not allowed because it is a reserved keyword", tableName));
this.keyspaceName = Optional.fromNullable(keyspaceName);
this.tableName = tableName;
return new CreateCustomIndex.CreateIndexOn();
}
/**
* Specify the table to create the index on.
*
* @param tableName the table name.
* @return a {@link CreateIndex.CreateIndexOn} that will allow the specification of the column.
*/
public CreateIndex.CreateIndexOn onTable(String tableName) {
validateNotEmpty(tableName, "Table name");
validateNotKeyWord(
tableName,
String.format(
"The table name '%s' is not allowed because it is a reserved keyword", tableName));
this.tableName = tableName;
return new CreateCustomIndex.CreateIndexOn();
}
String getCustomClassName() {
return "";
}
String getOptions() {
return "";
}
@Override
public String buildInternal() {
StringBuilder createStatement =
new StringBuilder(STATEMENT_START).append("CREATE CUSTOM INDEX ");
if (ifNotExists) {
createStatement.append("IF NOT EXISTS ");
}
createStatement.append(indexName).append(" ON ");
if (keyspaceName.isPresent()) {
createStatement.append(keyspaceName.get()).append(".");
}
createStatement.append(tableName);
createStatement.append("(");
if (keys) {
createStatement.append("KEYS(");
}
createStatement.append(columnName);
if (keys) {
createStatement.append(")");
}
createStatement.append(")");
createStatement.append(" USING '");
createStatement.append(getCustomClassName());
createStatement.append("' WITH OPTIONS = {");
createStatement.append(getOptions());
createStatement.append(" }");
return createStatement.toString();
}
public class CreateIndexOn extends CreateIndex.CreateIndexOn {
/**
* Specify the column to create the index on.
*
* @param columnName the column name.
* @return the final CREATE INDEX statement.
*/
public SchemaStatement andColumn(String columnName) {
validateNotEmpty(columnName, "Column name");
validateNotKeyWord(
columnName,
String.format(
"The column name '%s' is not allowed because it is a reserved keyword", columnName));
CreateCustomIndex.this.columnName = columnName;
return SchemaStatement.fromQueryString(buildInternal());
} }
/** /**
* Create an index on the keys of the given map column. * Add the 'IF NOT EXISTS' condition to this CREATE INDEX statement.
* *
* @param columnName the column name. * @return this CREATE INDEX statement.
* @return the final CREATE INDEX statement.
*/ */
public SchemaStatement andKeysOfColumn(String columnName) { public CreateIndex ifNotExists() {
validateNotEmpty(columnName, "Column name"); this.ifNotExists = true;
validateNotKeyWord( return this;
columnName, }
String.format(
"The column name '%s' is not allowed because it is a reserved keyword", columnName)); /**
CreateCustomIndex.this.columnName = columnName; * Specify the keyspace and table to create the index on.
CreateCustomIndex.this.keys = true; *
return SchemaStatement.fromQueryString(buildInternal()); * @param keyspaceName the keyspace name.
* @param tableName the table name.
* @return a {@link CreateIndex.CreateIndexOn} that will allow the specification of the column.
*/
public CreateIndex.CreateIndexOn onTable(String keyspaceName, String tableName) {
validateNotEmpty(keyspaceName, "Keyspace name");
validateNotEmpty(tableName, "Table name");
validateNotKeyWord(keyspaceName, String.format("The keyspace name '%s' is not allowed because it is a reserved keyword", keyspaceName));
validateNotKeyWord(tableName, String.format("The table name '%s' is not allowed because it is a reserved keyword", tableName));
this.keyspaceName = Optional.fromNullable(keyspaceName);
this.tableName = tableName;
return new CreateCustomIndex.CreateIndexOn();
}
/**
* Specify the table to create the index on.
*
* @param tableName the table name.
* @return a {@link CreateIndex.CreateIndexOn} that will allow the specification of the column.
*/
public CreateIndex.CreateIndexOn onTable(String tableName) {
validateNotEmpty(tableName, "Table name");
validateNotKeyWord(tableName, String.format("The table name '%s' is not allowed because it is a reserved keyword", tableName));
this.tableName = tableName;
return new CreateCustomIndex.CreateIndexOn();
}
public class CreateIndexOn extends CreateIndex.CreateIndexOn {
/**
* Specify the column to create the index on.
*
* @param columnName the column name.
* @return the final CREATE INDEX statement.
*/
public SchemaStatement andColumn(String columnName) {
validateNotEmpty(columnName, "Column name");
validateNotKeyWord(columnName, String.format("The column name '%s' is not allowed because it is a reserved keyword", columnName));
CreateCustomIndex.this.columnName = columnName;
return SchemaStatement.fromQueryString(buildInternal());
}
/**
* Create an index on the keys of the given map column.
*
* @param columnName the column name.
* @return the final CREATE INDEX statement.
*/
public SchemaStatement andKeysOfColumn(String columnName) {
validateNotEmpty(columnName, "Column name");
validateNotKeyWord(columnName, String.format("The column name '%s' is not allowed because it is a reserved keyword", columnName));
CreateCustomIndex.this.columnName = columnName;
CreateCustomIndex.this.keys = true;
return SchemaStatement.fromQueryString(buildInternal());
}
}
String getCustomClassName() { return ""; }
String getOptions() { return ""; }
@Override
public String buildInternal() {
StringBuilder createStatement = new StringBuilder(STATEMENT_START).append("CREATE CUSTOM INDEX ");
if (ifNotExists) {
createStatement.append("IF NOT EXISTS ");
}
createStatement.append(indexName).append(" ON ");
if (keyspaceName.isPresent()) {
createStatement.append(keyspaceName.get()).append(".");
}
createStatement.append(tableName);
createStatement.append("(");
if (keys) {
createStatement.append("KEYS(");
}
createStatement.append(columnName);
if (keys) {
createStatement.append(")");
}
createStatement.append(")");
createStatement.append(" USING '");
createStatement.append(getCustomClassName());
createStatement.append("' WITH OPTIONS = {");
createStatement.append(getOptions());
createStatement.append(" }");
return createStatement.toString();
} }
}
} }

View file

@ -1,57 +0,0 @@
package com.datastax.driver.core.schemabuilder;
import com.datastax.driver.core.CodecRegistry;
import com.datastax.driver.core.querybuilder.Select;
public class CreateMaterializedView extends Create {
private final String viewName;
private Select.Where selection;
private String primaryKey;
private String clustering;
public CreateMaterializedView(
String keyspaceName,
String viewName,
Select.Where selection,
String primaryKey,
String clustering) {
super(keyspaceName, viewName);
this.viewName = viewName;
this.selection = selection;
this.primaryKey = primaryKey;
this.clustering = clustering;
}
public String getQueryString(CodecRegistry codecRegistry) {
return buildInternal();
}
public String buildInternal() {
StringBuilder createStatement =
new StringBuilder(STATEMENT_START).append("CREATE MATERIALIZED VIEW");
if (ifNotExists) {
createStatement.append(" IF NOT EXISTS");
}
createStatement.append(" ");
if (keyspaceName.isPresent()) {
createStatement.append(keyspaceName.get()).append(".");
}
createStatement.append(viewName);
createStatement.append(" AS ");
createStatement.append(selection.getQueryString());
createStatement.setLength(createStatement.length() - 1);
createStatement.append(" ");
createStatement.append(primaryKey);
if (clustering != null) {
createStatement.append(" ").append(clustering);
}
createStatement.append(";");
return createStatement.toString();
}
public String toString() {
return buildInternal();
}
}

View file

@ -2,17 +2,17 @@ package com.datastax.driver.core.schemabuilder;
public class CreateSasiIndex extends CreateCustomIndex { public class CreateSasiIndex extends CreateCustomIndex {
public CreateSasiIndex(String indexName) { public CreateSasiIndex(String indexName) {
super(indexName); super(indexName);
} }
String getCustomClassName() { String getCustomClassName() {
return "org.apache.cassandra.index.sasi.SASIIndex"; return "org.apache.cassandra.index.sasi.SASIIndex";
} }
String getOptions() { String getOptions() {
return "'analyzer_class': " return "'analyzer_class': "
+ "'org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer', " + "'org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer', "
+ "'case_sensitive': 'false'"; + "'case_sensitive': 'false'";
} }
} }

View file

@ -17,22 +17,24 @@ package com.datastax.driver.core.schemabuilder;
import com.datastax.driver.core.CodecRegistry; import com.datastax.driver.core.CodecRegistry;
/** A built CREATE TABLE statement. */ /**
* A built CREATE TABLE statement.
*/
public class CreateTable extends Create { public class CreateTable extends Create {
public CreateTable(String keyspaceName, String tableName) { public CreateTable(String keyspaceName, String tableName) {
super(keyspaceName, tableName); super(keyspaceName, tableName);
} }
public CreateTable(String tableName) { public CreateTable(String tableName) {
super(tableName); super(tableName);
} }
public String getQueryString(CodecRegistry codecRegistry) { public String getQueryString(CodecRegistry codecRegistry) {
return buildInternal(); return buildInternal();
} }
public String toString() { public String toString() {
return buildInternal(); return buildInternal();
} }
} }

View file

@ -1,52 +0,0 @@
package com.datastax.driver.core.schemabuilder;
import com.google.common.base.Optional;
public class DropMaterializedView extends Drop {
private Optional<String> keyspaceName = Optional.absent();
private String itemName;
private boolean ifExists = true;
public DropMaterializedView(String keyspaceName, String viewName) {
this(keyspaceName, viewName, DroppedItem.MATERIALIZED_VIEW);
}
private DropMaterializedView(String keyspaceName, String viewName, DroppedItem itemType) {
super(keyspaceName, viewName, Drop.DroppedItem.TABLE);
validateNotEmpty(keyspaceName, "Keyspace name");
this.keyspaceName = Optional.fromNullable(keyspaceName);
this.itemName = viewName;
}
/**
* Add the 'IF EXISTS' condition to this DROP statement.
*
* @return this statement.
*/
public Drop ifExists() {
this.ifExists = true;
return this;
}
@Override
public String buildInternal() {
StringBuilder dropStatement = new StringBuilder("DROP MATERIALIZED VIEW ");
if (ifExists) {
dropStatement.append("IF EXISTS ");
}
if (keyspaceName.isPresent()) {
dropStatement.append(keyspaceName.get()).append(".");
}
dropStatement.append(itemName);
return dropStatement.toString();
}
enum DroppedItem {
TABLE,
TYPE,
INDEX,
MATERIALIZED_VIEW
}
}

View file

@ -1,48 +1,49 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors *
* * Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. * You may obtain a copy of the License at
* You may obtain a copy of the License at *
* * http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0 *
* * Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and * limitations under the License.
* limitations under the License. */
*/ package net.helenus.config;
package net.helenus.config;
import java.lang.reflect.Method;
import java.lang.reflect.Method; import java.util.function.Function;
import java.util.function.Function;
import net.helenus.core.DslInstantiator; import net.helenus.core.DslInstantiator;
import net.helenus.core.MapperInstantiator; import net.helenus.core.MapperInstantiator;
import net.helenus.core.reflect.ReflectionDslInstantiator; import net.helenus.core.reflect.ReflectionDslInstantiator;
import net.helenus.core.reflect.ReflectionMapperInstantiator; import net.helenus.core.reflect.ReflectionMapperInstantiator;
import net.helenus.mapping.convert.CamelCaseToUnderscoreConverter; import net.helenus.mapping.convert.CamelCaseToUnderscoreConverter;
public class DefaultHelenusSettings implements HelenusSettings { public class DefaultHelenusSettings implements HelenusSettings {
@Override @Override
public Function<String, String> getPropertyToColumnConverter() { public Function<String, String> getPropertyToColumnConverter() {
return CamelCaseToUnderscoreConverter.INSTANCE; return CamelCaseToUnderscoreConverter.INSTANCE;
} }
@Override @Override
public Function<Method, Boolean> getGetterMethodDetector() { public Function<Method, Boolean> getGetterMethodDetector() {
return GetterMethodDetector.INSTANCE; return GetterMethodDetector.INSTANCE;
} }
@Override @Override
public DslInstantiator getDslInstantiator() { public DslInstantiator getDslInstantiator() {
return ReflectionDslInstantiator.INSTANCE; return ReflectionDslInstantiator.INSTANCE;
} }
@Override @Override
public MapperInstantiator getMapperInstantiator() { public MapperInstantiator getMapperInstantiator() {
return ReflectionMapperInstantiator.INSTANCE; return ReflectionMapperInstantiator.INSTANCE;
} }
}
}

View file

@ -1,49 +1,47 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors *
* * Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. * You may obtain a copy of the License at
* You may obtain a copy of the License at *
* * http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0 *
* * Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and * limitations under the License.
* limitations under the License. */
*/ package net.helenus.config;
package net.helenus.config;
import net.helenus.mapping.annotation.Transient;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Method;
import java.util.function.Function; import java.util.function.Function;
import net.helenus.mapping.annotation.Transient;
public enum GetterMethodDetector implements Function<Method, Boolean> {
public enum GetterMethodDetector implements Function<Method, Boolean> {
INSTANCE; INSTANCE;
@Override @Override
public Boolean apply(Method method) { public Boolean apply(Method method) {
if (method == null) { if (method == null) {
throw new IllegalArgumentException("empty parameter"); throw new IllegalArgumentException("empty parameter");
} }
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) { if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
return false; return false;
} }
if (Modifier.isStatic(method.getModifiers())) { // Methods marked "Transient" are not mapped, skip them.
return false; if (method.getDeclaredAnnotation(Transient.class) != null) {
} return false;
}
// Methods marked "Transient" are not mapped, skip them.
if (method.getDeclaredAnnotation(Transient.class) != null) { return true;
return false;
} }
return true; }
}
}

View file

@ -1,33 +1,34 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors *
* * Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. * You may obtain a copy of the License at
* You may obtain a copy of the License at *
* * http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0 *
* * Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and * limitations under the License.
* limitations under the License. */
*/ package net.helenus.config;
package net.helenus.config;
import java.lang.reflect.Method;
import java.lang.reflect.Method; import java.util.function.Function;
import java.util.function.Function;
import net.helenus.core.DslInstantiator; import net.helenus.core.DslInstantiator;
import net.helenus.core.MapperInstantiator; import net.helenus.core.MapperInstantiator;
public interface HelenusSettings { public interface HelenusSettings {
Function<String, String> getPropertyToColumnConverter(); Function<String, String> getPropertyToColumnConverter();
Function<Method, Boolean> getGetterMethodDetector(); Function<Method, Boolean> getGetterMethodDetector();
DslInstantiator getDslInstantiator(); DslInstantiator getDslInstantiator();
MapperInstantiator getMapperInstantiator(); MapperInstantiator getMapperInstantiator();
}
}

View file

@ -1,38 +0,0 @@
package net.helenus.core;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import net.helenus.core.reflect.MapExportable;
public abstract class AbstractAuditedEntityDraft<E> extends AbstractEntityDraft<E> {
public AbstractAuditedEntityDraft(MapExportable entity) {
super(entity);
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date now = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
String who = getCurrentAuditor();
if (entity == null) {
if (who != null) {
set("createdBy", who);
}
set("createdAt", now);
}
if (who != null) {
set("modifiedBy", who);
}
set("modifiedAt", now);
}
protected String getCurrentAuditor() {
return null;
}
public Date createdAt() {
return get("createdAt", Date.class);
}
}

View file

@ -1,202 +0,0 @@
package net.helenus.core;
import com.google.common.primitives.Primitives;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import net.helenus.core.reflect.DefaultPrimitiveTypes;
import net.helenus.core.reflect.Drafted;
import net.helenus.core.reflect.MapExportable;
import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.MappingUtil;
import org.apache.commons.lang3.SerializationUtils;
public abstract class AbstractEntityDraft<E> implements Drafted<E> {
private final MapExportable entity;
private final Map<String, Object> valuesMap;
private final Set<String> readSet;
private final Map<String, Object> mutationsMap = new HashMap<String, Object>();
public AbstractEntityDraft(MapExportable entity) {
this.entity = entity;
// Entities can mutate their map.
if (entity != null) {
this.valuesMap = entity.toMap(true);
this.readSet = entity.toReadSet();
} else {
this.valuesMap = new HashMap<String, Object>();
this.readSet = new HashSet<String>();
}
}
public abstract Class<E> getEntityClass();
public E build() {
return Helenus.map(getEntityClass(), toMap());
}
@SuppressWarnings("unchecked")
public <T> T get(Getter<T> getter, Class<?> returnType) {
return (T) get(this.<T>methodNameFor(getter), returnType);
}
@SuppressWarnings("unchecked")
public <T> T get(String key, Class<?> returnType) {
readSet.add(key);
T value = (T) mutationsMap.get(key);
if (value == null) {
value = (T) valuesMap.get(key);
if (value == null) {
if (Primitives.allPrimitiveTypes().contains(returnType)) {
DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(returnType);
if (type == null) {
throw new RuntimeException("unknown primitive type " + returnType);
}
return (T) type.getDefaultValue();
}
} else {
// Collections fetched from the valuesMap
if (value instanceof Collection) {
value = (T) SerializationUtils.<Serializable>clone((Serializable) value);
}
}
}
return value;
}
public <T> Object set(Getter<T> getter, Object value) {
HelenusProperty prop = MappingUtil.resolveMappingProperty(getter).getProperty();
String key = prop.getPropertyName();
HelenusValidator.INSTANCE.validate(prop, value);
if (key == null || value == null) {
return null;
}
mutationsMap.put(key, value);
return value;
}
public Object set(String key, Object value) {
if (key == null || value == null) {
return null;
}
mutationsMap.put(key, value);
return value;
}
public void put(String key, Object value) {
mutationsMap.put(key, value);
}
@SuppressWarnings("unchecked")
public <T> T mutate(Getter<T> getter, T value) {
return (T) mutate(this.<T>methodNameFor(getter), value);
}
public <T> T mutate(String key, T value) {
Objects.requireNonNull(key);
if (value != null) {
if (entity != null) {
T currentValue = this.<T>fetch(key);
if (!value.equals(currentValue)) {
mutationsMap.put(key, value);
return value;
}
} else {
mutationsMap.put(key, value);
}
}
return null;
}
private <T> String methodNameFor(Getter<T> getter) {
return MappingUtil.resolveMappingProperty(getter).getProperty().getPropertyName();
}
public <T> Object unset(Getter<T> getter) {
return unset(methodNameFor(getter));
}
public Object unset(String key) {
if (key != null) {
Object value = mutationsMap.get(key);
mutationsMap.put(key, null);
return value;
}
return null;
}
public <T> boolean reset(Getter<T> getter, T desiredValue) {
return this.<T>reset(this.<T>methodNameFor(getter), desiredValue);
}
private <T> T fetch(String key) {
T value = (T) mutationsMap.get(key);
if (value == null) {
value = (T) valuesMap.get(key);
}
return value;
}
public <T> boolean reset(String key, T desiredValue) {
if (key != null && desiredValue != null) {
@SuppressWarnings("unchecked")
T currentValue = (T) this.<T>fetch(key);
if (currentValue == null || !currentValue.equals(desiredValue)) {
set(key, desiredValue);
return true;
}
}
return false;
}
@Override
public Map<String, Object> toMap() {
return toMap(valuesMap);
}
public Map<String, Object> toMap(Map<String, Object> entityMap) {
Map<String, Object> combined;
if (entityMap != null && entityMap.size() > 0) {
combined = new HashMap<String, Object>(entityMap.size());
for (Map.Entry<String, Object> e : entityMap.entrySet()) {
combined.put(e.getKey(), e.getValue());
}
} else {
combined = new HashMap<String, Object>(mutationsMap.size());
}
for (String key : mutated()) {
combined.put(key, mutationsMap.get(key));
}
return combined;
}
@Override
public Set<String> mutated() {
return mutationsMap.keySet();
}
@Override
public Set<String> read() {
return readSet;
}
@Override
public String toString() {
return mutationsMap.toString();
}
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,118 +15,133 @@
*/ */
package net.helenus.core; package net.helenus.core;
import com.codahale.metrics.MetricRegistry;
import com.datastax.driver.core.*;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Table;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import net.helenus.core.cache.Facet;
import net.helenus.mapping.value.ColumnValuePreparer; import com.datastax.driver.core.schemabuilder.SchemaStatement;
import net.helenus.mapping.value.ColumnValueProvider;
import net.helenus.support.Either;
import net.helenus.support.HelenusException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.datastax.driver.core.*;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.google.common.util.concurrent.ListenableFuture;
import net.helenus.mapping.value.ColumnValuePreparer;
import net.helenus.mapping.value.ColumnValueProvider;
import net.helenus.support.HelenusException;
import javax.xml.validation.Schema;
public abstract class AbstractSessionOperations { public abstract class AbstractSessionOperations {
private static final Logger LOG = LoggerFactory.getLogger(AbstractSessionOperations.class); final Logger logger = LoggerFactory.getLogger(getClass());
public abstract Session currentSession(); abstract public Session currentSession();
public abstract String usingKeyspace(); abstract public String usingKeyspace();
public abstract boolean isShowCql(); abstract public boolean isShowCql();
public abstract boolean showValues(); abstract public PrintStream getPrintStream();
public abstract PrintStream getPrintStream(); abstract public Executor getExecutor();
public abstract Executor getExecutor(); abstract public SessionRepository getSessionRepository();
public abstract SessionRepository getSessionRepository(); abstract public ColumnValueProvider getValueProvider();
public abstract ColumnValueProvider getValueProvider(); abstract public ColumnValuePreparer getValuePreparer();
public abstract ColumnValuePreparer getValuePreparer(); public PreparedStatement prepare(RegularStatement statement) {
public abstract ConsistencyLevel getDefaultConsistencyLevel(); try {
public abstract boolean getDefaultQueryIdempotency(); log(statement, false);
public PreparedStatement prepare(RegularStatement statement) { return currentSession().prepare(statement);
try {
return currentSession().prepare(statement);
} catch (RuntimeException e) {
throw translateException(e);
}
}
public ListenableFuture<PreparedStatement> prepareAsync(RegularStatement statement) { } catch (RuntimeException e) {
try { throw translateException(e);
return currentSession().prepareAsync(statement); }
} catch (RuntimeException e) {
throw translateException(e);
}
}
public ResultSet execute(Statement statement) { }
return execute(statement, null, null);
}
public ResultSet execute(Statement statement, Stopwatch timer) { public ListenableFuture<PreparedStatement> prepareAsync(RegularStatement statement) {
return execute(statement, null, timer);
}
public ResultSet execute(Statement statement, UnitOfWork uow) { try {
return execute(statement, uow, null);
}
public ResultSet execute(Statement statement, UnitOfWork uow, Stopwatch timer) { log(statement, false);
return executeAsync(statement, uow, timer).getUninterruptibly();
}
public ResultSetFuture executeAsync(Statement statement) { return currentSession().prepareAsync(statement);
return executeAsync(statement, null, null);
}
public ResultSetFuture executeAsync(Statement statement, Stopwatch timer) { } catch (RuntimeException e) {
return executeAsync(statement, null, timer); throw translateException(e);
} }
public ResultSetFuture executeAsync(Statement statement, UnitOfWork uow) { }
return executeAsync(statement, uow, null);
}
public ResultSetFuture executeAsync(Statement statement, UnitOfWork uow, Stopwatch timer) { public ResultSet execute(Statement statement, boolean showValues) {
try {
return currentSession().executeAsync(statement);
} catch (RuntimeException e) {
throw translateException(e);
}
}
public MetricRegistry getMetricRegistry() { return executeAsync(statement, showValues).getUninterruptibly();
return null;
}
public void mergeCache(Table<String, String, Either<Object, List<Facet>>> uowCache) {} }
RuntimeException translateException(RuntimeException e) { public ResultSetFuture executeAsync(Statement statement, boolean showValues) {
if (e instanceof HelenusException) {
return e;
}
throw new HelenusException(e);
}
public Object checkCache(String tableName, List<Facet> facets) { try {
return null;
}
public void updateCache(Object pojo, List<Facet> facets) {} log(statement, showValues);
return currentSession().executeAsync(statement);
} catch (RuntimeException e) {
throw translateException(e);
}
}
void log(Statement statement, boolean showValues) {
if (logger.isInfoEnabled()) {
logger.info("Execute statement " + statement);
}
if (isShowCql()) {
if (statement instanceof BuiltStatement) {
BuiltStatement builtStatement = (BuiltStatement) statement;
if (showValues) {
RegularStatement regularStatement = builtStatement.setForceNoValues(true);
printCql(regularStatement.getQueryString());
} else {
printCql(builtStatement.getQueryString());
}
} else if (statement instanceof RegularStatement) {
RegularStatement regularStatement = (RegularStatement) statement;
printCql(regularStatement.getQueryString());
} else {
printCql(statement.toString());
}
}
}
public abstract void cache(String key, Object value);
RuntimeException translateException(RuntimeException e) {
if (e instanceof HelenusException) {
return e;
}
throw new HelenusException(e);
}
void printCql(String cql) {
getPrintStream().println(cql);
}
public void cacheEvict(List<Facet> facets) {}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,8 +16,5 @@
package net.helenus.core; package net.helenus.core;
public enum AutoDdl { public enum AutoDdl {
VALIDATE, VALIDATE, UPDATE, CREATE, CREATE_DROP;
UPDATE,
CREATE,
CREATE_DROP;
} }

View file

@ -1,27 +1,11 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core; package net.helenus.core;
public class ConflictingUnitOfWorkException extends Exception { public class ConflictingUnitOfWorkException extends Exception {
final UnitOfWork uow; final UnitOfWork uow;
ConflictingUnitOfWorkException(UnitOfWork uow) {
this.uow = uow;
}
ConflictingUnitOfWorkException(UnitOfWork uow) {
this.uow = uow;
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,15 +15,13 @@
*/ */
package net.helenus.core; package net.helenus.core;
import com.datastax.driver.core.Metadata;
import java.util.Optional; import java.util.Optional;
import com.datastax.driver.core.Metadata;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
public interface DslInstantiator { public interface DslInstantiator {
<E> E instantiate( <E> E instantiate(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent, Metadata metadata);
Class<E> iface,
ClassLoader classLoader,
Optional<HelenusPropertyNode> parent,
Metadata metadata);
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,108 +15,99 @@
*/ */
package net.helenus.core; package net.helenus.core;
import com.datastax.driver.core.querybuilder.Clause;
import java.util.Objects; import java.util.Objects;
import com.datastax.driver.core.querybuilder.Clause;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.MappingUtil; import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.value.ColumnValuePreparer; import net.helenus.mapping.value.ColumnValuePreparer;
public final class Filter<V> { public final class Filter<V> {
private final HelenusPropertyNode node; private final HelenusPropertyNode node;
private final Postulate<V> postulate; private final Postulate<V> postulate;
private Filter(HelenusPropertyNode node, Postulate<V> postulate) { private Filter(HelenusPropertyNode node, Postulate<V> postulate) {
this.node = node; this.node = node;
this.postulate = postulate; this.postulate = postulate;
} }
public static <V> Filter<V> equal(Getter<V> getter, V val) { public HelenusPropertyNode getNode() {
return create(getter, Operator.EQ, val); return node;
} }
public static <V> Filter<V> in(Getter<V> getter, V... vals) { public Clause getClause(ColumnValuePreparer valuePreparer) {
Objects.requireNonNull(getter, "empty getter"); return postulate.getClause(node, valuePreparer);
Objects.requireNonNull(vals, "empty values"); }
if (vals.length == 0) { public static <V> Filter<V> equal(Getter<V> getter, V val) {
throw new IllegalArgumentException("values array is empty"); return create(getter, Operator.EQ, val);
} }
for (int i = 0; i != vals.length; ++i) { public static <V> Filter<V> in(Getter<V> getter, V... vals) {
Objects.requireNonNull(vals[i], "value[" + i + "] is empty"); Objects.requireNonNull(getter, "empty getter");
} Objects.requireNonNull(vals, "empty values");
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter); if (vals.length == 0) {
throw new IllegalArgumentException("values array is empty");
}
Postulate<V> postulate = Postulate.of(Operator.IN, vals); for (int i = 0; i != vals.length; ++i) {
Objects.requireNonNull(vals[i], "value[" + i + "] is empty");
}
return new Filter<V>(node, postulate); HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
}
public static <V> Filter<V> greaterThan(Getter<V> getter, V val) { Postulate<V> postulate = Postulate.of(Operator.IN, vals);
return create(getter, Operator.GT, val);
}
public static <V> Filter<V> lessThan(Getter<V> getter, V val) { return new Filter<V>(node, postulate);
return create(getter, Operator.LT, val); }
}
public static <V> Filter<V> greaterThanOrEqual(Getter<V> getter, V val) { public static <V> Filter<V> greaterThan(Getter<V> getter, V val) {
return create(getter, Operator.GTE, val); return create(getter, Operator.GT, val);
} }
public static <V> Filter<V> lessThanOrEqual(Getter<V> getter, V val) { public static <V> Filter<V> lessThan(Getter<V> getter, V val) {
return create(getter, Operator.LTE, val); return create(getter, Operator.LT, val);
} }
public static <V> Filter<V> create(Getter<V> getter, Postulate<V> postulate) { public static <V> Filter<V> greaterThanOrEqual(Getter<V> getter, V val) {
Objects.requireNonNull(getter, "empty getter"); return create(getter, Operator.GTE, val);
Objects.requireNonNull(postulate, "empty operator"); }
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter); public static <V> Filter<V> lessThanOrEqual(Getter<V> getter, V val) {
return create(getter, Operator.LTE, val);
}
return new Filter<V>(node, postulate); public static <V> Filter<V> create(Getter<V> getter, Postulate<V> postulate) {
} Objects.requireNonNull(getter, "empty getter");
Objects.requireNonNull(postulate, "empty operator");
public static <V> Filter<V> create( HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
Getter<V> getter, HelenusPropertyNode node, Postulate<V> postulate) {
Objects.requireNonNull(getter, "empty getter");
Objects.requireNonNull(postulate, "empty operator");
return new Filter<V>(node, postulate);
}
public static <V> Filter<V> create(Getter<V> getter, Operator op, V val) { return new Filter<V>(node, postulate);
Objects.requireNonNull(getter, "empty getter"); }
Objects.requireNonNull(op, "empty op");
Objects.requireNonNull(val, "empty value");
if (op == Operator.IN) { public static <V> Filter<V> create(Getter<V> getter, Operator op, V val) {
throw new IllegalArgumentException( Objects.requireNonNull(getter, "empty getter");
"invalid usage of the 'in' operator, use Filter.in() static method"); Objects.requireNonNull(op, "empty op");
} Objects.requireNonNull(val, "empty value");
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter); if (op == Operator.IN) {
throw new IllegalArgumentException("invalid usage of the 'in' operator, use Filter.in() static method");
}
Postulate<V> postulate = Postulate.of(op, val); HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
return new Filter<V>(node, postulate); Postulate<V> postulate = Postulate.of(op, val);
}
public HelenusPropertyNode getNode() { return new Filter<V>(node, postulate);
return node; }
}
public Clause getClause(ColumnValuePreparer valuePreparer) { @Override
return postulate.getClause(node, valuePreparer); public String toString() {
} return node.getColumnName() + postulate.toString();
}
public V[] postulateValues() {
return postulate.values();
}
@Override
public String toString() {
return node.getColumnName() + postulate.toString();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,5 +17,6 @@ package net.helenus.core;
public interface Getter<V> { public interface Getter<V> {
V get(); V get();
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,15 +15,14 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Metadata; import com.datastax.driver.core.Metadata;
import com.datastax.driver.core.Session; import com.datastax.driver.core.Session;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import net.helenus.config.DefaultHelenusSettings; import net.helenus.config.DefaultHelenusSettings;
import net.helenus.config.HelenusSettings; import net.helenus.config.HelenusSettings;
import net.helenus.core.reflect.DslExportable; import net.helenus.core.reflect.DslExportable;
@ -34,170 +32,156 @@ import net.helenus.support.HelenusMappingException;
public final class Helenus { public final class Helenus {
private static final ConcurrentMap<Class<?>, Object> dslCache = private static volatile HelenusSettings settings = new DefaultHelenusSettings();
new ConcurrentHashMap<Class<?>, Object>(); private static final ConcurrentMap<Class<?>, Object> dslCache = new ConcurrentHashMap<Class<?>, Object>();
private static final ConcurrentMap<Class<?>, Metadata> metadataForEntity = private static final ConcurrentMap<Class<?>, Metadata> metadataForEntity = new ConcurrentHashMap<Class<?>, Metadata>();
new ConcurrentHashMap<Class<?>, Metadata>(); private static final Set<HelenusSession> sessions = new HashSet<HelenusSession>();
private static final Set<HelenusSession> sessions = new HashSet<HelenusSession>(); private static volatile HelenusSession singleton;
private static volatile HelenusSettings settings = new DefaultHelenusSettings();
private static volatile HelenusSession singleton;
private Helenus() {}
protected static void setSession(HelenusSession session) { private Helenus() {
sessions.add(session); }
singleton = session;
}
public static HelenusSession session() { protected static void setSession(HelenusSession session) {
return singleton; sessions.add(session);
} singleton = session;
}
public static void shutdown() { public static HelenusSession session() {
sessions.forEach( return singleton;
(session) -> { }
session.close();
sessions.remove(session); public static void shutdown() {
sessions.forEach((session) -> {
session.close();
sessions.remove(session);
}); });
dslCache.clear(); dslCache.clear();
}
public static HelenusSettings settings() {
return settings;
}
public static HelenusSettings settings(HelenusSettings overrideSettings) {
HelenusSettings old = settings;
settings = overrideSettings;
return old;
}
public static SessionInitializer connect(Cluster cluster) {
Session session = cluster.connect();
return new SessionInitializer(session);
}
public static SessionInitializer connect(Cluster cluster, String keyspace) {
Session session = cluster.connect(keyspace);
return new SessionInitializer(session);
}
public static SessionInitializer init(Session session, String keyspace) {
return new SessionInitializer(session, keyspace);
}
public static SessionInitializer init(Session session) {
if (session == null) {
throw new IllegalArgumentException("empty session");
} }
return new SessionInitializer(session); public static HelenusSettings settings() {
} return settings;
public static void clearDslCache() {
dslCache.clear();
}
public static <E> E dsl(Class<E> iface) {
return dsl(iface, null);
}
public static <E> E dsl(Class<E> iface, Metadata metadata) {
return dsl(iface, iface.getClassLoader(), Optional.empty(), metadata);
}
public static <E> E dsl(Class<E> iface, ClassLoader classLoader, Metadata metadata) {
return dsl(iface, classLoader, Optional.empty(), metadata);
}
public static <E> E dsl(
Class<E> iface,
ClassLoader classLoader,
Optional<HelenusPropertyNode> parent,
Metadata metadata) {
Object instance = null;
if (!parent.isPresent()) {
instance = dslCache.get(iface);
} }
if (instance == null) { public static HelenusSettings settings(HelenusSettings overrideSettings) {
HelenusSettings old = settings;
settings = overrideSettings;
return old;
}
instance = settings.getDslInstantiator().instantiate(iface, classLoader, parent, metadata); public static SessionInitializer connect(Cluster cluster) {
Session session = cluster.connect();
return new SessionInitializer(session);
}
if (!parent.isPresent()) { public static SessionInitializer connect(Cluster cluster, String keyspace) {
Session session = cluster.connect(keyspace);
return new SessionInitializer(session);
}
Object c = dslCache.putIfAbsent(iface, instance); public static SessionInitializer init(Session session) {
if (c != null) {
instance = c; if (session == null) {
throw new IllegalArgumentException("empty session");
} }
}
return new SessionInitializer(session);
} }
return (E) instance; public static void clearDslCache() {
} dslCache.clear();
public static <E> E map(Class<E> iface, Map<String, Object> src) {
return map(iface, src, iface.getClassLoader());
}
public static <E> E map(Class<E> iface, Map<String, Object> src, ClassLoader classLoader) {
return settings.getMapperInstantiator().instantiate(iface, src, classLoader);
}
public static HelenusEntity entity(Class<?> iface) {
Metadata metadata = metadataForEntity.get(iface);
if (metadata == null) {
HelenusSession session = session();
if (session != null) {
metadata = session.getMetadata();
}
}
return entity(iface, metadata);
}
public static HelenusEntity entity(Class<?> iface, Metadata metadata) {
Object dsl = dsl(iface, metadata);
DslExportable e = (DslExportable) dsl;
return e.getHelenusMappingEntity();
}
public static HelenusEntity resolve(Object ifaceOrDsl) {
return resolve(ifaceOrDsl, metadataForEntity.get(ifaceOrDsl));
}
public static HelenusEntity resolve(Object ifaceOrDsl, Metadata metadata) {
if (ifaceOrDsl == null) {
throw new HelenusMappingException("ifaceOrDsl is null");
} }
if (ifaceOrDsl instanceof DslExportable) { public static <E> E dsl(Class<E> iface) {
return dsl(iface, null);
DslExportable e = (DslExportable) ifaceOrDsl;
return e.getHelenusMappingEntity();
} }
if (ifaceOrDsl instanceof Class) { public static <E> E dsl(Class<E> iface, Metadata metadata) {
return dsl(iface, iface.getClassLoader(), Optional.empty(), metadata);
Class<?> iface = (Class<?>) ifaceOrDsl;
if (!iface.isInterface()) {
throw new HelenusMappingException("class is not an interface " + iface);
}
if (metadata != null) {
metadataForEntity.putIfAbsent(iface, metadata);
}
return entity(iface, metadata);
} }
throw new HelenusMappingException("unknown dsl object or mapping interface " + ifaceOrDsl); public static <E> E dsl(Class<E> iface, ClassLoader classLoader, Metadata metadata) {
} return dsl(iface, classLoader, Optional.empty(), metadata);
}
public static <E> E dsl(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent,
Metadata metadata) {
Object instance = null;
if (!parent.isPresent()) {
instance = dslCache.get(iface);
}
if (instance == null) {
instance = settings.getDslInstantiator().instantiate(iface, classLoader, parent, metadata);
if (!parent.isPresent()) {
Object c = dslCache.putIfAbsent(iface, instance);
if (c != null) {
instance = c;
}
}
}
return (E) instance;
}
public static <E> E map(Class<E> iface, Map<String, Object> src) {
return map(iface, src, iface.getClassLoader());
}
public static <E> E map(Class<E> iface, Map<String, Object> src, ClassLoader classLoader) {
return settings.getMapperInstantiator().instantiate(iface, src, classLoader);
}
public static HelenusEntity entity(Class<?> iface) {
return entity(iface, metadataForEntity.get(iface));
}
public static HelenusEntity entity(Class<?> iface, Metadata metadata) {
Object dsl = dsl(iface, metadata);
DslExportable e = (DslExportable) dsl;
return e.getHelenusMappingEntity();
}
public static HelenusEntity resolve(Object ifaceOrDsl) {
return resolve(ifaceOrDsl, metadataForEntity.get(ifaceOrDsl));
}
public static HelenusEntity resolve(Object ifaceOrDsl, Metadata metadata) {
if (ifaceOrDsl == null) {
throw new HelenusMappingException("ifaceOrDsl is null");
}
if (ifaceOrDsl instanceof DslExportable) {
DslExportable e = (DslExportable) ifaceOrDsl;
return e.getHelenusMappingEntity();
}
if (ifaceOrDsl instanceof Class) {
Class<?> iface = (Class<?>) ifaceOrDsl;
if (!iface.isInterface()) {
throw new HelenusMappingException("class is not an interface " + iface);
}
metadataForEntity.putIfAbsent(iface, metadata);
return entity(iface, metadata);
}
throw new HelenusMappingException("unknown dsl object or mapping interface " + ifaceOrDsl);
}
} }

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,32 +16,36 @@
package net.helenus.core; package net.helenus.core;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidator;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public enum HelenusValidator implements PropertyValueValidator { public enum HelenusValidator implements PropertyValueValidator {
INSTANCE;
public void validate(HelenusProperty prop, Object value) { INSTANCE;
for (ConstraintValidator<? extends Annotation, ?> validator : prop.getValidators()) { public void validate(HelenusProperty prop, Object value) {
ConstraintValidator typeless = (ConstraintValidator) validator; for (ConstraintValidator<? extends Annotation, ?> validator : prop.getValidators()) {
boolean valid = false; ConstraintValidator typeless = (ConstraintValidator) validator;
try { boolean valid = false;
valid = typeless.isValid(value, null);
} catch (ClassCastException e) { try {
throw new HelenusMappingException( valid = typeless.isValid(value, null);
"validator was used for wrong type '" + value + "' in " + prop, e); } catch (ClassCastException e) {
} throw new HelenusMappingException("validator was used for wrong type '" + value + "' in " + prop, e);
}
if (!valid) {
throw new HelenusException("wrong value '" + value + "' for " + prop);
}
}
}
if (!valid) {
throw new HelenusException("wrong value '" + value + "' for " + prop);
}
}
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,5 +19,6 @@ import java.util.Map;
public interface MapperInstantiator { public interface MapperInstantiator {
<E> E instantiate(Class<E> iface, Map<String, Object> src, ClassLoader classLoader); <E> E instantiate(Class<E> iface, Map<String, Object> src, ClassLoader classLoader);
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,8 +15,10 @@
*/ */
package net.helenus.core; package net.helenus.core;
import com.datastax.driver.core.Row;
import java.util.function.Function; import java.util.function.Function;
import com.datastax.driver.core.Row;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.value.ColumnValueProvider; import net.helenus.mapping.value.ColumnValueProvider;
@ -25,203 +26,162 @@ import net.helenus.support.Fun;
public final class Mappers { public final class Mappers {
private Mappers() {} private Mappers() {
}
public static final class Mapper1<A> implements Function<Row, Fun.Tuple1<A>> { public final static class Mapper1<A> implements Function<Row, Fun.Tuple1<A>> {
private final ColumnValueProvider provider; private final ColumnValueProvider provider;
private final HelenusProperty p1; private final HelenusProperty p1;
public Mapper1(ColumnValueProvider provider, HelenusPropertyNode p1) { public Mapper1(ColumnValueProvider provider, HelenusPropertyNode p1) {
this.provider = provider; this.provider = provider;
this.p1 = p1.getProperty(); this.p1 = p1.getProperty();
} }
@Override @Override
public Fun.Tuple1<A> apply(Row row) { public Fun.Tuple1<A> apply(Row row) {
return new Fun.Tuple1<A>(provider.getColumnValue(row, 0, p1)); return new Fun.Tuple1<A>(provider.getColumnValue(row, 0, p1));
} }
} }
public static final class Mapper2<A, B> implements Function<Row, Fun.Tuple2<A, B>> { public final static class Mapper2<A, B> implements Function<Row, Fun.Tuple2<A, B>> {
private final ColumnValueProvider provider; private final ColumnValueProvider provider;
private final HelenusProperty p1; private final HelenusProperty p1;
private final HelenusProperty p2; private final HelenusProperty p2;
public Mapper2(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2) { public Mapper2(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2) {
this.provider = provider; this.provider = provider;
this.p1 = p1.getProperty(); this.p1 = p1.getProperty();
this.p2 = p2.getProperty(); this.p2 = p2.getProperty();
} }
@Override @Override
public Fun.Tuple2<A, B> apply(Row row) { public Fun.Tuple2<A, B> apply(Row row) {
return new Fun.Tuple2<A, B>( return new Fun.Tuple2<A, B>(provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2));
provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2)); }
} }
}
public static final class Mapper3<A, B, C> implements Function<Row, Fun.Tuple3<A, B, C>> { public final static class Mapper3<A, B, C> implements Function<Row, Fun.Tuple3<A, B, C>> {
private final ColumnValueProvider provider; private final ColumnValueProvider provider;
private final HelenusProperty p1; private final HelenusProperty p1;
private final HelenusProperty p2; private final HelenusProperty p2;
private final HelenusProperty p3; private final HelenusProperty p3;
public Mapper3( public Mapper3(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
ColumnValueProvider provider, HelenusPropertyNode p3) {
HelenusPropertyNode p1, this.provider = provider;
HelenusPropertyNode p2, this.p1 = p1.getProperty();
HelenusPropertyNode p3) { this.p2 = p2.getProperty();
this.provider = provider; this.p3 = p3.getProperty();
this.p1 = p1.getProperty(); }
this.p2 = p2.getProperty();
this.p3 = p3.getProperty();
}
@Override @Override
public Fun.Tuple3<A, B, C> apply(Row row) { public Fun.Tuple3<A, B, C> apply(Row row) {
return new Fun.Tuple3<A, B, C>( return new Fun.Tuple3<A, B, C>(provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2),
provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 2, p3));
provider.getColumnValue(row, 1, p2), }
provider.getColumnValue(row, 2, p3)); }
}
}
public static final class Mapper4<A, B, C, D> implements Function<Row, Fun.Tuple4<A, B, C, D>> { public final static class Mapper4<A, B, C, D> implements Function<Row, Fun.Tuple4<A, B, C, D>> {
private final ColumnValueProvider provider; private final ColumnValueProvider provider;
private final HelenusProperty p1; private final HelenusProperty p1;
private final HelenusProperty p2; private final HelenusProperty p2;
private final HelenusProperty p3; private final HelenusProperty p3;
private final HelenusProperty p4; private final HelenusProperty p4;
public Mapper4( public Mapper4(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
ColumnValueProvider provider, HelenusPropertyNode p3, HelenusPropertyNode p4) {
HelenusPropertyNode p1, this.provider = provider;
HelenusPropertyNode p2, this.p1 = p1.getProperty();
HelenusPropertyNode p3, this.p2 = p2.getProperty();
HelenusPropertyNode p4) { this.p3 = p3.getProperty();
this.provider = provider; this.p4 = p4.getProperty();
this.p1 = p1.getProperty(); }
this.p2 = p2.getProperty();
this.p3 = p3.getProperty();
this.p4 = p4.getProperty();
}
@Override @Override
public Fun.Tuple4<A, B, C, D> apply(Row row) { public Fun.Tuple4<A, B, C, D> apply(Row row) {
return new Fun.Tuple4<A, B, C, D>( return new Fun.Tuple4<A, B, C, D>(provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2),
provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 2, p3), provider.getColumnValue(row, 3, p4));
provider.getColumnValue(row, 1, p2), }
provider.getColumnValue(row, 2, p3), }
provider.getColumnValue(row, 3, p4));
}
}
public static final class Mapper5<A, B, C, D, E> public final static class Mapper5<A, B, C, D, E> implements Function<Row, Fun.Tuple5<A, B, C, D, E>> {
implements Function<Row, Fun.Tuple5<A, B, C, D, E>> {
private final ColumnValueProvider provider; private final ColumnValueProvider provider;
private final HelenusProperty p1, p2, p3, p4, p5; private final HelenusProperty p1, p2, p3, p4, p5;
public Mapper5( public Mapper5(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
ColumnValueProvider provider, HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5) {
HelenusPropertyNode p1, this.provider = provider;
HelenusPropertyNode p2, this.p1 = p1.getProperty();
HelenusPropertyNode p3, this.p2 = p2.getProperty();
HelenusPropertyNode p4, this.p3 = p3.getProperty();
HelenusPropertyNode p5) { this.p4 = p4.getProperty();
this.provider = provider; this.p5 = p5.getProperty();
this.p1 = p1.getProperty(); }
this.p2 = p2.getProperty();
this.p3 = p3.getProperty();
this.p4 = p4.getProperty();
this.p5 = p5.getProperty();
}
@Override @Override
public Fun.Tuple5<A, B, C, D, E> apply(Row row) { public Fun.Tuple5<A, B, C, D, E> apply(Row row) {
return new Fun.Tuple5<A, B, C, D, E>( return new Fun.Tuple5<A, B, C, D, E>(provider.getColumnValue(row, 0, p1),
provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2), provider.getColumnValue(row, 2, p3),
provider.getColumnValue(row, 1, p2), provider.getColumnValue(row, 3, p4), provider.getColumnValue(row, 4, p5));
provider.getColumnValue(row, 2, p3), }
provider.getColumnValue(row, 3, p4), }
provider.getColumnValue(row, 4, p5));
}
}
public static final class Mapper6<A, B, C, D, E, F> public final static class Mapper6<A, B, C, D, E, F> implements Function<Row, Fun.Tuple6<A, B, C, D, E, F>> {
implements Function<Row, Fun.Tuple6<A, B, C, D, E, F>> {
private final ColumnValueProvider provider; private final ColumnValueProvider provider;
private final HelenusProperty p1, p2, p3, p4, p5, p6; private final HelenusProperty p1, p2, p3, p4, p5, p6;
public Mapper6( public Mapper6(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
ColumnValueProvider provider, HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5, HelenusPropertyNode p6) {
HelenusPropertyNode p1, this.provider = provider;
HelenusPropertyNode p2, this.p1 = p1.getProperty();
HelenusPropertyNode p3, this.p2 = p2.getProperty();
HelenusPropertyNode p4, this.p3 = p3.getProperty();
HelenusPropertyNode p5, this.p4 = p4.getProperty();
HelenusPropertyNode p6) { this.p5 = p5.getProperty();
this.provider = provider; this.p6 = p6.getProperty();
this.p1 = p1.getProperty(); }
this.p2 = p2.getProperty();
this.p3 = p3.getProperty();
this.p4 = p4.getProperty();
this.p5 = p5.getProperty();
this.p6 = p6.getProperty();
}
@Override @Override
public Fun.Tuple6<A, B, C, D, E, F> apply(Row row) { public Fun.Tuple6<A, B, C, D, E, F> apply(Row row) {
return new Fun.Tuple6<A, B, C, D, E, F>( return new Fun.Tuple6<A, B, C, D, E, F>(provider.getColumnValue(row, 0, p1),
provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2), provider.getColumnValue(row, 2, p3),
provider.getColumnValue(row, 1, p2), provider.getColumnValue(row, 3, p4), provider.getColumnValue(row, 4, p5),
provider.getColumnValue(row, 2, p3), provider.getColumnValue(row, 5, p6));
provider.getColumnValue(row, 3, p4), }
provider.getColumnValue(row, 4, p5), }
provider.getColumnValue(row, 5, p6));
}
}
public static final class Mapper7<A, B, C, D, E, F, G> public final static class Mapper7<A, B, C, D, E, F, G> implements Function<Row, Fun.Tuple7<A, B, C, D, E, F, G>> {
implements Function<Row, Fun.Tuple7<A, B, C, D, E, F, G>> {
private final ColumnValueProvider provider; private final ColumnValueProvider provider;
private final HelenusProperty p1, p2, p3, p4, p5, p6, p7; private final HelenusProperty p1, p2, p3, p4, p5, p6, p7;
public Mapper7( public Mapper7(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
ColumnValueProvider provider, HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5, HelenusPropertyNode p6,
HelenusPropertyNode p1, HelenusPropertyNode p7) {
HelenusPropertyNode p2, this.provider = provider;
HelenusPropertyNode p3, this.p1 = p1.getProperty();
HelenusPropertyNode p4, this.p2 = p2.getProperty();
HelenusPropertyNode p5, this.p3 = p3.getProperty();
HelenusPropertyNode p6, this.p4 = p4.getProperty();
HelenusPropertyNode p7) { this.p5 = p5.getProperty();
this.provider = provider; this.p6 = p6.getProperty();
this.p1 = p1.getProperty(); this.p7 = p7.getProperty();
this.p2 = p2.getProperty(); }
this.p3 = p3.getProperty();
this.p4 = p4.getProperty(); @Override
this.p5 = p5.getProperty(); public Fun.Tuple7<A, B, C, D, E, F, G> apply(Row row) {
this.p6 = p6.getProperty(); return new Fun.Tuple7<A, B, C, D, E, F, G>(provider.getColumnValue(row, 0, p1),
this.p7 = p7.getProperty(); provider.getColumnValue(row, 1, p2), provider.getColumnValue(row, 2, p3),
} provider.getColumnValue(row, 3, p4), provider.getColumnValue(row, 4, p5),
provider.getColumnValue(row, 5, p6), provider.getColumnValue(row, 6, p7));
}
}
@Override
public Fun.Tuple7<A, B, C, D, E, F, G> apply(Row row) {
return new Fun.Tuple7<A, B, C, D, E, F, G>(
provider.getColumnValue(row, 0, p1),
provider.getColumnValue(row, 1, p2),
provider.getColumnValue(row, 2, p3),
provider.getColumnValue(row, 3, p4),
provider.getColumnValue(row, 4, p5),
provider.getColumnValue(row, 5, p6),
provider.getColumnValue(row, 6, p7));
}
}
} }

View file

@ -0,0 +1,109 @@
/*
* Copyright 2016 Ben Manes. All Rights Reserved.
*
* 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.
*/
package net.helenus.core;
import static java.util.Objects.requireNonNull;
import java.util.concurrent.TimeUnit;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.github.benmanes.caffeine.cache.stats.CacheStats;
import com.github.benmanes.caffeine.cache.stats.StatsCounter;
/**
* A {@link StatsCounter} instrumented with Dropwizard Metrics.
*
* @author ben.manes@gmail.com (Ben Manes)
*/
public final class MetricsStatsCounter implements StatsCounter {
private final Meter hitCount;
private final Meter missCount;
private final Meter loadSuccessCount;
private final Meter loadFailureCount;
private final Timer totalLoadTime;
private final Meter evictionCount;
private final Meter evictionWeight;
/**
* Constructs an instance for use by a single cache.
*
* @param registry the registry of metric instances
* @param metricsPrefix the prefix name for the metrics
*/
public MetricsStatsCounter(MetricRegistry registry, String metricsPrefix) {
requireNonNull(metricsPrefix);
hitCount = registry.meter(metricsPrefix + ".hits");
missCount = registry.meter(metricsPrefix + ".misses");
totalLoadTime = registry.timer(metricsPrefix + ".loads");
loadSuccessCount = registry.meter(metricsPrefix + ".loads-success");
loadFailureCount = registry.meter(metricsPrefix + ".loads-failure");
evictionCount = registry.meter(metricsPrefix + ".evictions");
evictionWeight = registry.meter(metricsPrefix + ".evictions-weight");
}
@Override
public void recordHits(int count) {
hitCount.mark(count);
}
@Override
public void recordMisses(int count) {
missCount.mark(count);
}
@Override
public void recordLoadSuccess(long loadTime) {
loadSuccessCount.mark();
totalLoadTime.update(loadTime, TimeUnit.NANOSECONDS);
}
@Override
public void recordLoadFailure(long loadTime) {
loadFailureCount.mark();
totalLoadTime.update(loadTime, TimeUnit.NANOSECONDS);
}
@Override
public void recordEviction() {
// This method is scheduled for removal in version 3.0 in favor of recordEviction(weight)
recordEviction(1);
}
@Override
public void recordEviction(int weight) {
evictionCount.mark();
evictionWeight.mark(weight);
}
@Override
public CacheStats snapshot() {
return new CacheStats(
hitCount.getCount(),
missCount.getCount(),
loadSuccessCount.getCount(),
loadFailureCount.getCount(),
totalLoadTime.getCount(),
evictionCount.getCount(),
evictionWeight.getCount());
}
@Override
public String toString() {
return snapshot().toString();
}
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,37 +19,39 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public enum Operator { public enum Operator {
EQ("=="),
IN("in"), EQ("=="),
GT(">"), IN("in"),
LT("<"), GT(">"),
GTE(">="), LT("<"),
LTE("<="); GTE(">="),
private static final Map<String, Operator> indexByName = new HashMap<String, Operator>(); LTE("<=");
static { private final String name;
for (Operator fo : Operator.values()) {
indexByName.put(fo.getName(), fo);
}
}
private final String name; private final static Map<String, Operator> indexByName = new HashMap<String, Operator>();
private Operator(String name) { static {
this.name = name; for (Operator fo : Operator.values()) {
} indexByName.put(fo.getName(), fo);
}
}
public static Operator findByOperator(String name) { private Operator(String name) {
return indexByName.get(name); this.name = name;
} }
public String getName() {
return name;
}
public static Operator findByOperator(String name) {
return indexByName.get(name);
}
public String getName() {
return name;
}
} }

View file

@ -1,8 +1,10 @@
package net.helenus.core; package net.helenus.core;
import java.util.Objects;
import com.datastax.driver.core.querybuilder.Ordering; import com.datastax.driver.core.querybuilder.Ordering;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import java.util.Objects;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.ColumnType; import net.helenus.mapping.ColumnType;
import net.helenus.mapping.MappingUtil; import net.helenus.mapping.MappingUtil;
@ -11,34 +13,37 @@ import net.helenus.support.HelenusMappingException;
public final class Ordered { public final class Ordered {
private final Getter<?> getter; private final Getter<?> getter;
private final OrderingDirection direction; private final OrderingDirection direction;
public Ordered(Getter<?> getter, OrderingDirection direction) { public Ordered(Getter<?> getter, OrderingDirection direction) {
this.getter = getter; this.getter = getter;
this.direction = direction; this.direction = direction;
} }
public Ordering getOrdering() { public Ordering getOrdering() {
Objects.requireNonNull(getter, "property is null"); Objects.requireNonNull(getter, "property is null");
Objects.requireNonNull(direction, "direction is null"); Objects.requireNonNull(direction, "direction is null");
HelenusPropertyNode propNode = MappingUtil.resolveMappingProperty(getter); HelenusPropertyNode propNode = MappingUtil.resolveMappingProperty(getter);
if (propNode.getProperty().getColumnType() != ColumnType.CLUSTERING_COLUMN) { if (propNode.getProperty().getColumnType() != ColumnType.CLUSTERING_COLUMN) {
throw new HelenusMappingException( throw new HelenusMappingException(
"property must be a clustering column " + propNode.getProperty().getPropertyName()); "property must be a clustering column " + propNode.getProperty().getPropertyName());
} }
switch (direction) { switch (direction) {
case ASC:
return QueryBuilder.asc(propNode.getColumnName());
case DESC: case ASC :
return QueryBuilder.desc(propNode.getColumnName()); return QueryBuilder.asc(propNode.getColumnName());
}
case DESC :
return QueryBuilder.desc(propNode.getColumnName());
}
throw new HelenusMappingException("invalid direction " + direction);
}
throw new HelenusMappingException("invalid direction " + direction);
}
} }

View file

@ -1,78 +0,0 @@
package net.helenus.core;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import net.helenus.support.CheckedRunnable;
public class PostCommitFunction<T, R> implements java.util.function.Function<T, R> {
public static final PostCommitFunction<Void, Void> NULL_ABORT = new PostCommitFunction<Void, Void>(null, null, null, false);
public static final PostCommitFunction<Void, Void> NULL_COMMIT = new PostCommitFunction<Void, Void>(null, null, null, true);
private final List<CheckedRunnable> commitThunks;
private final List<CheckedRunnable> abortThunks;
private Consumer<? super Throwable> exceptionallyThunk;
private boolean committed;
PostCommitFunction(List<CheckedRunnable> postCommit, List<CheckedRunnable> abortThunks,
Consumer<? super Throwable> exceptionallyThunk,
boolean committed) {
this.commitThunks = postCommit;
this.abortThunks = abortThunks;
this.exceptionallyThunk = exceptionallyThunk;
this.committed = committed;
}
private void apply(CheckedRunnable... fns) {
try {
for (CheckedRunnable fn : fns) {
fn.run();
}
} catch (Throwable t) {
if (exceptionallyThunk != null) {
exceptionallyThunk.accept(t);
}
}
}
public PostCommitFunction<T, R> andThen(CheckedRunnable... after) {
Objects.requireNonNull(after);
if (commitThunks == null) {
if (committed) {
apply(after);
}
} else {
for (CheckedRunnable fn : after) {
commitThunks.add(fn);
}
}
return this;
}
public PostCommitFunction<T, R> orElse(CheckedRunnable... after) {
Objects.requireNonNull(after);
if (abortThunks == null) {
if (!committed) {
apply(after);
}
} else {
for (CheckedRunnable fn : after) {
abortThunks.add(fn);
}
}
return this;
}
public PostCommitFunction<T, R> exceptionally(Consumer<? super Throwable> fn) {
Objects.requireNonNull(fn);
exceptionallyThunk = fn;
return this;
}
@Override
public R apply(T t) {
return null;
}
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,84 +17,86 @@ package net.helenus.core;
import com.datastax.driver.core.querybuilder.Clause; import com.datastax.driver.core.querybuilder.Clause;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.value.ColumnValuePreparer; import net.helenus.mapping.value.ColumnValuePreparer;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public final class Postulate<V> { public final class Postulate<V> {
private final Operator operator; private final Operator operator;
private final V[] values; private final V[] values;
protected Postulate(Operator op, V[] values) { protected Postulate(Operator op, V[] values) {
this.operator = op; this.operator = op;
this.values = values; this.values = values;
} }
public static <V> Postulate<V> of(Operator op, V... values) { public static <V> Postulate<V> of(Operator op, V... values) {
return new Postulate<V>(op, values); return new Postulate<V>(op, values);
} }
public Clause getClause(HelenusPropertyNode node, ColumnValuePreparer valuePreparer) { public Clause getClause(HelenusPropertyNode node, ColumnValuePreparer valuePreparer) {
switch (operator) { switch (operator) {
case EQ:
return QueryBuilder.eq(
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
case IN: case EQ :
Object[] preparedValues = new Object[values.length]; return QueryBuilder.eq(node.getColumnName(),
for (int i = 0; i != values.length; ++i) { valuePreparer.prepareColumnValue(values[0], node.getProperty()));
preparedValues[i] = valuePreparer.prepareColumnValue(values[i], node.getProperty());
}
return QueryBuilder.in(node.getColumnName(), preparedValues);
case LT: case IN :
return QueryBuilder.lt( Object[] preparedValues = new Object[values.length];
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty())); for (int i = 0; i != values.length; ++i) {
preparedValues[i] = valuePreparer.prepareColumnValue(values[i], node.getProperty());
}
return QueryBuilder.in(node.getColumnName(), preparedValues);
case LTE: case LT :
return QueryBuilder.lte( return QueryBuilder.lt(node.getColumnName(),
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty())); valuePreparer.prepareColumnValue(values[0], node.getProperty()));
case GT: case LTE :
return QueryBuilder.gt( return QueryBuilder.lte(node.getColumnName(),
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty())); valuePreparer.prepareColumnValue(values[0], node.getProperty()));
case GTE: case GT :
return QueryBuilder.gte( return QueryBuilder.gt(node.getColumnName(),
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty())); valuePreparer.prepareColumnValue(values[0], node.getProperty()));
default: case GTE :
throw new HelenusMappingException("unknown filter operation " + operator); return QueryBuilder.gte(node.getColumnName(),
} valuePreparer.prepareColumnValue(values[0], node.getProperty()));
}
public V[] values() { default :
return values; throw new HelenusMappingException("unknown filter operation " + operator);
} }
@Override }
public String toString() {
if (operator == Operator.IN) { @Override
public String toString() {
if (values == null) { if (operator == Operator.IN) {
return "in()";
}
int len = values.length; if (values == null) {
StringBuilder b = new StringBuilder(); return "in()";
b.append("in("); }
for (int i = 0; i != len; i++) {
if (b.length() > 3) { int len = values.length;
b.append(", "); StringBuilder b = new StringBuilder();
} b.append("in(");
b.append(String.valueOf(values[i])); for (int i = 0; i != len; i++) {
} if (b.length() > 3) {
return b.append(')').toString(); b.append(", ");
} }
b.append(String.valueOf(values[i]));
}
return b.append(')').toString();
}
return operator.getName() + values[0];
}
return operator.getName() + values[0];
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,5 +19,6 @@ import net.helenus.mapping.HelenusProperty;
public interface PropertyValueValidator { public interface PropertyValueValidator {
void validate(HelenusProperty prop, Object value); void validate(HelenusProperty prop, Object value);
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,80 +15,90 @@
*/ */
package net.helenus.core; package net.helenus.core;
import com.datastax.driver.core.querybuilder.BindMarker;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import com.datastax.driver.core.querybuilder.BindMarker;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import net.helenus.mapping.OrderingDirection; import net.helenus.mapping.OrderingDirection;
/** Sugar methods for the queries */ /**
* Sugar methods for the queries
*
*/
public final class Query { public final class Query {
private Query() {} private Query() {
}
public static BindMarker marker() { public static BindMarker marker() {
return QueryBuilder.bindMarker(); return QueryBuilder.bindMarker();
} }
public static BindMarker marker(String name) { public static BindMarker marker(String name) {
return QueryBuilder.bindMarker(name); return QueryBuilder.bindMarker(name);
} }
public static Ordered asc(Getter<?> getter) { public static Ordered asc(Getter<?> getter) {
return new Ordered(getter, OrderingDirection.ASC); return new Ordered(getter, OrderingDirection.ASC);
} }
public static Ordered desc(Getter<?> getter) { public static Ordered desc(Getter<?> getter) {
return new Ordered(getter, OrderingDirection.DESC); return new Ordered(getter, OrderingDirection.DESC);
} }
public static <V> Postulate<V> eq(V val) { public static <V> Postulate<V> eq(V val) {
return Postulate.of(Operator.EQ, val); return Postulate.of(Operator.EQ, val);
} }
public static <V> Postulate<V> lt(V val) { public static <V> Postulate<V> lt(V val) {
return Postulate.of(Operator.LT, val); return Postulate.of(Operator.LT, val);
} }
public static <V> Postulate<V> lte(V val) { public static <V> Postulate<V> lte(V val) {
return Postulate.of(Operator.LTE, val); return Postulate.of(Operator.LTE, val);
} }
public static <V> Postulate<V> gt(V val) { public static <V> Postulate<V> gt(V val) {
return Postulate.of(Operator.GT, val); return Postulate.of(Operator.GT, val);
} }
public static <V> Postulate<V> gte(V val) { public static <V> Postulate<V> gte(V val) {
return Postulate.of(Operator.GTE, val); return Postulate.of(Operator.GTE, val);
} }
public static <V> Postulate<V> in(V[] vals) { public static <V> Postulate<V> in(V[] vals) {
return new Postulate<V>(Operator.IN, vals); return new Postulate<V>(Operator.IN, vals);
} }
public static <K, V> Getter<V> getIdx(Getter<List<V>> listGetter, int index) { public static <K, V> Getter<V> getIdx(Getter<List<V>> listGetter, int index) {
Objects.requireNonNull(listGetter, "listGetter is null"); Objects.requireNonNull(listGetter, "listGetter is null");
return new Getter<V>() { return new Getter<V>() {
@Override @Override
public V get() { public V get() {
return listGetter.get().get(index); return listGetter.get().get(index);
} }
};
}
public static <K, V> Getter<V> get(Getter<Map<K, V>> mapGetter, K k) { };
Objects.requireNonNull(mapGetter, "mapGetter is null"); }
Objects.requireNonNull(k, "key is null");
return new Getter<V>() { public static <K, V> Getter<V> get(Getter<Map<K, V>> mapGetter, K k) {
Objects.requireNonNull(mapGetter, "mapGetter is null");
Objects.requireNonNull(k, "key is null");
return new Getter<V>() {
@Override
public V get() {
return mapGetter.get().get(k);
}
};
}
@Override
public V get() {
return mapGetter.get().get(k);
}
};
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,459 +15,351 @@
*/ */
package net.helenus.core; package net.helenus.core;
import com.datastax.driver.core.*;
import com.datastax.driver.core.querybuilder.IsNotNullClause;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.schemabuilder.*;
import com.datastax.driver.core.schemabuilder.Create.Options;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import net.helenus.core.reflect.HelenusPropertyNode;
import com.datastax.driver.core.*;
import com.datastax.driver.core.IndexMetadata;
import com.datastax.driver.core.schemabuilder.*;
import com.datastax.driver.core.schemabuilder.Create.Options;
import net.helenus.mapping.*; import net.helenus.mapping.*;
import net.helenus.mapping.ColumnType; import net.helenus.mapping.ColumnType;
import net.helenus.mapping.annotation.ClusteringColumn;
import net.helenus.mapping.type.OptionalColumnMetadata; import net.helenus.mapping.type.OptionalColumnMetadata;
import net.helenus.support.CqlUtil; import net.helenus.support.CqlUtil;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public final class SchemaUtil { public final class SchemaUtil {
private SchemaUtil() {} private SchemaUtil() {
}
public static RegularStatement use(String keyspace, boolean forceQuote) { public static RegularStatement use(String keyspace, boolean forceQuote) {
if (forceQuote) { if (forceQuote) {
return new SimpleStatement("USE" + CqlUtil.forceQuote(keyspace)); return new SimpleStatement("USE" + CqlUtil.forceQuote(keyspace));
} else { } else {
return new SimpleStatement("USE " + keyspace); return new SimpleStatement("USE " + keyspace);
} }
} }
public static SchemaStatement createUserType(HelenusEntity entity) { public static SchemaStatement createUserType(HelenusEntity entity) {
if (entity.getType() != HelenusEntityType.UDT) { if (entity.getType() != HelenusEntityType.UDT) {
throw new HelenusMappingException("expected UDT entity " + entity); throw new HelenusMappingException("expected UDT entity " + entity);
} }
CreateType create = SchemaBuilder.createType(entity.getName().toCql()); CreateType create = SchemaBuilder.createType(entity.getName().toCql());
for (HelenusProperty prop : entity.getOrderedProperties()) { for (HelenusProperty prop : entity.getOrderedProperties()) {
ColumnType columnType = prop.getColumnType(); ColumnType columnType = prop.getColumnType();
if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) { if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
throw new HelenusMappingException( throw new HelenusMappingException("primary key columns are not supported in UserDefinedType for "
"primary key columns are not supported in UserDefinedType for " + prop.getPropertyName() + " in entity " + entity);
+ prop.getPropertyName() }
+ " in entity "
+ entity);
}
try { try {
prop.getDataType().addColumn(create, prop.getColumnName()); prop.getDataType().addColumn(create, prop.getColumnName());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new HelenusMappingException( throw new HelenusMappingException("invalid column name '" + prop.getColumnName() + "' in entity '"
"invalid column name '" + entity.getName().getName() + "'", e);
+ prop.getColumnName() }
+ "' in entity '" }
+ entity.getName().getName()
+ "'",
e);
}
}
return create; return create;
} }
public static List<SchemaStatement> alterUserType( public static List<SchemaStatement> alterUserType(UserType userType, HelenusEntity entity,
UserType userType, HelenusEntity entity, boolean dropUnusedColumns) { boolean dropUnusedColumns) {
if (entity.getType() != HelenusEntityType.UDT) { if (entity.getType() != HelenusEntityType.UDT) {
throw new HelenusMappingException("expected UDT entity " + entity); throw new HelenusMappingException("expected UDT entity " + entity);
} }
List<SchemaStatement> result = new ArrayList<SchemaStatement>(); List<SchemaStatement> result = new ArrayList<SchemaStatement>();
/** /**
* TODO: In future replace SchemaBuilder.alterTable by SchemaBuilder.alterType when it will * TODO: In future replace SchemaBuilder.alterTable by SchemaBuilder.alterType
* exist * when it will exist
*/ */
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
final Set<String> visitedColumns = Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
for (HelenusProperty prop : entity.getOrderedProperties()) { final Set<String> visitedColumns = dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
String columnName = prop.getColumnName().getName(); for (HelenusProperty prop : entity.getOrderedProperties()) {
if (dropUnusedColumns) { String columnName = prop.getColumnName().getName();
visitedColumns.add(columnName);
}
ColumnType columnType = prop.getColumnType(); if (dropUnusedColumns) {
visitedColumns.add(columnName);
}
if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) { ColumnType columnType = prop.getColumnType();
continue;
}
DataType dataType = userType.getFieldType(columnName); if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
SchemaStatement stmt = continue;
prop.getDataType() }
.alterColumn(alter, prop.getColumnName(), optional(columnName, dataType));
if (stmt != null) { DataType dataType = userType.getFieldType(columnName);
result.add(stmt); SchemaStatement stmt = prop.getDataType().alterColumn(alter, prop.getColumnName(),
} optional(columnName, dataType));
}
if (dropUnusedColumns) { if (stmt != null) {
for (String field : userType.getFieldNames()) { result.add(stmt);
if (!visitedColumns.contains(field)) { }
result.add(alter.dropColumn(field)); }
}
}
}
return result; if (dropUnusedColumns) {
} for (String field : userType.getFieldNames()) {
if (!visitedColumns.contains(field)) {
public static SchemaStatement dropUserType(HelenusEntity entity) { result.add(alter.dropColumn(field));
if (entity.getType() != HelenusEntityType.UDT) { }
throw new HelenusMappingException("expected UDT entity " + entity); }
} }
return SchemaBuilder.dropType(entity.getName().toCql()).ifExists(); return result;
}
public static SchemaStatement dropUserType(UserType type) { }
return SchemaBuilder.dropType(type.getTypeName()).ifExists(); public static SchemaStatement dropUserType(HelenusEntity entity) {
}
public static String createPrimaryKeyPhrase(Collection<HelenusProperty> properties) { if (entity.getType() != HelenusEntityType.UDT) {
List<String> p = new ArrayList<String>(properties.size()); throw new HelenusMappingException("expected UDT entity " + entity);
List<String> c = new ArrayList<String>(properties.size());
for (HelenusProperty prop : properties) {
String columnName = prop.getColumnName().toCql();
switch (prop.getColumnType()) {
case PARTITION_KEY:
p.add(columnName);
break;
case CLUSTERING_COLUMN:
c.add(columnName);
break;
default:
break;
}
}
if (p.size() == 0 && c.size() == 0)
return "{"
+ properties
.stream()
.map(HelenusProperty::getPropertyName)
.collect(Collectors.joining(", "))
+ "}";
return "("
+ ((p.size() > 1) ? "(" + String.join(", ", p) + ")" : p.get(0))
+ ((c.size() > 0)
? ", " + ((c.size() > 1) ? "(" + String.join(", ", c) + ")" : c.get(0))
: "")
+ ")";
}
public static SchemaStatement createMaterializedView(
String keyspace, String viewName, HelenusEntity entity) {
if (entity.getType() != HelenusEntityType.VIEW) {
throw new HelenusMappingException("expected view entity " + entity);
}
List<HelenusPropertyNode> props = new ArrayList<HelenusPropertyNode>();
entity
.getOrderedProperties()
.stream()
.map(p -> new HelenusPropertyNode(p, Optional.empty()))
.forEach(p -> props.add(p));
Select.Selection selection = QueryBuilder.select();
for (HelenusPropertyNode prop : props) {
String columnName = prop.getColumnName();
selection = selection.column(columnName);
}
Class<?> iface = entity.getMappingInterface();
String tableName = Helenus.entity(iface.getInterfaces()[0]).getName().toCql();
Select.Where where = selection.from(tableName).where();
List<String> o = new ArrayList<String>(props.size());
for (HelenusPropertyNode prop : props) {
String columnName = prop.getColumnName();
switch (prop.getProperty().getColumnType()) {
case PARTITION_KEY:
where = where.and(new IsNotNullClause(columnName));
break;
case CLUSTERING_COLUMN:
where = where.and(new IsNotNullClause(columnName));
ClusteringColumn clusteringColumn =
prop.getProperty().getGetterMethod().getAnnotation(ClusteringColumn.class);
if (clusteringColumn != null && clusteringColumn.ordering() != null) {
o.add(columnName + " " + clusteringColumn.ordering().cql());
}
break;
default:
break;
}
}
String primaryKey = "PRIMARY KEY " + createPrimaryKeyPhrase(entity.getOrderedProperties());
String clustering = "";
if (o.size() > 0) {
clustering = "WITH CLUSTERING ORDER BY (" + String.join(", ", o) + ")";
}
return new CreateMaterializedView(keyspace, viewName, where, primaryKey, clustering)
.ifNotExists();
}
public static SchemaStatement dropMaterializedView(
String keyspace, String viewName, HelenusEntity entity) {
return new DropMaterializedView(keyspace, viewName);
}
public static SchemaStatement createTable(HelenusEntity entity) {
if (entity.getType() != HelenusEntityType.TABLE) {
throw new HelenusMappingException("expected table entity " + entity);
}
// NOTE: There is a bug in the normal path of createTable where the
// "cache" is set too early and never unset preventing more than
// one column on a table.
// SchemaBuilder.createTable(entity.getName().toCql());
CreateTable create = new CreateTable(entity.getName().toCql());
create.ifNotExists();
List<HelenusProperty> clusteringColumns = new ArrayList<HelenusProperty>();
for (HelenusProperty prop : entity.getOrderedProperties()) {
ColumnType columnType = prop.getColumnType();
if (columnType == ColumnType.CLUSTERING_COLUMN) {
clusteringColumns.add(prop);
}
prop.getDataType().addColumn(create, prop.getColumnName());
}
if (!clusteringColumns.isEmpty()) {
Options options = create.withOptions();
clusteringColumns.forEach(
p -> options.clusteringOrder(p.getColumnName().toCql(), mapDirection(p.getOrdering())));
}
return create;
}
public static List<SchemaStatement> alterTable(
TableMetadata tmd, HelenusEntity entity, boolean dropUnusedColumns) {
if (entity.getType() != HelenusEntityType.TABLE) {
throw new HelenusMappingException("expected table entity " + entity);
}
List<SchemaStatement> result = new ArrayList<SchemaStatement>();
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
final Set<String> visitedColumns =
dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
for (HelenusProperty prop : entity.getOrderedProperties()) {
String columnName = prop.getColumnName().getName();
if (dropUnusedColumns) {
visitedColumns.add(columnName);
}
ColumnType columnType = prop.getColumnType();
if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
continue;
}
ColumnMetadata columnMetadata = tmd.getColumn(columnName);
SchemaStatement stmt =
prop.getDataType().alterColumn(alter, prop.getColumnName(), optional(columnMetadata));
if (stmt != null) {
result.add(stmt);
}
}
if (dropUnusedColumns) {
for (ColumnMetadata cm : tmd.getColumns()) {
if (!visitedColumns.contains(cm.getName())) {
result.add(alter.dropColumn(cm.getName()));
}
}
}
return result;
}
public static SchemaStatement dropTable(HelenusEntity entity) {
if (entity.getType() != HelenusEntityType.TABLE) {
throw new HelenusMappingException("expected table entity " + entity);
}
return SchemaBuilder.dropTable(entity.getName().toCql()).ifExists();
}
public static SchemaStatement createIndex(HelenusProperty prop) {
if (prop.caseSensitiveIndex()) {
return SchemaBuilder.createIndex(indexName(prop))
.ifNotExists()
.onTable(prop.getEntity().getName().toCql())
.andColumn(prop.getColumnName().toCql());
} else {
return new CreateSasiIndex(prop.getIndexName().get().toCql())
.ifNotExists()
.onTable(prop.getEntity().getName().toCql())
.andColumn(prop.getColumnName().toCql());
}
}
public static List<SchemaStatement> createIndexes(HelenusEntity entity) {
return entity
.getOrderedProperties()
.stream()
.filter(p -> p.getIndexName().isPresent())
.map(p -> SchemaUtil.createIndex(p))
.collect(Collectors.toList());
}
public static List<SchemaStatement> alterIndexes(
TableMetadata tmd, HelenusEntity entity, boolean dropUnusedIndexes) {
List<SchemaStatement> list = new ArrayList<SchemaStatement>();
final Set<String> visitedColumns =
dropUnusedIndexes ? new HashSet<String>() : Collections.<String>emptySet();
entity
.getOrderedProperties()
.stream()
.filter(p -> p.getIndexName().isPresent())
.forEach(
p -> {
String columnName = p.getColumnName().getName();
if (dropUnusedIndexes) {
visitedColumns.add(columnName);
}
ColumnMetadata cm = tmd.getColumn(columnName);
if (cm != null) {
IndexMetadata im = tmd.getIndex(columnName);
if (im == null) {
list.add(createIndex(p));
}
} else {
list.add(createIndex(p));
}
});
if (dropUnusedIndexes) {
tmd.getColumns()
.stream()
.filter(c -> tmd.getIndex(c.getName()) != null && !visitedColumns.contains(c.getName()))
.forEach(
c -> {
list.add(SchemaBuilder.dropIndex(tmd.getIndex(c.getName()).getName()).ifExists());
});
}
return list;
}
public static SchemaStatement dropIndex(HelenusProperty prop) {
return SchemaBuilder.dropIndex(indexName(prop)).ifExists();
}
private static SchemaBuilder.Direction mapDirection(OrderingDirection o) {
switch (o) {
case ASC:
return SchemaBuilder.Direction.ASC;
case DESC:
return SchemaBuilder.Direction.DESC;
}
throw new HelenusMappingException("unknown ordering " + o);
}
public static void throwNoMapping(HelenusProperty prop) {
throw new HelenusMappingException(
"only primitive types and Set,List,Map collections and UserDefinedTypes are allowed, unknown type for property '"
+ prop.getPropertyName()
+ "' type is '"
+ prop.getJavaType()
+ "' in the entity "
+ prop.getEntity());
}
private static OptionalColumnMetadata optional(final ColumnMetadata columnMetadata) {
if (columnMetadata != null) {
return new OptionalColumnMetadata() {
@Override
public String getName() {
return columnMetadata.getName();
} }
@Override return SchemaBuilder.dropType(entity.getName().toCql()).ifExists();
public DataType getType() {
return columnMetadata.getType();
}
};
} }
return null;
}
private static OptionalColumnMetadata optional(final String name, final DataType dataType) { public static SchemaStatement dropUserType(UserType type) {
if (dataType != null) {
return new OptionalColumnMetadata() {
@Override return SchemaBuilder.dropType(type.getTypeName()).ifExists();
public String getName() { }
return name;
public static SchemaStatement createTable(HelenusEntity entity) {
if (entity.getType() != HelenusEntityType.TABLE) {
throw new HelenusMappingException("expected table entity " + entity);
}
// NOTE: There is a bug in the normal path of createTable where the
// "cache" is set too early and never unset preventing more than
// one column on a table.
// SchemaBuilder.createTable(entity.getName().toCql());
CreateTable create = new CreateTable(entity.getName().toCql());
create.ifNotExists();
List<HelenusProperty> clusteringColumns = new ArrayList<HelenusProperty>();
for (HelenusProperty prop : entity.getOrderedProperties()) {
ColumnType columnType = prop.getColumnType();
if (columnType == ColumnType.CLUSTERING_COLUMN) {
clusteringColumns.add(prop);
}
prop.getDataType().addColumn(create, prop.getColumnName());
}
if (!clusteringColumns.isEmpty()) {
Options options = create.withOptions();
clusteringColumns
.forEach(p -> options.clusteringOrder(p.getColumnName().toCql(), mapDirection(p.getOrdering())));
}
return create;
}
public static List<SchemaStatement> alterTable(TableMetadata tmd, HelenusEntity entity, boolean dropUnusedColumns) {
if (entity.getType() != HelenusEntityType.TABLE) {
throw new HelenusMappingException("expected table entity " + entity);
}
List<SchemaStatement> result = new ArrayList<SchemaStatement>();
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
final Set<String> visitedColumns = dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
for (HelenusProperty prop : entity.getOrderedProperties()) {
String columnName = prop.getColumnName().getName();
if (dropUnusedColumns) {
visitedColumns.add(columnName);
}
ColumnType columnType = prop.getColumnType();
if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
continue;
}
ColumnMetadata columnMetadata = tmd.getColumn(columnName);
SchemaStatement stmt = prop.getDataType().alterColumn(alter, prop.getColumnName(),
optional(columnMetadata));
if (stmt != null) {
result.add(stmt);
}
}
if (dropUnusedColumns) {
for (ColumnMetadata cm : tmd.getColumns()) {
if (!visitedColumns.contains(cm.getName())) {
result.add(alter.dropColumn(cm.getName()));
}
}
}
return result;
}
public static SchemaStatement dropTable(HelenusEntity entity) {
if (entity.getType() != HelenusEntityType.TABLE) {
throw new HelenusMappingException("expected table entity " + entity);
}
return SchemaBuilder.dropTable(entity.getName().toCql()).ifExists();
}
public static SchemaStatement createIndex(HelenusProperty prop) {
if (prop.caseSensitiveIndex()) {
return SchemaBuilder.createIndex(prop.getIndexName().get().toCql())
.ifNotExists()
.onTable(prop.getEntity().getName().toCql())
.andColumn(prop.getColumnName().toCql());
} else {
return new CreateSasiIndex(prop.getIndexName().get().toCql())
.ifNotExists()
.onTable(prop.getEntity().getName().toCql())
.andColumn(prop.getColumnName().toCql());
} }
}
@Override public static List<SchemaStatement> createIndexes(HelenusEntity entity) {
public DataType getType() {
return dataType;
}
};
}
return null;
}
private static String indexName(HelenusProperty prop) { return entity.getOrderedProperties().stream().filter(p -> p.getIndexName().isPresent())
return prop.getEntity().getName().toCql() + "_" + prop.getIndexName().get().toCql(); .map(p -> SchemaUtil.createIndex(p)).collect(Collectors.toList());
}
}
public static List<SchemaStatement> alterIndexes(TableMetadata tmd, HelenusEntity entity,
boolean dropUnusedIndexes) {
List<SchemaStatement> list = new ArrayList<SchemaStatement>();
final Set<String> visitedColumns = dropUnusedIndexes ? new HashSet<String>() : Collections.<String>emptySet();
entity.getOrderedProperties().stream().filter(p -> p.getIndexName().isPresent()).forEach(p -> {
String columnName = p.getColumnName().getName();
if (dropUnusedIndexes) {
visitedColumns.add(columnName);
}
ColumnMetadata cm = tmd.getColumn(columnName);
if (cm != null) {
IndexMetadata im = tmd.getIndex(columnName);
if (im == null) {
list.add(createIndex(p));
}
} else {
list.add(createIndex(p));
}
});
if (dropUnusedIndexes) {
tmd.getColumns().stream().filter(c -> tmd.getIndex(c.getName()) != null && !visitedColumns.contains(c.getName()))
.forEach(c -> {
list.add(SchemaBuilder.dropIndex(tmd.getIndex(c.getName()).getName()).ifExists());
});
}
return list;
}
public static SchemaStatement dropIndex(HelenusProperty prop) {
return SchemaBuilder.dropIndex(prop.getIndexName().get().toCql()).ifExists();
}
private static SchemaBuilder.Direction mapDirection(OrderingDirection o) {
switch (o) {
case ASC :
return SchemaBuilder.Direction.ASC;
case DESC :
return SchemaBuilder.Direction.DESC;
}
throw new HelenusMappingException("unknown ordering " + o);
}
public static void throwNoMapping(HelenusProperty prop) {
throw new HelenusMappingException(
"only primitive types and Set,List,Map collections and UserDefinedTypes are allowed, unknown type for property '"
+ prop.getPropertyName() + "' type is '" + prop.getJavaType() + "' in the entity "
+ prop.getEntity());
}
private static OptionalColumnMetadata optional(final ColumnMetadata columnMetadata) {
if (columnMetadata != null) {
return new OptionalColumnMetadata() {
@Override
public String getName() {
return columnMetadata.getName();
}
@Override
public DataType getType() {
return columnMetadata.getType();
}
};
}
return null;
}
private static OptionalColumnMetadata optional(final String name, final DataType dataType) {
if (dataType != null) {
return new OptionalColumnMetadata() {
@Override
public String getName() {
return name;
}
@Override
public DataType getType() {
return dataType;
}
};
}
return null;
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,447 +18,325 @@ package net.helenus.core;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import com.datastax.driver.core.*; import com.datastax.driver.core.*;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusEntityType;
import net.helenus.mapping.value.ColumnValuePreparer;
import net.helenus.mapping.value.ColumnValueProvider;
import net.helenus.support.HelenusException;
import net.helenus.support.PackageUtil;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.*; import java.util.*;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.cache.CacheManager;
import net.helenus.core.reflect.DslExportable;
import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusEntityType;
import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.value.ColumnValuePreparer;
import net.helenus.mapping.value.ColumnValueProvider;
import net.helenus.support.Either;
import net.helenus.support.HelenusException;
import net.helenus.support.PackageUtil;
public final class SessionInitializer extends AbstractSessionOperations { public final class SessionInitializer extends AbstractSessionOperations {
private final Session session; private final Session session;
private final List<Either<Object, Class<?>>> initList = new ArrayList<Either<Object, Class<?>>>(); private CodecRegistry registry;
private CodecRegistry registry; private MetricRegistry metricRegistry;
private String usingKeyspace; private String usingKeyspace;
private boolean showCql = false; private boolean showCql = false;
private boolean showValues = true; private PrintStream printStream = System.out;
private ConsistencyLevel consistencyLevel; private Executor executor = MoreExecutors.directExecutor();
private boolean idempotent = false;
private MetricRegistry metricRegistry = new MetricRegistry();
private PrintStream printStream = System.out;
private Executor executor = MoreExecutors.directExecutor();
private SessionRepositoryBuilder sessionRepository;
private boolean dropUnusedColumns = false;
private boolean dropUnusedIndexes = false;
private KeyspaceMetadata keyspaceMetadata;
private AutoDdl autoDdl = AutoDdl.UPDATE;
private CacheManager cacheManager = null;
SessionInitializer(Session session, String keyspace) { private SessionRepositoryBuilder sessionRepository;
this.session = session;
this.usingKeyspace = keyspace; private boolean dropUnusedColumns = false;
if (session != null) { private boolean dropUnusedIndexes = false;
this.sessionRepository = new SessionRepositoryBuilder(session);
private KeyspaceMetadata keyspaceMetadata;
private final List<Object> initList = new ArrayList<Object>();
private AutoDdl autoDdl = AutoDdl.UPDATE;
SessionInitializer(Session session) {
this.session = Objects.requireNonNull(session, "empty session");
this.usingKeyspace = session.getLoggedKeyspace(); // can be null
this.sessionRepository = new SessionRepositoryBuilder(session);
}
@Override
public void cache(String key, Object value) { }
@Override
public Session currentSession() {
return session;
}
@Override
public String usingKeyspace() {
return usingKeyspace;
}
@Override
public Executor getExecutor() {
return executor;
}
@Override
public SessionRepository getSessionRepository() {
throw new HelenusException("not expected to call");
}
@Override
public ColumnValueProvider getValueProvider() {
throw new HelenusException("not expected to call");
}
@Override
public ColumnValuePreparer getValuePreparer() {
throw new HelenusException("not expected to call");
}
public SessionInitializer showCql() {
this.showCql = true;
return this;
}
public SessionInitializer showCql(boolean enabled) {
this.showCql = enabled;
return this;
}
@Override
public PrintStream getPrintStream() {
return printStream;
}
public SessionInitializer printTo(PrintStream out) {
this.printStream = out;
return this;
}
public SessionInitializer withExecutor(Executor executor) {
Objects.requireNonNull(executor, "empty executor");
this.executor = executor;
return this;
}
public SessionInitializer withMetricsRegistry(MetricRegistry metricRegistry) {
Objects.requireNonNull(metricRegistry, "empty registry");
this.metricRegistry = metricRegistry;
return this;
} }
}
SessionInitializer(Session session) { public SessionInitializer withCachingExecutor() {
this.session = Objects.requireNonNull(session, "empty session"); this.executor = Executors.newCachedThreadPool();
this.usingKeyspace = session.getLoggedKeyspace(); // can be null return this;
this.sessionRepository = new SessionRepositoryBuilder(session); }
}
@Override public SessionInitializer dropUnusedColumns(boolean enabled) {
public Session currentSession() { this.dropUnusedColumns = enabled;
return session; return this;
} }
@Override public SessionInitializer dropUnusedIndexes(boolean enabled) {
public String usingKeyspace() { this.dropUnusedIndexes = enabled;
return usingKeyspace; return this;
} }
@Override public SessionInitializer withCodecRegistry(CodecRegistry registry) {
public Executor getExecutor() { this.registry = registry;
return executor; return this;
}
@Override
public SessionRepository getSessionRepository() {
throw new HelenusException("not expected to call");
}
@Override
public ColumnValueProvider getValueProvider() {
throw new HelenusException("not expected to call");
}
@Override
public ColumnValuePreparer getValuePreparer() {
throw new HelenusException("not expected to call");
}
public SessionInitializer showCql() {
this.showCql = true;
return this;
}
public SessionInitializer showCql(boolean enabled) {
this.showCql = enabled;
return this;
}
public SessionInitializer showQueryValuesInLog(boolean showValues) {
this.showValues = showValues;
return this;
}
public SessionInitializer showQueryValuesInLog() {
this.showValues = true;
return this;
}
public boolean showValues() {
return showValues;
}
public SessionInitializer metricRegistry(MetricRegistry metricRegistry) {
this.metricRegistry = metricRegistry;
return this;
}
public SessionInitializer consistencyLevel(ConsistencyLevel consistencyLevel) {
this.consistencyLevel = consistencyLevel;
return this;
}
public SessionInitializer setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
return this;
}
public ConsistencyLevel getDefaultConsistencyLevel() {
return consistencyLevel;
}
public SessionInitializer setOperationsIdempotentByDefault() {
this.idempotent = true;
return this;
}
public SessionInitializer idempotentQueryExecution(boolean idempotent) {
this.idempotent = idempotent;
return this;
}
public boolean getDefaultQueryIdempotency() {
return idempotent;
}
@Override
public PrintStream getPrintStream() {
return printStream;
}
public SessionInitializer printTo(PrintStream out) {
this.printStream = out;
return this;
}
public SessionInitializer withExecutor(Executor executor) {
Objects.requireNonNull(executor, "empty executor");
this.executor = executor;
return this;
}
public SessionInitializer withCachingExecutor() {
this.executor = Executors.newCachedThreadPool();
return this;
}
public SessionInitializer dropUnusedColumns(boolean enabled) {
this.dropUnusedColumns = enabled;
return this;
}
public SessionInitializer dropUnusedIndexes(boolean enabled) {
this.dropUnusedIndexes = enabled;
return this;
}
public SessionInitializer withCodecRegistry(CodecRegistry registry) {
this.registry = registry;
return this;
}
@Override
public boolean isShowCql() {
return showCql;
}
public SessionInitializer addPackage(String packageName) {
try {
PackageUtil.getClasses(packageName)
.stream()
.filter(c -> c.isInterface() && !c.isAnnotation())
.forEach(
clazz -> {
initList.add(Either.right(clazz));
});
} catch (IOException | ClassNotFoundException e) {
throw new HelenusException("fail to add package " + packageName, e);
} }
return this;
}
public SessionInitializer add(Object... dsls) { @Override
Objects.requireNonNull(dsls, "dsls is empty"); public boolean isShowCql() {
int len = dsls.length; return showCql;
for (int i = 0; i != len; ++i) { }
Object obj = Objects.requireNonNull(dsls[i], "element " + i + " is empty");
initList.add(Either.left(obj));
}
return this;
}
public SessionInitializer autoValidate() { public SessionInitializer addPackage(String packageName) {
this.autoDdl = AutoDdl.VALIDATE; try {
return this; PackageUtil.getClasses(packageName).stream().filter(c -> c.isInterface() && !c.isAnnotation())
} .forEach(initList::add);
} catch (IOException | ClassNotFoundException e) {
throw new HelenusException("fail to add package " + packageName, e);
}
return this;
}
public SessionInitializer autoUpdate() { public SessionInitializer add(Object... dsls) {
this.autoDdl = AutoDdl.UPDATE; Objects.requireNonNull(dsls, "dsls is empty");
return this; int len = dsls.length;
} for (int i = 0; i != len; ++i) {
Object obj = Objects.requireNonNull(dsls[i], "element " + i + " is empty");
initList.add(obj);
}
return this;
}
public SessionInitializer autoCreate() { public SessionInitializer autoValidate() {
this.autoDdl = AutoDdl.CREATE; this.autoDdl = AutoDdl.VALIDATE;
return this; return this;
} }
public SessionInitializer autoCreateDrop() { public SessionInitializer autoUpdate() {
this.autoDdl = AutoDdl.CREATE_DROP; this.autoDdl = AutoDdl.UPDATE;
return this; return this;
} }
public SessionInitializer auto(AutoDdl autoDdl) { public SessionInitializer autoCreate() {
this.autoDdl = autoDdl; this.autoDdl = AutoDdl.CREATE;
return this; return this;
} }
public SessionInitializer use(String keyspace) { public SessionInitializer autoCreateDrop() {
if (session != null) { this.autoDdl = AutoDdl.CREATE_DROP;
session.execute(SchemaUtil.use(keyspace, false)); return this;
this.usingKeyspace = keyspace; }
}
return this;
}
public SessionInitializer use(String keyspace, boolean forceQuote) { public SessionInitializer auto(AutoDdl autoDdl) {
session.execute(SchemaUtil.use(keyspace, forceQuote)); this.autoDdl = autoDdl;
this.usingKeyspace = keyspace; return this;
return this; }
}
public void singleton() { public SessionInitializer use(String keyspace) {
Helenus.setSession(get()); session.execute(SchemaUtil.use(keyspace, false));
} this.usingKeyspace = keyspace;
return this;
}
public synchronized HelenusSession get() { public SessionInitializer use(String keyspace, boolean forceQuote) {
initialize(); session.execute(SchemaUtil.use(keyspace, forceQuote));
return new HelenusSession( this.usingKeyspace = keyspace;
session, return this;
usingKeyspace, }
registry,
showCql,
showValues,
printStream,
sessionRepository,
executor,
autoDdl == AutoDdl.CREATE_DROP,
consistencyLevel,
idempotent,
cacheManager,
metricRegistry);
}
private void initialize() { public void singleton() {
Objects.requireNonNull(usingKeyspace, "please define keyspace by 'use' operator"); Helenus.setSession(get());
}
initList.forEach( public synchronized HelenusSession get() {
(either) -> { initialize();
Class<?> iface = null; return new HelenusSession(session, usingKeyspace, registry, showCql, printStream, sessionRepository, executor,
if (either.isLeft()) { autoDdl == AutoDdl.CREATE_DROP, metricRegistry);
iface = MappingUtil.getMappingInterface(either.getLeft()); }
} else {
iface = either.getRight();
}
DslExportable dsl = (DslExportable) Helenus.dsl(iface); private void initialize() {
if (session != null) {
dsl.setCassandraMetadataForHelenusSession(session.getCluster().getMetadata()); Objects.requireNonNull(usingKeyspace, "please define keyspace by 'use' operator");
}
if (sessionRepository != null) { initList.forEach(dsl -> sessionRepository.add(dsl));
sessionRepository.add(dsl);
} TableOperations tableOps = new TableOperations(this, dropUnusedColumns, dropUnusedIndexes);
UserTypeOperations userTypeOps = new UserTypeOperations(this, dropUnusedColumns);
switch (autoDdl) {
case CREATE_DROP :
// Drop tables first, otherwise a `DROP TYPE ...` will fail as the type is still referenced
// by a table.
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.TABLE)
.forEach(e -> tableOps.dropTable(e));
eachUserTypeInReverseOrder(userTypeOps, e -> userTypeOps.dropUserType(e));
// FALLTHRU to CREATE case (read: the absence of a `break;` statement here is intentional!)
case CREATE :
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.createUserType(e));
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.TABLE)
.forEach(e -> tableOps.createTable(e));
break;
case VALIDATE :
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.validateUserType(getUserType(e), e));
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.TABLE)
.forEach(e -> tableOps.validateTable(getTableMetadata(e), e));
break;
case UPDATE :
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.updateUserType(getUserType(e), e));
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.TABLE)
.forEach(e -> tableOps.updateTable(getTableMetadata(e), e));
break;
}
KeyspaceMetadata km = getKeyspaceMetadata();
for (UserType userType : km.getUserTypes()) {
sessionRepository.addUserType(userType.getTypeName(), userType);
}
}
private void eachUserTypeInOrder(UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) {
Set<HelenusEntity> processedSet = new HashSet<HelenusEntity>();
Set<HelenusEntity> stack = new HashSet<HelenusEntity>();
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.UDT).forEach(e -> {
stack.clear();
eachUserTypeInRecursion(e, processedSet, stack, userTypeOps, action);
}); });
if (session == null) return;
TableOperations tableOps = new TableOperations(this, dropUnusedColumns, dropUnusedIndexes);
UserTypeOperations userTypeOps = new UserTypeOperations(this, dropUnusedColumns);
switch (autoDdl) {
case CREATE_DROP:
// Drop view first, otherwise a `DROP TABLE ...` will fail as the type is still
// referenced
// by a view.
sessionRepository
.entities()
.stream()
.filter(e -> e.getType() == HelenusEntityType.VIEW)
.forEach(e -> tableOps.dropView(e));
// Drop tables second, before DROP TYPE otherwise a `DROP TYPE ...` will fail as
// the type is
// still referenced by a table.
sessionRepository
.entities()
.stream()
.filter(e -> e.getType() == HelenusEntityType.TABLE)
.forEach(e -> tableOps.dropTable(e));
eachUserTypeInReverseOrder(userTypeOps, e -> userTypeOps.dropUserType(e));
// FALLTHRU to CREATE case (read: the absence of a `break;` statement here is
// intentional!)
case CREATE:
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.createUserType(e));
sessionRepository
.entities()
.stream()
.filter(e -> e.getType() == HelenusEntityType.TABLE)
.forEach(e -> tableOps.createTable(e));
sessionRepository
.entities()
.stream()
.filter(e -> e.getType() == HelenusEntityType.VIEW)
.forEach(e -> tableOps.createView(e));
break;
case VALIDATE:
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.validateUserType(getUserType(e), e));
sessionRepository
.entities()
.stream()
.filter(e -> e.getType() == HelenusEntityType.TABLE)
.forEach(e -> tableOps.validateTable(getTableMetadata(e), e));
break;
case UPDATE:
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.updateUserType(getUserType(e), e));
sessionRepository
.entities()
.stream()
.filter(e -> e.getType() == HelenusEntityType.VIEW)
.forEach(e -> tableOps.dropView(e));
sessionRepository
.entities()
.stream()
.filter(e -> e.getType() == HelenusEntityType.TABLE)
.forEach(e -> tableOps.updateTable(getTableMetadata(e), e));
sessionRepository
.entities()
.stream()
.filter(e -> e.getType() == HelenusEntityType.VIEW)
.forEach(e -> tableOps.createView(e));
break;
} }
KeyspaceMetadata km = getKeyspaceMetadata(); private void eachUserTypeInReverseOrder(UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) {
ArrayDeque<HelenusEntity> deque = new ArrayDeque<>();
eachUserTypeInOrder(userTypeOps, e -> deque.addFirst(e));
deque.stream().forEach(e -> {action.accept(e); });
/*
Set<HelenusEntity> processedSet = new HashSet<HelenusEntity>();
Set<HelenusEntity> stack = new HashSet<HelenusEntity>();
for (UserType userType : km.getUserTypes()) { sessionRepository.entities().stream()
sessionRepository.addUserType(userType.getTypeName(), userType); .filter(e -> e.getType() == HelenusEntityType.UDT)
} .collect(Collectors.toCollection(ArrayDeque::new))
} .descendingIterator()
.forEachRemaining(e -> {
private void eachUserTypeInOrder( stack.clear();
UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) { eachUserTypeInRecursion(e, processedSet, stack, userTypeOps, action);
});
Set<HelenusEntity> processedSet = new HashSet<HelenusEntity>(); */
Set<HelenusEntity> stack = new HashSet<HelenusEntity>();
sessionRepository
.entities()
.stream()
.filter(e -> e.getType() == HelenusEntityType.UDT)
.forEach(
e -> {
stack.clear();
eachUserTypeInRecursion(e, processedSet, stack, userTypeOps, action);
});
}
private void eachUserTypeInReverseOrder(
UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) {
ArrayDeque<HelenusEntity> deque = new ArrayDeque<>();
eachUserTypeInOrder(userTypeOps, e -> deque.addFirst(e));
deque
.stream()
.forEach(
e -> {
action.accept(e);
});
}
private void eachUserTypeInRecursion(
HelenusEntity e,
Set<HelenusEntity> processedSet,
Set<HelenusEntity> stack,
UserTypeOperations userTypeOps,
Consumer<? super HelenusEntity> action) {
stack.add(e);
Collection<HelenusEntity> createBefore = sessionRepository.getUserTypeUses(e);
for (HelenusEntity be : createBefore) {
if (!processedSet.contains(be) && !stack.contains(be)) {
eachUserTypeInRecursion(be, processedSet, stack, userTypeOps, action);
processedSet.add(be);
}
} }
if (!processedSet.contains(e)) { private void eachUserTypeInRecursion(HelenusEntity e, Set<HelenusEntity> processedSet, Set<HelenusEntity> stack,
action.accept(e); UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) {
processedSet.add(e);
}
}
private KeyspaceMetadata getKeyspaceMetadata() { stack.add(e);
if (keyspaceMetadata == null) {
keyspaceMetadata =
session.getCluster().getMetadata().getKeyspace(usingKeyspace.toLowerCase());
}
return keyspaceMetadata;
}
private TableMetadata getTableMetadata(HelenusEntity entity) { Collection<HelenusEntity> createBefore = sessionRepository.getUserTypeUses(e);
return getKeyspaceMetadata().getTable(entity.getName().getName());
}
private UserType getUserType(HelenusEntity entity) { for (HelenusEntity be : createBefore) {
return getKeyspaceMetadata().getUserType(entity.getName().getName()); if (!processedSet.contains(be) && !stack.contains(be)) {
} eachUserTypeInRecursion(be, processedSet, stack, userTypeOps, action);
processedSet.add(be);
}
}
if (!processedSet.contains(e)) {
action.accept(e);
processedSet.add(e);
}
}
private KeyspaceMetadata getKeyspaceMetadata() {
if (keyspaceMetadata == null) {
keyspaceMetadata = session.getCluster().getMetadata().getKeyspace(usingKeyspace.toLowerCase());
}
return keyspaceMetadata;
}
private TableMetadata getTableMetadata(HelenusEntity entity) {
return getKeyspaceMetadata().getTable(entity.getName().getName());
}
private UserType getUserType(HelenusEntity entity) {
return getKeyspaceMetadata().getUserType(entity.getName().getName());
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,30 +15,32 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.Collection;
import com.datastax.driver.core.UserType; import com.datastax.driver.core.UserType;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.util.Collection;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
public final class SessionRepository { public final class SessionRepository {
private final ImmutableMap<String, UserType> userTypeMap; private final ImmutableMap<String, UserType> userTypeMap;
private final ImmutableMap<Class<?>, HelenusEntity> entityMap; private final ImmutableMap<Class<?>, HelenusEntity> entityMap;
public SessionRepository(SessionRepositoryBuilder builder) { public SessionRepository(SessionRepositoryBuilder builder) {
userTypeMap = ImmutableMap.<String, UserType>builder().putAll(builder.getUserTypeMap()).build(); userTypeMap = ImmutableMap.<String, UserType>builder().putAll(builder.getUserTypeMap()).build();
entityMap = entityMap = ImmutableMap.<Class<?>, HelenusEntity>builder().putAll(builder.getEntityMap()).build();
ImmutableMap.<Class<?>, HelenusEntity>builder().putAll(builder.getEntityMap()).build(); }
}
public UserType findUserType(String name) { public UserType findUserType(String name) {
return userTypeMap.get(name.toLowerCase()); return userTypeMap.get(name.toLowerCase());
} }
public Collection<HelenusEntity> entities() {
return entityMap.values();
}
public Collection<HelenusEntity> entities() {
return entityMap.values();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,15 +15,17 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import com.datastax.driver.core.Session; import com.datastax.driver.core.Session;
import com.datastax.driver.core.UDTValue; import com.datastax.driver.core.UDTValue;
import com.datastax.driver.core.UserType; import com.datastax.driver.core.UserType;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusEntityType; import net.helenus.mapping.HelenusEntityType;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
@ -34,112 +35,118 @@ import net.helenus.support.HelenusMappingException;
public final class SessionRepositoryBuilder { public final class SessionRepositoryBuilder {
private static final Optional<HelenusEntityType> OPTIONAL_UDT = private static final Optional<HelenusEntityType> OPTIONAL_UDT = Optional.of(HelenusEntityType.UDT);
Optional.of(HelenusEntityType.UDT);
private final Map<Class<?>, HelenusEntity> entityMap = new HashMap<Class<?>, HelenusEntity>(); private final Map<Class<?>, HelenusEntity> entityMap = new HashMap<Class<?>, HelenusEntity>();
private final Map<String, UserType> userTypeMap = new HashMap<String, UserType>(); private final Map<String, UserType> userTypeMap = new HashMap<String, UserType>();
private final Multimap<HelenusEntity, HelenusEntity> userTypeUsesMap = HashMultimap.create(); private final Multimap<HelenusEntity, HelenusEntity> userTypeUsesMap = HashMultimap.create();
private final Session session; private final Session session;
SessionRepositoryBuilder(Session session) {
this.session = session;
}
public SessionRepository build() { SessionRepositoryBuilder(Session session) {
return new SessionRepository(this); this.session = session;
} }
public Collection<HelenusEntity> getUserTypeUses(HelenusEntity udtName) { public SessionRepository build() {
return userTypeUsesMap.get(udtName); return new SessionRepository(this);
} }
public Collection<HelenusEntity> entities() { public Collection<HelenusEntity> getUserTypeUses(HelenusEntity udtName) {
return entityMap.values(); return userTypeUsesMap.get(udtName);
} }
protected Map<Class<?>, HelenusEntity> getEntityMap() { public Collection<HelenusEntity> entities() {
return entityMap; return entityMap.values();
} }
protected Map<String, UserType> getUserTypeMap() { protected Map<Class<?>, HelenusEntity> getEntityMap() {
return userTypeMap; return entityMap;
} }
public void addUserType(String name, UserType userType) { protected Map<String, UserType> getUserTypeMap() {
userTypeMap.putIfAbsent(name.toLowerCase(), userType); return userTypeMap;
} }
public HelenusEntity add(Object dsl) { public void addUserType(String name, UserType userType) {
return add(dsl, Optional.empty()); userTypeMap.putIfAbsent(name.toLowerCase(), userType);
} }
public void addEntity(HelenusEntity entity) { public HelenusEntity add(Object dsl) {
return add(dsl, Optional.empty());
}
HelenusEntity concurrentEntity = entityMap.putIfAbsent(entity.getMappingInterface(), entity); public void addEntity(HelenusEntity entity) {
if (concurrentEntity == null) { HelenusEntity concurrentEntity = entityMap.putIfAbsent(entity.getMappingInterface(), entity);
addUserDefinedTypes(entity.getOrderedProperties());
}
}
public HelenusEntity add(Object dsl, Optional<HelenusEntityType> type) { if (concurrentEntity == null) {
addUserDefinedTypes(entity.getOrderedProperties());
}
HelenusEntity helenusEntity = Helenus.resolve(dsl, session.getCluster().getMetadata()); }
Class<?> iface = helenusEntity.getMappingInterface(); public HelenusEntity add(Object dsl, Optional<HelenusEntityType> type) {
HelenusEntity entity = entityMap.get(iface); HelenusEntity helenusEntity = Helenus.resolve(dsl, session.getCluster().getMetadata());
if (entity == null) { Class<?> iface = helenusEntity.getMappingInterface();
entity = helenusEntity; HelenusEntity entity = entityMap.get(iface);
if (type.isPresent() && entity.getType() != type.get()) { if (entity == null) {
throw new HelenusMappingException(
"unexpected entity type " + entity.getType() + " for " + entity);
}
HelenusEntity concurrentEntity = entityMap.putIfAbsent(iface, entity); entity = helenusEntity;
if (concurrentEntity == null) { if (type.isPresent() && entity.getType() != type.get()) {
addUserDefinedTypes(entity.getOrderedProperties()); throw new HelenusMappingException("unexpected entity type " + entity.getType() + " for " + entity);
} else { }
entity = concurrentEntity;
}
}
return entity; HelenusEntity concurrentEntity = entityMap.putIfAbsent(iface, entity);
}
private void addUserDefinedTypes(Collection<HelenusProperty> props) { if (concurrentEntity == null) {
addUserDefinedTypes(entity.getOrderedProperties());
} else {
entity = concurrentEntity;
}
for (HelenusProperty prop : props) { }
AbstractDataType type = prop.getDataType(); return entity;
}
if (type instanceof DTDataType) { private void addUserDefinedTypes(Collection<HelenusProperty> props) {
continue;
}
if (!UDTValue.class.isAssignableFrom(prop.getJavaType())) { for (HelenusProperty prop : props) {
for (Class<?> udtClass : type.getTypeArguments()) { AbstractDataType type = prop.getDataType();
if (UDTValue.class.isAssignableFrom(udtClass)) { if (type instanceof DTDataType) {
continue; continue;
} }
HelenusEntity addedUserType = add(udtClass, OPTIONAL_UDT); if (!UDTValue.class.isAssignableFrom(prop.getJavaType())) {
for (Class<?> udtClass : type.getTypeArguments()) {
if (UDTValue.class.isAssignableFrom(udtClass)) {
continue;
}
HelenusEntity addedUserType = add(udtClass, OPTIONAL_UDT);
if (HelenusEntityType.UDT == prop.getEntity().getType()) {
userTypeUsesMap.put(prop.getEntity(), addedUserType);
}
}
}
}
}
if (HelenusEntityType.UDT == prop.getEntity().getType()) {
userTypeUsesMap.put(prop.getEntity(), addedUserType);
}
}
}
}
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,92 +15,74 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.List;
import com.datastax.driver.core.TableMetadata; import com.datastax.driver.core.TableMetadata;
import com.datastax.driver.core.schemabuilder.SchemaStatement; import com.datastax.driver.core.schemabuilder.SchemaStatement;
import java.util.List;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
public final class TableOperations { public final class TableOperations {
private final AbstractSessionOperations sessionOps; private final AbstractSessionOperations sessionOps;
private final boolean dropUnusedColumns; private final boolean dropUnusedColumns;
private final boolean dropUnusedIndexes; private final boolean dropUnusedIndexes;
public TableOperations( public TableOperations(AbstractSessionOperations sessionOps, boolean dropUnusedColumns, boolean dropUnusedIndexes) {
AbstractSessionOperations sessionOps, boolean dropUnusedColumns, boolean dropUnusedIndexes) { this.sessionOps = sessionOps;
this.sessionOps = sessionOps; this.dropUnusedColumns = dropUnusedColumns;
this.dropUnusedColumns = dropUnusedColumns; this.dropUnusedIndexes = dropUnusedIndexes;
this.dropUnusedIndexes = dropUnusedIndexes; }
}
public void createTable(HelenusEntity entity) { public void createTable(HelenusEntity entity) {
sessionOps.execute(SchemaUtil.createTable(entity));
executeBatch(SchemaUtil.createIndexes(entity));
}
public void dropTable(HelenusEntity entity) { sessionOps.execute(SchemaUtil.createTable(entity), true);
sessionOps.execute(SchemaUtil.dropTable(entity));
}
public void validateTable(TableMetadata tmd, HelenusEntity entity) { executeBatch(SchemaUtil.createIndexes(entity));
}
public void dropTable(HelenusEntity entity) {
sessionOps.execute(SchemaUtil.dropTable(entity), true);
if (tmd == null) {
throw new HelenusException(
"table does not exists "
+ entity.getName()
+ "for entity "
+ entity.getMappingInterface());
} }
List<SchemaStatement> list = SchemaUtil.alterTable(tmd, entity, dropUnusedColumns); public void validateTable(TableMetadata tmd, HelenusEntity entity) {
list.addAll(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes)); if (tmd == null) {
throw new HelenusException(
"table not exists " + entity.getName() + "for entity " + entity.getMappingInterface());
}
if (!list.isEmpty()) { List<SchemaStatement> list = SchemaUtil.alterTable(tmd, entity, dropUnusedColumns);
throw new HelenusException(
"schema changed for entity "
+ entity.getMappingInterface()
+ ", apply this command: "
+ list);
}
}
public void updateTable(TableMetadata tmd, HelenusEntity entity) { list.addAll(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
if (tmd == null) {
createTable(entity);
return;
}
executeBatch(SchemaUtil.alterTable(tmd, entity, dropUnusedColumns)); if (!list.isEmpty()) {
executeBatch(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes)); throw new HelenusException(
} "schema changed for entity " + entity.getMappingInterface() + ", apply this command: " + list);
}
}
public void createView(HelenusEntity entity) { public void updateTable(TableMetadata tmd, HelenusEntity entity) {
sessionOps.execute(
SchemaUtil.createMaterializedView(
sessionOps.usingKeyspace(), entity.getName().toCql(), entity));
// executeBatch(SchemaUtil.createIndexes(entity)); NOTE: Unfortunately C* 3.10 does not yet support 2i on materialized views.
}
public void dropView(HelenusEntity entity) { if (tmd == null) {
sessionOps.execute( createTable(entity);
SchemaUtil.dropMaterializedView( return;
sessionOps.usingKeyspace(), entity.getName().toCql(), entity)); }
}
public void updateView(TableMetadata tmd, HelenusEntity entity) { executeBatch(SchemaUtil.alterTable(tmd, entity, dropUnusedColumns));
if (tmd == null) { executeBatch(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
createTable(entity); }
return;
}
executeBatch(SchemaUtil.alterTable(tmd, entity, dropUnusedColumns)); private void executeBatch(List<SchemaStatement> list) {
executeBatch(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
}
private void executeBatch(List<SchemaStatement> list) { list.forEach(s -> {
sessionOps.execute(s, true);
});
}
list.forEach(s -> sessionOps.execute(s));
}
} }

View file

@ -1,816 +1,60 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core; package net.helenus.core;
import static net.helenus.core.HelenusSession.deleted;
import com.google.common.base.Stopwatch;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.google.common.collect.TreeTraverser;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.configuration.Configuration;
import javax.cache.integration.CacheLoader;
import javax.cache.integration.CacheLoaderException;
import javax.cache.integration.CompletionListener;
import javax.cache.processor.EntryProcessor;
import javax.cache.processor.EntryProcessorException;
import javax.cache.processor.EntryProcessorResult;
import net.helenus.core.cache.CacheUtil; /**
import net.helenus.core.cache.Facet; * Encapsulates the concept of a "transaction" as a unit-of-work.
import net.helenus.core.cache.MapCache; */
import net.helenus.core.operation.AbstractOperation; public class UnitOfWork {
import net.helenus.core.operation.BatchOperation;
import net.helenus.mapping.MappingUtil; private final HelenusSession session;
import net.helenus.support.CheckedRunnable; private ArrayList<UnitOfWork> nested;
import net.helenus.support.Either;
import net.helenus.support.HelenusException; UnitOfWork(HelenusSession session) {
import org.apache.commons.lang3.SerializationUtils; this.session = session;
import org.apache.commons.lang3.StringUtils; // log.record(txn::start)
import org.slf4j.Logger; }
import org.slf4j.LoggerFactory;
/**
* Marks the beginning of a transactional section of work. Will write a record
* to the shared write-ahead log.
*
* @return the handle used to commit or abort the work.
*/
public UnitOfWork begin() {
if (nested == null) {
nested = new ArrayList<UnitOfWork>();
}
UnitOfWork unitOfWork = new UnitOfWork(session);
nested.add(unitOfWork);
return unitOfWork;
}
/**
* Checks to see if the work performed between calling begin and now can be
* committed or not.
*
* @throws ConflictingUnitOfWorkException
* when the work overlaps with other concurrent writers.
*/
public void commit() throws ConflictingUnitOfWorkException {
// nested.foreach.commit()
// log.record(txn::provisionalCommit)
// examine log for conflicts in read-set and write-set between begin and
// provisional commit
// if (conflict) { throw new ConflictingUnitOfWorkException(this) }
}
/**
* Explicitly discard the work and mark it as as such in the log.
*/
public void abort() {
// log.record(txn::abort)
// cache.invalidateSince(txn::start time)
}
public String describeConflicts() {
return "it's complex...";
}
/** Encapsulates the concept of a "transaction" as a unit-of-work. */
public class UnitOfWork implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(UnitOfWork.class);
public final UnitOfWork parent;
protected final List<UnitOfWork> nested = new ArrayList<>();
protected final Table<String, String, Either<Object, List<Facet>>> cache = HashBasedTable.create();
protected final EvictTrackingMapCache<String, Object> statementCache;
protected final HelenusSession session;
protected String purpose;
protected List<String> nestedPurposes = new ArrayList<String>();
protected String info;
protected int cacheHits = 0;
protected int cacheMisses = 0;
protected int databaseLookups = 0;
protected final Stopwatch elapsedTime;
protected Map<String, Double> databaseTime = new HashMap<>();
protected double cacheLookupTimeMSecs = 0.0;
private List<CheckedRunnable> commitThunks = new ArrayList<>();
private List<CheckedRunnable> abortThunks = new ArrayList<>();
private Consumer<? super Throwable> exceptionallyThunk;
private List<CompletableFuture<?>> asyncOperationFutures = new ArrayList<CompletableFuture<?>>();
private boolean aborted = false;
private boolean committed = false;
private long committedAt = 0L;
private BatchOperation batch;
public UnitOfWork(HelenusSession session) {
this(session, null);
}
public UnitOfWork(HelenusSession session, UnitOfWork parent) {
Objects.requireNonNull(session, "containing session cannot be null");
this.parent = parent;
if (parent != null) {
parent.addNestedUnitOfWork(this);
}
this.session = session;
CacheLoader<String, Object> cacheLoader = null;
if (parent != null) {
cacheLoader =
new CacheLoader<String, Object>() {
Cache<String, Object> cache = parent.getCache();
@Override
public Object load(String key) throws CacheLoaderException {
return cache.get(key);
}
@Override
public Map<String, Object> loadAll(Iterable<? extends String> keys)
throws CacheLoaderException {
Map<String, Object> kvp = new HashMap<String, Object>();
for (String key : keys) {
kvp.put(key, cache.get(key));
}
return kvp;
}
};
}
this.elapsedTime = Stopwatch.createUnstarted();
this.statementCache = new EvictTrackingMapCache<String, Object>(null, "UOW(" + hashCode() + ")", cacheLoader, true);
}
public void addDatabaseTime(String name, Stopwatch amount) {
Double time = databaseTime.get(name);
if (time == null) {
databaseTime.put(name, (double) amount.elapsed(TimeUnit.MICROSECONDS));
} else {
databaseTime.put(name, time + amount.elapsed(TimeUnit.MICROSECONDS));
}
}
public void addCacheLookupTime(Stopwatch amount) {
cacheLookupTimeMSecs += amount.elapsed(TimeUnit.MICROSECONDS);
}
public void addNestedUnitOfWork(UnitOfWork uow) {
synchronized (nested) {
nested.add(uow);
}
}
/**
* Marks the beginning of a transactional section of work. Will write a
* recordCacheAndDatabaseOperationCount to the shared write-ahead log.
*
* @return the handle used to commit or abort the work.
*/
public synchronized UnitOfWork begin() {
elapsedTime.start();
// log.record(txn::start)
return this;
}
public String getPurpose() {
return purpose;
}
public UnitOfWork setPurpose(String purpose) {
this.purpose = purpose;
return this;
}
public void addFuture(CompletableFuture<?> future) {
asyncOperationFutures.add(future);
}
public void setInfo(String info) {
this.info = info;
}
public void recordCacheAndDatabaseOperationCount(int cache, int ops) {
if (cache > 0) {
cacheHits += cache;
} else {
cacheMisses += Math.abs(cache);
}
if (ops > 0) {
databaseLookups += ops;
}
}
public String logTimers(String what) {
double e = (double) elapsedTime.elapsed(TimeUnit.MICROSECONDS) / 1000.0;
double d = 0.0;
double c = cacheLookupTimeMSecs / 1000.0;
double fc = (c / e) * 100.0;
String database = "";
if (databaseTime.size() > 0) {
List<String> dbt = new ArrayList<>(databaseTime.size());
for (Map.Entry<String, Double> dt : databaseTime.entrySet()) {
double t = dt.getValue() / 1000.0;
d += t;
dbt.add(String.format("%s took %,.3fms %,2.2f%%", dt.getKey(), t, (t / e) * 100.0));
}
double fd = (d / e) * 100.0;
database =
String.format(
", %d quer%s (%,.3fms %,2.2f%% - %s)",
databaseLookups, (databaseLookups > 1) ? "ies" : "y", d, fd, String.join(", ", dbt));
}
String cache = "";
if (cacheLookupTimeMSecs > 0) {
int cacheLookups = cacheHits + cacheMisses;
cache =
String.format(
" with %d cache lookup%s (%,.3fms %,2.2f%% - %,d hit, %,d miss)",
cacheLookups, cacheLookups > 1 ? "s" : "", c, fc, cacheHits, cacheMisses);
}
String da = "";
if (databaseTime.size() > 0 || cacheLookupTimeMSecs > 0) {
double dat = d + c;
double daf = (dat / e) * 100;
da =
String.format(
" consuming %,.3fms for data access, or %,2.2f%% of total UOW time.", dat, daf);
}
String x = nestedPurposes.stream().distinct().collect(Collectors.joining(", "));
String n =
nested
.stream()
.map(uow -> String.valueOf(uow.hashCode()))
.collect(Collectors.joining(", "));
String s =
String.format(
Locale.US,
"UOW(%s%s) %s in %,.3fms%s%s%s%s%s%s",
hashCode(),
(nested.size() > 0 ? ", [" + n + "]" : ""),
what,
e,
cache,
database,
da,
(purpose == null ? "" : " " + purpose),
(nestedPurposes.isEmpty()) ? "" : ", " + x,
(info == null) ? "" : " " + info);
return s;
}
private void applyPostCommitFunctions(String what, List<CheckedRunnable> thunks, Consumer<? super Throwable> exceptionallyThunk) {
if (!thunks.isEmpty()) {
for (CheckedRunnable f : thunks) {
try {
f.run();
} catch (Throwable t) {
if (exceptionallyThunk != null) {
exceptionallyThunk.accept(t);
}
}
}
}
}
public Optional<Object> cacheLookup(List<Facet> facets) {
String tableName = CacheUtil.schemaName(facets);
Optional<Object> result = Optional.empty();
for (Facet facet : facets) {
if (!facet.fixed()) {
String columnName = facet.name() + "==" + facet.value();
Either<Object, List<Facet>> eitherValue = cache.get(tableName, columnName);
if (eitherValue != null) {
Object value = deleted;
if (eitherValue.isLeft()) {
value = eitherValue.getLeft();
}
return Optional.of(value);
}
}
}
// Be sure to check all enclosing UnitOfWork caches as well, we may be nested.
result = checkParentCache(facets);
if (result.isPresent()) {
Object r = result.get();
Class<?> iface = MappingUtil.getMappingInterface(r);
if (Helenus.entity(iface).isDraftable()) {
cacheUpdate(r, facets);
} else {
cacheUpdate(SerializationUtils.<Serializable>clone((Serializable) r), facets);
}
}
return result;
}
private Optional<Object> checkParentCache(List<Facet> facets) {
Optional<Object> result = Optional.empty();
if (parent != null) {
result = parent.checkParentCache(facets);
}
return result;
}
public List<Facet> cacheEvict(List<Facet> facets) {
Either<Object, List<Facet>> deletedObjectFacets = Either.right(facets);
String tableName = CacheUtil.schemaName(facets);
Optional<Object> optionalValue = cacheLookup(facets);
for (Facet facet : facets) {
if (!facet.fixed()) {
String columnKey = facet.name() + "==" + facet.value();
// mark the value identified by the facet to `deleted`
cache.put(tableName, columnKey, deletedObjectFacets);
}
}
// Now, look for other row/col pairs that referenced the same object, mark them
// `deleted` if the cache had a value before we added the deleted marker objects.
if (optionalValue.isPresent()) {
Object value = optionalValue.get();
cache
.columnKeySet()
.forEach(
columnKey -> {
Either<Object, List<Facet>> eitherCachedValue = cache.get(tableName, columnKey);
if (eitherCachedValue.isLeft()) {
Object cachedValue = eitherCachedValue.getLeft();
if (cachedValue == value) {
cache.put(tableName, columnKey, deletedObjectFacets);
String[] parts = columnKey.split("==");
facets.add(new Facet<String>(parts[0], parts[1]));
}
}
});
}
return facets;
}
public Cache<String, Object> getCache() {
return statementCache;
}
public Object cacheUpdate(Object value, List<Facet> facets) {
Object result = null;
String tableName = CacheUtil.schemaName(facets);
for (Facet facet : facets) {
if (!facet.fixed()) {
if (facet.alone()) {
String columnName = facet.name() + "==" + facet.value();
if (result == null) result = cache.get(tableName, columnName);
cache.put(tableName, columnName, Either.left(value));
}
}
}
return result;
}
public void batch(AbstractOperation s) {
if (batch == null) {
batch = new BatchOperation(session);
}
batch.add(s);
}
private Iterator<UnitOfWork> getChildNodes() {
return nested.iterator();
}
/**
* Checks to see if the work performed between calling begin and now can be committed or not.
*
* @return a function from which to chain work that only happens when commit is successful
* @throws HelenusException when the work overlaps with other concurrent writers.
*/
public synchronized PostCommitFunction<Void, Void> commit() throws HelenusException {
if (isDone()) {
return PostCommitFunction.NULL_ABORT;
}
// Only the outer-most UOW batches statements for commit time, execute them.
if (batch != null) {
committedAt = batch.sync(this); //TODO(gburd): update cache with writeTime...
}
// All nested UnitOfWork should be committed (not aborted) before calls to
// commit, check.
boolean canCommit = true;
TreeTraverser<UnitOfWork> traverser = TreeTraverser.using(node -> node::getChildNodes);
for (UnitOfWork uow : traverser.postOrderTraversal(this)) {
if (this != uow) {
canCommit &= (!uow.aborted && uow.committed);
}
}
if (!canCommit) {
if (parent == null) {
// Apply all post-commit abort functions, this is the outer-most UnitOfWork.
traverser
.postOrderTraversal(this)
.forEach(
uow -> {
applyPostCommitFunctions("aborted", abortThunks, exceptionallyThunk);
});
elapsedTime.stop();
if (LOG.isInfoEnabled()) {
LOG.info(logTimers("aborted"));
}
}
return PostCommitFunction.NULL_ABORT;
} else {
committed = true;
aborted = false;
if (parent == null) {
// Apply all post-commit commit functions, this is the outer-most UnitOfWork.
traverser
.postOrderTraversal(this)
.forEach(
uow -> {
applyPostCommitFunctions("committed", uow.commitThunks, exceptionallyThunk);
});
// Merge our statement cache into the session cache if it exists.
CacheManager cacheManager = session.getCacheManager();
if (cacheManager != null) {
for (Map.Entry<String, Object> entry :
(Set<Map.Entry<String, Object>>) statementCache.<Map>unwrap(Map.class).entrySet()) {
String[] keyParts = entry.getKey().split("\\.");
if (keyParts.length == 2) {
String cacheName = keyParts[0];
String key = keyParts[1];
if (!StringUtils.isBlank(cacheName) && !StringUtils.isBlank(key)) {
Cache<Object, Object> cache = cacheManager.getCache(cacheName);
if (cache != null) {
Object value = entry.getValue();
if (value == deleted) {
cache.remove(key);
} else {
cache.put(key.toString(), value);
}
}
}
}
}
}
// Merge our cache into the session cache.
session.mergeCache(cache);
// Spoil any lingering futures that may be out there.
asyncOperationFutures.forEach(
f ->
f.completeExceptionally(
new HelenusException(
"Futures must be resolved before their unit of work has committed/aborted.")));
elapsedTime.stop();
if (LOG.isInfoEnabled()) {
LOG.info(logTimers("committed"));
}
return PostCommitFunction.NULL_COMMIT;
} else {
// Merge cache and statistics into parent if there is one.
parent.statementCache.putAll(statementCache.<Map>unwrap(Map.class));
parent.statementCache.removeAll(statementCache.getDeletions());
parent.mergeCache(cache);
parent.addBatched(batch);
if (purpose != null) {
parent.nestedPurposes.add(purpose);
}
parent.cacheHits += cacheHits;
parent.cacheMisses += cacheMisses;
parent.databaseLookups += databaseLookups;
parent.cacheLookupTimeMSecs += cacheLookupTimeMSecs;
for (Map.Entry<String, Double> dt : databaseTime.entrySet()) {
String name = dt.getKey();
if (parent.databaseTime.containsKey(name)) {
double t = parent.databaseTime.get(name);
parent.databaseTime.put(name, t + dt.getValue());
} else {
parent.databaseTime.put(name, dt.getValue());
}
}
}
}
// TODO(gburd): hopefully we'll be able to detect conflicts here and so we'd want to...
// else {
// Constructor<T> ctor = clazz.getConstructor(conflictExceptionClass);
// T object = ctor.newInstance(new Object[] { String message });
// }
return new PostCommitFunction<Void, Void>(commitThunks, abortThunks, exceptionallyThunk, true);
}
private void addBatched(BatchOperation batchArg) {
if (batchArg != null) {
if (this.batch == null) {
this.batch = batchArg;
} else {
this.batch.addAll(batchArg);
}
}
}
/**
* Explicitly abort the work within this unit of work. Any nested aborted unit of work will
* trigger the entire unit of work to commit.
*/
public synchronized void abort() {
if (!aborted) {
aborted = true;
// Spoil any pending futures created within the context of this unit of work.
asyncOperationFutures.forEach(
f ->
f.completeExceptionally(
new HelenusException(
"Futures must be resolved before their unit of work has committed/aborted.")));
TreeTraverser<UnitOfWork> traverser = TreeTraverser.using(node -> node::getChildNodes);
traverser
.postOrderTraversal(this)
.forEach(
uow -> {
applyPostCommitFunctions("aborted", uow.abortThunks, exceptionallyThunk);
uow.abortThunks.clear();
});
if (parent == null) {
if (elapsedTime.isRunning()) {
elapsedTime.stop();
}
if (LOG.isInfoEnabled()) {
LOG.info(logTimers("aborted"));
}
}
// TODO(gburd): when we integrate the transaction support we'll need to...
// log.record(txn::abort)
// cache.invalidateSince(txn::start time)
}
}
private void mergeCache(Table<String, String, Either<Object, List<Facet>>> from) {
Table<String, String, Either<Object, List<Facet>>> to = this.cache;
from.rowMap()
.forEach(
(rowKey, columnMap) -> {
columnMap.forEach(
(columnKey, value) -> {
if (to.contains(rowKey, columnKey)) {
to.put(
rowKey,
columnKey,
Either.left(
CacheUtil.merge(
to.get(rowKey, columnKey).getLeft(),
from.get(rowKey, columnKey).getLeft())));
} else {
to.put(rowKey, columnKey, from.get(rowKey, columnKey));
}
});
});
}
public boolean isDone() {
return aborted || committed;
}
public String describeConflicts() {
return "it's complex...";
}
@Override
public void close() throws HelenusException {
// Closing a UnitOfWork will abort iff we've not already aborted or committed this unit of work.
if (aborted == false && committed == false) {
abort();
}
}
public boolean hasAborted() {
return aborted;
}
public boolean hasCommitted() {
return committed;
}
public long committedAt() {
return committedAt;
}
private static class EvictTrackingMapCache<K, V> implements Cache<K, V> {
private final Set<K> deletes;
private final Cache<K, V> delegate;
public EvictTrackingMapCache(CacheManager manager, String name, CacheLoader<K, V> cacheLoader,
boolean isReadThrough) {
deletes = Collections.synchronizedSet(new HashSet<>());
delegate = new MapCache<>(manager, name, cacheLoader, isReadThrough);
}
/** Non-interface method; should only be called by UnitOfWork when merging to an enclosing UnitOfWork. */
public Set<K> getDeletions() {
return new HashSet<>(deletes);
}
@Override
public V get(K key) {
if (deletes.contains(key)) {
return null;
}
return delegate.get(key);
}
@Override
public Map<K, V> getAll(Set<? extends K> keys) {
Set<? extends K> clonedKeys = new HashSet<>(keys);
clonedKeys.removeAll(deletes);
return delegate.getAll(clonedKeys);
}
@Override
public boolean containsKey(K key) {
if (deletes.contains(key)) {
return false;
}
return delegate.containsKey(key);
}
@Override
public void loadAll(Set<? extends K> keys, boolean replaceExistingValues, CompletionListener listener) {
Set<? extends K> clonedKeys = new HashSet<>(keys);
clonedKeys.removeAll(deletes);
delegate.loadAll(clonedKeys, replaceExistingValues, listener);
}
@Override
public void put(K key, V value) {
if (deletes.contains(key)) {
deletes.remove(key);
}
delegate.put(key, value);
}
@Override
public V getAndPut(K key, V value) {
if (deletes.contains(key)) {
deletes.remove(key);
}
return delegate.getAndPut(key, value);
}
@Override
public void putAll(Map<? extends K, ? extends V> map) {
deletes.removeAll(map.keySet());
delegate.putAll(map);
}
@Override
public synchronized boolean putIfAbsent(K key, V value) {
if (!delegate.containsKey(key) && deletes.contains(key)) {
deletes.remove(key);
}
return delegate.putIfAbsent(key, value);
}
@Override
public boolean remove(K key) {
boolean removed = delegate.remove(key);
deletes.add(key);
return removed;
}
@Override
public boolean remove(K key, V value) {
boolean removed = delegate.remove(key, value);
if (removed) {
deletes.add(key);
}
return removed;
}
@Override
public V getAndRemove(K key) {
V value = delegate.getAndRemove(key);
deletes.add(key);
return value;
}
@Override
public void removeAll(Set<? extends K> keys) {
Set<? extends K> cloneKeys = new HashSet<>(keys);
delegate.removeAll(cloneKeys);
deletes.addAll(cloneKeys);
}
@Override
@SuppressWarnings("unchecked")
public synchronized void removeAll() {
Map<K, V> impl = delegate.unwrap(Map.class);
Set<K> keys = impl.keySet();
delegate.removeAll();
deletes.addAll(keys);
}
@Override
public void clear() {
delegate.clear();
// TODO(gburd): all parents too
deletes.clear();
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
if (deletes.contains(key)) {
return false;
}
return delegate.replace(key, oldValue, newValue);
}
@Override
public boolean replace(K key, V value) {
if (deletes.contains(key)) {
return false;
}
return delegate.replace(key, value);
}
@Override
public V getAndReplace(K key, V value) {
if (deletes.contains(key)) {
return null;
}
return delegate.getAndReplace(key, value);
}
@Override
public <C extends Configuration<K, V>> C getConfiguration(Class<C> clazz) {
return delegate.getConfiguration(clazz);
}
@Override
public <T> T invoke(K key, EntryProcessor<K, V, T> processor, Object... arguments)
throws EntryProcessorException {
if (deletes.contains(key)) {
return null;
}
return delegate.invoke(key, processor, arguments);
}
@Override
public <T> Map<K, EntryProcessorResult<T>> invokeAll(Set<? extends K> keys, EntryProcessor<K, V, T> processor,
Object... arguments) {
Set<? extends K> clonedKeys = new HashSet<>(keys);
clonedKeys.removeAll(deletes);
return delegate.invokeAll(clonedKeys, processor, arguments);
}
@Override
public String getName() {
return delegate.getName();
}
@Override
public CacheManager getCacheManager() {
return delegate.getCacheManager();
}
@Override
public void close() {
delegate.close();
}
@Override
public boolean isClosed() {
return delegate.isClosed();
}
@Override
public <T> T unwrap(Class<T> clazz) {
return delegate.unwrap(clazz);
}
@Override
public void registerCacheEntryListener(CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {
delegate.registerCacheEntryListener(cacheEntryListenerConfiguration);
}
@Override
public void deregisterCacheEntryListener(CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {
delegate.deregisterCacheEntryListener(cacheEntryListenerConfiguration);
}
@Override
public Iterator<Entry<K, V>> iterator() {
return delegate.iterator();
}
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,62 +15,69 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.List;
import com.datastax.driver.core.UserType; import com.datastax.driver.core.UserType;
import com.datastax.driver.core.schemabuilder.SchemaStatement; import com.datastax.driver.core.schemabuilder.SchemaStatement;
import java.util.List;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
public final class UserTypeOperations { public final class UserTypeOperations {
private final AbstractSessionOperations sessionOps; private final AbstractSessionOperations sessionOps;
private final boolean dropUnusedColumns; private final boolean dropUnusedColumns;
public UserTypeOperations(AbstractSessionOperations sessionOps, boolean dropUnusedColumns) { public UserTypeOperations(AbstractSessionOperations sessionOps, boolean dropUnusedColumns) {
this.sessionOps = sessionOps; this.sessionOps = sessionOps;
this.dropUnusedColumns = dropUnusedColumns; this.dropUnusedColumns = dropUnusedColumns;
} }
public void createUserType(HelenusEntity entity) { public void createUserType(HelenusEntity entity) {
sessionOps.execute(SchemaUtil.createUserType(entity)); sessionOps.execute(SchemaUtil.createUserType(entity), true);
}
public void dropUserType(HelenusEntity entity) { }
sessionOps.execute(SchemaUtil.dropUserType(entity)); public void dropUserType(HelenusEntity entity) {
}
public void validateUserType(UserType userType, HelenusEntity entity) { sessionOps.execute(SchemaUtil.dropUserType(entity), true);
if (userType == null) {
throw new HelenusException(
"userType not exists " + entity.getName() + "for entity " + entity.getMappingInterface());
} }
List<SchemaStatement> list = SchemaUtil.alterUserType(userType, entity, dropUnusedColumns); public void validateUserType(UserType userType, HelenusEntity entity) {
if (!list.isEmpty()) { if (userType == null) {
throw new HelenusException( throw new HelenusException(
"schema changed for entity " "userType not exists " + entity.getName() + "for entity " + entity.getMappingInterface());
+ entity.getMappingInterface() }
+ ", apply this command: "
+ list);
}
}
public void updateUserType(UserType userType, HelenusEntity entity) { List<SchemaStatement> list = SchemaUtil.alterUserType(userType, entity, dropUnusedColumns);
if (userType == null) { if (!list.isEmpty()) {
createUserType(entity); throw new HelenusException(
return; "schema changed for entity " + entity.getMappingInterface() + ", apply this command: " + list);
} }
executeBatch(SchemaUtil.alterUserType(userType, entity, dropUnusedColumns)); }
}
private void executeBatch(List<SchemaStatement> list) { public void updateUserType(UserType userType, HelenusEntity entity) {
if (userType == null) {
createUserType(entity);
return;
}
executeBatch(SchemaUtil.alterUserType(userType, entity, dropUnusedColumns));
}
private void executeBatch(List<SchemaStatement> list) {
list.forEach(s -> {
sessionOps.execute(s, true);
});
}
list.forEach(s -> sessionOps.execute(s));
}
} }

View file

@ -1,19 +1,3 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core.annotation; package net.helenus.core.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
@ -23,4 +7,5 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
public @interface Cacheable {} public @interface Cacheable {
}

View file

@ -1,36 +1,17 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core.annotation; package net.helenus.core.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.util.concurrent.TimeoutException;
import net.helenus.core.ConflictingUnitOfWorkException; import net.helenus.core.ConflictingUnitOfWorkException;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface Retry { public @interface Retry {
Class<? extends Exception>[] on() default { Class<? extends Exception>[] on() default ConflictingUnitOfWorkException.class;
ConflictingUnitOfWorkException.class, TimeoutException.class
};
int times() default 3; int times() default 3;
} }

View file

@ -1,98 +0,0 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core.aspect;
import java.lang.reflect.Method;
import java.util.Arrays;
import net.helenus.core.annotation.Retry;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
@Aspect
public class RetryAspect {
private static final Logger log = LoggerFactory.getLogger(RetryAspect.class);
@Around("@annotation(net.helenus.core.annotations.Retry)")
public Object retry(ProceedingJoinPoint pjp) throws Throwable {
Retry retryAnnotation = getRetryAnnotation(pjp);
return (retryAnnotation != null) ? proceed(pjp, retryAnnotation) : proceed(pjp);
}
private Object proceed(ProceedingJoinPoint pjp) throws Throwable {
return pjp.proceed();
}
private Object proceed(ProceedingJoinPoint pjp, Retry retryAnnotation) throws Throwable {
int times = retryAnnotation.times();
Class<? extends Throwable>[] retryOn = retryAnnotation.on();
Assert.isTrue(times > 0, "@Retry{times} should be greater than 0!");
Assert.isTrue(retryOn.length > 0, "@Retry{on} should have at least one Throwable!");
log.info("Proceed with {} retries on {}", times, Arrays.toString(retryOn));
return tryProceeding(pjp, times, retryOn);
}
private Object tryProceeding(
ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn) throws Throwable {
try {
return proceed(pjp);
} catch (Throwable throwable) {
if (isRetryThrowable(throwable, retryOn) && times-- > 0) {
log.info("Conflict detected, {} remaining retries on {}", times, Arrays.toString(retryOn));
return tryProceeding(pjp, times, retryOn);
}
throw throwable;
}
}
private boolean isRetryThrowable(Throwable throwable, Class<? extends Throwable>[] retryOn) {
Throwable[] causes = ExceptionUtils.getThrowables(throwable);
for (Throwable cause : causes) {
for (Class<? extends Throwable> retryThrowable : retryOn) {
if (retryThrowable.isAssignableFrom(cause.getClass())) {
return true;
}
}
}
return false;
}
private Retry getRetryAnnotation(ProceedingJoinPoint pjp) throws NoSuchMethodException {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
Retry retryAnnotation = AnnotationUtils.findAnnotation(method, Retry.class);
if (retryAnnotation != null) {
return retryAnnotation;
}
Class<?>[] argClasses = new Class[pjp.getArgs().length];
for (int i = 0; i < pjp.getArgs().length; i++) {
argClasses[i] = pjp.getArgs()[i].getClass();
}
method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argClasses);
return AnnotationUtils.findAnnotation(method, Retry.class);
}
}

View file

@ -2,7 +2,7 @@ package net.helenus.core.aspect;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import net.helenus.core.annotation.Retry;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Around;
@ -13,69 +13,71 @@ import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import net.helenus.core.annotation.Retry;
@Aspect @Aspect
public class RetryConcurrentUnitOfWorkAspect { public class RetryConcurrentUnitOfWorkAspect {
private static final Logger log = LoggerFactory.getLogger(RetryConcurrentUnitOfWorkAspect.class); private static final Logger log = LoggerFactory.getLogger(RetryConcurrentUnitOfWorkAspect.class);
@Around("@annotation(net.helenus.core.annotations.Retry)") @Around("@annotation(net.helenus.core.annotations.Retry)")
public Object retry(ProceedingJoinPoint pjp) throws Throwable { public Object retry(ProceedingJoinPoint pjp) throws Throwable {
Retry retryAnnotation = getRetryAnnotation(pjp); Retry retryAnnotation = getRetryAnnotation(pjp);
return (retryAnnotation != null) ? proceed(pjp, retryAnnotation) : proceed(pjp); return (retryAnnotation != null) ? proceed(pjp, retryAnnotation) : proceed(pjp);
} }
private Object proceed(ProceedingJoinPoint pjp) throws Throwable { private Object proceed(ProceedingJoinPoint pjp) throws Throwable {
return pjp.proceed(); return pjp.proceed();
} }
private Object proceed(ProceedingJoinPoint pjp, Retry retryAnnotation) throws Throwable { private Object proceed(ProceedingJoinPoint pjp, Retry retryAnnotation) throws Throwable {
int times = retryAnnotation.times(); int times = retryAnnotation.times();
Class<? extends Throwable>[] retryOn = retryAnnotation.on(); Class<? extends Throwable>[] retryOn = retryAnnotation.on();
Assert.isTrue(times > 0, "@Retry{times} should be greater than 0!"); Assert.isTrue(times > 0, "@Retry{times} should be greater than 0!");
Assert.isTrue(retryOn.length > 0, "@Retry{on} should have at least one Throwable!"); Assert.isTrue(retryOn.length > 0, "@Retry{on} should have at least one Throwable!");
log.info("Proceed with {} retries on {}", times, Arrays.toString(retryOn)); log.info("Proceed with {} retries on {}", times, Arrays.toString(retryOn));
return tryProceeding(pjp, times, retryOn); return tryProceeding(pjp, times, retryOn);
} }
private Object tryProceeding( private Object tryProceeding(ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn)
ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn) throws Throwable { throws Throwable {
try { try {
return proceed(pjp); return proceed(pjp);
} catch (Throwable throwable) { } catch (Throwable throwable) {
if (isRetryThrowable(throwable, retryOn) && times-- > 0) { if (isRetryThrowable(throwable, retryOn) && times-- > 0) {
log.info("Conflict detected, {} remaining retries on {}", times, Arrays.toString(retryOn)); log.info("Conflict detected, {} remaining retries on {}", times, Arrays.toString(retryOn));
return tryProceeding(pjp, times, retryOn); return tryProceeding(pjp, times, retryOn);
} }
throw throwable; throw throwable;
} }
} }
private boolean isRetryThrowable(Throwable throwable, Class<? extends Throwable>[] retryOn) { private boolean isRetryThrowable(Throwable throwable, Class<? extends Throwable>[] retryOn) {
Throwable[] causes = ExceptionUtils.getThrowables(throwable); Throwable[] causes = ExceptionUtils.getThrowables(throwable);
for (Throwable cause : causes) { for (Throwable cause : causes) {
for (Class<? extends Throwable> retryThrowable : retryOn) { for (Class<? extends Throwable> retryThrowable : retryOn) {
if (retryThrowable.isAssignableFrom(cause.getClass())) { if (retryThrowable.isAssignableFrom(cause.getClass())) {
return true; return true;
} }
} }
} }
return false; return false;
} }
private Retry getRetryAnnotation(ProceedingJoinPoint pjp) throws NoSuchMethodException { private Retry getRetryAnnotation(ProceedingJoinPoint pjp) throws NoSuchMethodException {
MethodSignature signature = (MethodSignature) pjp.getSignature(); MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod(); Method method = signature.getMethod();
Retry retryAnnotation = AnnotationUtils.findAnnotation(method, Retry.class); Retry retryAnnotation = AnnotationUtils.findAnnotation(method, Retry.class);
if (retryAnnotation != null) { if (retryAnnotation != null) {
return retryAnnotation; return retryAnnotation;
} }
Class[] argClasses = new Class[pjp.getArgs().length]; Class[] argClasses = new Class[pjp.getArgs().length];
for (int i = 0; i < pjp.getArgs().length; i++) { for (int i = 0; i < pjp.getArgs().length; i++) {
argClasses[i] = pjp.getArgs()[i].getClass(); argClasses[i] = pjp.getArgs()[i].getClass();
} }
method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argClasses); method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argClasses);
return AnnotationUtils.findAnnotation(method, Retry.class); return AnnotationUtils.findAnnotation(method, Retry.class);
} }
} }

View file

@ -1,60 +0,0 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core.cache;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import net.helenus.mapping.HelenusProperty;
public class BoundFacet extends Facet<String> {
private final Map<HelenusProperty, Object> properties;
public BoundFacet(HelenusProperty property, Object value) {
super(property.getPropertyName(), value == null ? null : value.toString());
this.properties = new HashMap<HelenusProperty, Object>(1);
this.properties.put(property, value);
}
public Set<HelenusProperty> getProperties() {
return properties.keySet();
}
public BoundFacet(String name, Map<HelenusProperty, Object> properties) {
super(
name,
(properties.keySet().size() > 1)
? "["
+ String.join(
", ",
properties
.keySet()
.stream()
.map(key -> properties.get(key).toString())
.collect(Collectors.toSet()))
+ "]"
: String.join(
"",
properties
.keySet()
.stream()
.map(key -> properties.get(key).toString())
.collect(Collectors.toSet())));
this.properties = properties;
}
}

View file

@ -1,221 +0,0 @@
package net.helenus.core.cache;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import net.helenus.core.Helenus;
import net.helenus.core.reflect.Entity;
import net.helenus.core.reflect.MapExportable;
import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.value.BeanColumnValueProvider;
public class CacheUtil {
public static List<String[]> combinations(List<String> items) {
int n = items.size();
if (n > 20) throw new IllegalArgumentException(n + " is out of range");
long e = Math.round(Math.pow(2, n));
List<String[]> out = new ArrayList<String[]>((int) e - 1);
for (int k = 1; k <= items.size(); k++) {
kCombinations(items, 0, k, new String[k], out);
}
return out;
}
private static void kCombinations(
List<String> items, int n, int k, String[] arr, List<String[]> out) {
if (k == 0) {
out.add(arr.clone());
} else {
for (int i = n; i <= items.size() - k; i++) {
arr[arr.length - k] = items.get(i);
kCombinations(items, i + 1, k - 1, arr, out);
}
}
}
public static List<String> flatKeys(String table, List<Facet> facets) {
return flattenFacets(facets)
.stream()
.map(
combination -> {
return table + "." + Arrays.toString(combination);
})
.collect(Collectors.toList());
}
public static List<String[]> flattenFacets(List<Facet> facets) {
List<String[]> combinations =
CacheUtil.combinations(
facets
.stream()
.filter(facet -> !facet.fixed())
.filter(facet -> facet.value() != null)
.map(
facet -> {
return facet.name() + "==" + facet.value();
})
.collect(Collectors.toList()));
// TODO(gburd): rework so as to not generate the combinations at all rather than filter
facets =
facets
.stream()
.filter(f -> !f.fixed())
.filter(f -> !f.alone() || !f.combined())
.collect(Collectors.toList());
for (Facet facet : facets) {
combinations =
combinations
.stream()
.filter(
combo -> {
// When used alone, this facet is not distinct so don't use it as a key.
if (combo.length == 1) {
if (!facet.alone() && combo[0].startsWith(facet.name() + "==")) {
return false;
}
} else {
if (!facet.combined()) {
for (String c : combo) {
// Don't use this facet in combination with others to create keys.
if (c.startsWith(facet.name() + "==")) {
return false;
}
}
}
}
return true;
})
.collect(Collectors.toList());
}
return combinations;
}
/** Merge changed values in the map behind `from` into `to`. */
public static Object merge(Object t, Object f) {
HelenusEntity entity = Helenus.resolve(MappingUtil.getMappingInterface(t));
if (t == f) return t;
if (f == null) return t;
if (t == null) return f;
if (t instanceof MapExportable
&& t instanceof Entity
&& f instanceof MapExportable
&& f instanceof Entity) {
Entity to = (Entity) t;
Entity from = (Entity) f;
Map<String, Object> toValueMap = ((MapExportable) to).toMap();
Map<String, Object> fromValueMap = ((MapExportable) from).toMap();
for (HelenusProperty prop : entity.getOrderedProperties()) {
switch (prop.getColumnType()) {
case PARTITION_KEY:
case CLUSTERING_COLUMN:
continue;
default:
Object toVal = BeanColumnValueProvider.INSTANCE.getColumnValue(to, -1, prop, false);
Object fromVal = BeanColumnValueProvider.INSTANCE.getColumnValue(from, -1, prop, false);
String ttlKey = ttlKey(prop);
String writeTimeKey = writeTimeKey(prop);
int[] toTtlI = (int[]) toValueMap.get(ttlKey);
int toTtl = (toTtlI != null) ? toTtlI[0] : 0;
Long toWriteTime = (Long) toValueMap.get(writeTimeKey);
int[] fromTtlI = (int[]) fromValueMap.get(ttlKey);
int fromTtl = (fromTtlI != null) ? fromTtlI[0] : 0;
Long fromWriteTime = (Long) fromValueMap.get(writeTimeKey);
if (toVal != null) {
if (fromVal != null) {
if (toVal == fromVal) {
// Case: object identity
// Goal: ensure write time and ttl are also in sync
if (fromWriteTime != null
&& fromWriteTime != 0L
&& (toWriteTime == null || fromWriteTime > toWriteTime)) {
((MapExportable) to).put(writeTimeKey, fromWriteTime);
}
if (fromTtl > 0 && fromTtl > toTtl) {
((MapExportable) to).put(ttlKey, fromTtl);
}
} else if (fromWriteTime != null && fromWriteTime != 0L) {
// Case: to exists and from exists
// Goal: copy over from -> to iff from.writeTime > to.writeTime
if (toWriteTime != null && toWriteTime != 0L) {
if (fromWriteTime > toWriteTime) {
((MapExportable) to).put(prop.getPropertyName(), fromVal);
((MapExportable) to).put(writeTimeKey, fromWriteTime);
if (fromTtl > 0) {
((MapExportable) to).put(ttlKey, fromTtl);
}
}
} else {
((MapExportable) to).put(prop.getPropertyName(), fromVal);
((MapExportable) to).put(writeTimeKey, fromWriteTime);
if (fromTtl > 0) {
((MapExportable) to).put(ttlKey, fromTtl);
}
}
} else {
if (toWriteTime == null || toWriteTime == 0L) {
// Caution, entering grey area...
if (!toVal.equals(fromVal)) {
// dangerous waters here, values diverge without information that enables resolution,
// policy (for now) is to move value from -> to anyway.
((MapExportable) to).put(prop.getPropertyName(), fromVal);
if (fromTtl > 0) {
((MapExportable) to).put(ttlKey, fromTtl);
}
}
}
}
}
} else {
// Case: from exists, but to doesn't (it's null)
// Goal: copy over from -> to, include ttl and writeTime if present
if (fromVal != null) {
((MapExportable) to).put(prop.getPropertyName(), fromVal);
if (fromWriteTime != null && fromWriteTime != 0L) {
((MapExportable) to).put(writeTimeKey, fromWriteTime);
}
if (fromTtl > 0) {
((MapExportable) to).put(ttlKey, fromTtl);
}
}
}
}
}
return to;
}
return t;
}
public static String schemaName(List<Facet> facets) {
return facets
.stream()
.filter(Facet::fixed)
.map(facet -> facet.value().toString())
.collect(Collectors.joining("."));
}
public static String writeTimeKey(HelenusProperty prop) {
return writeTimeKey(prop.getColumnName().toCql(false));
}
public static String ttlKey(HelenusProperty prop) {
return ttlKey(prop.getColumnName().toCql(false));
}
public static String writeTimeKey(String columnName) {
String key = "_" + columnName + "_writeTime";
return key.toLowerCase();
}
public static String ttlKey(String columnName) {
String key = "_" + columnName + "_ttl";
return key.toLowerCase();
}
}

View file

@ -1,69 +0,0 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core.cache;
/** An Entity is identifiable via one or more Facets */
public class Facet<T> {
private final String name;
private T value;
private boolean fixed = false;
private boolean alone = true;
private boolean combined = true;
public Facet(String name) {
this.name = name;
}
public Facet(String name, T value) {
this.name = name;
this.value = value;
}
public String name() {
return name;
}
public T value() {
return value;
}
public Facet setFixed() {
fixed = true;
return this;
}
public boolean fixed() {
return fixed;
}
public void setUniquelyIdentifyingWhenAlone(boolean alone) {
this.alone = alone;
}
public void setUniquelyIdentifyingWhenCombined(boolean combined) {
this.combined = combined;
}
public boolean alone() {
return alone;
}
public boolean combined() {
return combined;
}
}

View file

@ -1,463 +0,0 @@
package net.helenus.core.cache;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.configuration.Configuration;
import javax.cache.event.CacheEntryRemovedListener;
import javax.cache.integration.CacheLoader;
import javax.cache.integration.CompletionListener;
import javax.cache.processor.EntryProcessor;
import javax.cache.processor.EntryProcessorException;
import javax.cache.processor.EntryProcessorResult;
import javax.cache.processor.MutableEntry;
public class MapCache<K, V> implements Cache<K, V> {
private final CacheManager manager;
private final String name;
private Map<K, V> map = new ConcurrentHashMap<>();
private Set<CacheEntryRemovedListener<K, V>> cacheEntryRemovedListeners = new HashSet<>();
private CacheLoader<K, V> cacheLoader = null;
private boolean isReadThrough = false;
private static class MapConfiguration<K, V> implements Configuration<K, V> {
private static final long serialVersionUID = 6093947542772516209L;
@Override
public Class<K> getKeyType() {
return null;
}
@Override
public Class<V> getValueType() {
return null;
}
@Override
public boolean isStoreByValue() {
return false;
}
}
public MapCache(
CacheManager manager, String name, CacheLoader<K, V> cacheLoader, boolean isReadThrough) {
this.manager = manager;
this.name = name;
this.cacheLoader = cacheLoader;
this.isReadThrough = isReadThrough;
}
/** {@inheritDoc} */
@Override
public V get(K key) {
V value = null;
synchronized (map) {
value = map.get(key);
if (value == null && isReadThrough && cacheLoader != null) {
V loadedValue = cacheLoader.load(key);
if (loadedValue != null) {
map.put(key, loadedValue);
value = loadedValue;
}
}
}
return value;
}
/** {@inheritDoc} */
@Override
public Map<K, V> getAll(Set<? extends K> keys) {
Map<K, V> result = null;
synchronized (map) {
result = new HashMap<K, V>(keys.size());
Iterator<? extends K> it = keys.iterator();
while (it.hasNext()) {
K key = it.next();
V value = map.get(key);
if (value != null) {
result.put(key, value);
it.remove();
}
}
if (keys.size() != 0 && isReadThrough && cacheLoader != null) {
Map<K, V> loadedValues = cacheLoader.loadAll(keys);
for (Map.Entry<K, V> entry : loadedValues.entrySet()) {
V v = entry.getValue();
if (v != null) {
K k = entry.getKey();
map.put(k, v);
result.put(k, v);
}
}
}
}
return result;
}
/** {@inheritDoc} */
@Override
public boolean containsKey(K key) {
return map.containsKey(key);
}
/** {@inheritDoc} */
@Override
public void loadAll(
Set<? extends K> keys, boolean replaceExistingValues, CompletionListener completionListener) {
if (cacheLoader != null) {
try {
synchronized (map) {
Map<K, V> loadedValues = cacheLoader.loadAll(keys);
for (Map.Entry<K, V> entry : loadedValues.entrySet()) {
V value = entry.getValue();
K key = entry.getKey();
if (value != null) {
boolean existsCurrently = map.containsKey(key);
if (!existsCurrently || replaceExistingValues) {
map.put(key, value);
keys.remove(key);
}
}
}
}
} catch (Exception e) {
if (completionListener != null) {
completionListener.onException(e);
}
}
}
if (completionListener != null) {
if (keys.isEmpty()) {
completionListener.onCompletion();
}
}
}
/** {@inheritDoc} */
@Override
public void put(K key, V value) {
map.put(key, value);
}
/** {@inheritDoc} */
@Override
public V getAndPut(K key, V value) {
V result = null;
synchronized (map) {
result = map.get(key);
if (result == null && isReadThrough && cacheLoader != null) {
V loadedValue = cacheLoader.load(key);
if (loadedValue != null) {
result = loadedValue;
}
}
map.put(key, value);
}
return result;
}
/** {@inheritDoc} */
@Override
public void putAll(Map<? extends K, ? extends V> map) {
synchronized (map) {
for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
this.map.put(entry.getKey(), entry.getValue());
}
}
}
/** {@inheritDoc} */
@Override
public boolean putIfAbsent(K key, V value) {
synchronized (map) {
if (!map.containsKey(key)) {
map.put(key, value);
return true;
} else {
return false;
}
}
}
/** {@inheritDoc} */
@Override
public boolean remove(K key) {
boolean removed = false;
synchronized (map) {
removed = map.remove(key) != null;
notifyRemovedListeners(key);
}
return removed;
}
/** {@inheritDoc} */
@Override
public boolean remove(K key, V oldValue) {
synchronized (map) {
V value = map.get(key);
if (value != null && oldValue.equals(value)) {
map.remove(key);
notifyRemovedListeners(key);
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public V getAndRemove(K key) {
synchronized (map) {
V oldValue = null;
oldValue = map.get(key);
map.remove(key);
notifyRemovedListeners(key);
return oldValue;
}
}
/** {@inheritDoc} */
@Override
public boolean replace(K key, V oldValue, V newValue) {
synchronized (map) {
V value = map.get(key);
if (value != null && oldValue.equals(value)) {
map.put(key, newValue);
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public boolean replace(K key, V value) {
synchronized (map) {
if (map.containsKey(key)) {
map.put(key, value);
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public V getAndReplace(K key, V value) {
synchronized (map) {
V oldValue = map.get(key);
if (value != null && value.equals(oldValue)) {
map.put(key, value);
return oldValue;
}
}
return null;
}
/** {@inheritDoc} */
@Override
public void removeAll(Set<? extends K> keys) {
synchronized (map) {
Iterator<? extends K> it = keys.iterator();
while (it.hasNext()) {
K key = it.next();
if (map.containsKey(key)) {
map.remove(key);
} else {
it.remove();
}
}
}
notifyRemovedListeners(keys);
}
/** {@inheritDoc} */
@Override
public void removeAll() {
synchronized (map) {
Set<K> keys = map.keySet();
map.clear();
notifyRemovedListeners(keys);
}
}
/** {@inheritDoc} */
@Override
public void clear() {
map.clear();
}
/** {@inheritDoc} */
@Override
public <C extends Configuration<K, V>> C getConfiguration(Class<C> clazz) {
if (!MapConfiguration.class.isAssignableFrom(clazz)) {
throw new IllegalArgumentException();
}
return null;
}
/** {@inheritDoc} */
@Override
public <T> T invoke(K key, EntryProcessor<K, V, T> entryProcessor, Object... arguments)
throws EntryProcessorException {
// TODO
return null;
}
/** {@inheritDoc} */
@Override
public <T> Map<K, EntryProcessorResult<T>> invokeAll(
Set<? extends K> keys, EntryProcessor<K, V, T> entryProcessor, Object... arguments) {
synchronized (map) {
for (K key : keys) {
V value = map.get(key);
if (value != null) {
entryProcessor.process(
new MutableEntry<K, V>() {
@Override
public boolean exists() {
return map.containsKey(key);
}
@Override
public void remove() {
synchronized (map) {
V value = map.get(key);
if (value != null) {
map.remove(key);
notifyRemovedListeners(key);
}
}
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return map.get(value);
}
@Override
public <T> T unwrap(Class<T> clazz) {
return null;
}
@Override
public void setValue(V value) {
map.put(key, value);
}
},
arguments);
}
}
}
return null;
}
/** {@inheritDoc} */
@Override
public String getName() {
return name;
}
/** {@inheritDoc} */
@Override
public CacheManager getCacheManager() {
return manager;
}
/** {@inheritDoc} */
@Override
public void close() {}
/** {@inheritDoc} */
@Override
public boolean isClosed() {
return false;
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> clazz) {
if (Map.class.isAssignableFrom(clazz)) {
return (T) map;
}
return null;
}
/** {@inheritDoc} */
@Override
public void registerCacheEntryListener(
CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {
//cacheEntryRemovedListeners.add(cacheEntryListenerConfiguration.getCacheEntryListenerFactory().create());
}
/** {@inheritDoc} */
@Override
public void deregisterCacheEntryListener(
CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {}
/** {@inheritDoc} */
@Override
public Iterator<Entry<K, V>> iterator() {
synchronized (map) {
return new Iterator<Entry<K, V>>() {
Iterator<Map.Entry<K, V>> entries = map.entrySet().iterator();
@Override
public boolean hasNext() {
return entries.hasNext();
}
@Override
public Entry<K, V> next() {
Map.Entry<K, V> entry = entries.next();
return new Entry<K, V>() {
K key = entry.getKey();
V value = entry.getValue();
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public <T> T unwrap(Class<T> clazz) {
return null;
}
};
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
private void notifyRemovedListeners(K key) {
// if (cacheEntryRemovedListeners != null) {
// cacheEntryRemovedListeners.forEach(listener -> listener.onRemoved())
// }
}
private void notifyRemovedListeners(Set<? extends K> keys) {}
}

View file

@ -1,95 +0,0 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core.cache;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.helenus.core.SchemaUtil;
import net.helenus.mapping.HelenusProperty;
public class UnboundFacet extends Facet<String> {
private final List<HelenusProperty> properties;
private final boolean alone;
private final boolean combined;
public UnboundFacet(List<HelenusProperty> properties, boolean alone, boolean combined) {
super(SchemaUtil.createPrimaryKeyPhrase(properties));
this.properties = properties;
this.alone = alone;
this.combined = combined;
}
public UnboundFacet(List<HelenusProperty> properties) {
this(properties, true, true);
}
public UnboundFacet(HelenusProperty property, boolean alone, boolean combined) {
super(property.getPropertyName());
properties = new ArrayList<HelenusProperty>();
properties.add(property);
this.alone = alone;
this.combined = combined;
}
public UnboundFacet(HelenusProperty property) {
this(property, true, true);
}
public List<HelenusProperty> getProperties() {
return properties;
}
public Binder binder() {
return new Binder(name(), properties, alone, combined);
}
public static class Binder {
private final String name;
private final boolean alone;
private final boolean combined;
private final List<HelenusProperty> properties = new ArrayList<HelenusProperty>();
private Map<HelenusProperty, Object> boundProperties = new HashMap<HelenusProperty, Object>();
Binder(String name, List<HelenusProperty> properties, boolean alone, boolean combined) {
this.name = name;
this.properties.addAll(properties);
this.alone = alone;
this.combined = combined;
}
public Binder setValueForProperty(HelenusProperty prop, Object value) {
properties.remove(prop);
boundProperties.put(prop, value);
return this;
}
public boolean isBound() {
return properties.isEmpty();
}
public BoundFacet bind() {
BoundFacet facet = new BoundFacet(name, boundProperties);
facet.setUniquelyIdentifyingWhenAlone(alone);
facet.setUniquelyIdentifyingWhenCombined(combined);
return facet;
}
}
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,153 +15,97 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.*; import java.util.LinkedList;
import java.util.List;
import net.helenus.core.*; import net.helenus.core.*;
import net.helenus.core.cache.Facet;
import net.helenus.core.cache.UnboundFacet;
import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.HelenusProperty;
public abstract class AbstractFilterOperation<E, O extends AbstractFilterOperation<E, O>> public abstract class AbstractFilterOperation<E, O extends AbstractFilterOperation<E, O>>
extends AbstractOperation<E, O> { extends
AbstractOperation<E, O> {
protected List<Filter<?>> filters = null; protected List<Filter<?>> filters = null;
protected List<Filter<?>> ifFilters = null; protected List<Filter<?>> ifFilters = null;
public AbstractFilterOperation(AbstractSessionOperations sessionOperations) { public AbstractFilterOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public <V> O where(Getter<V> getter, Postulate<V> postulate) { public <V> O where(Getter<V> getter, Postulate<V> postulate) {
addFilter(Filter.create(getter, postulate)); addFilter(Filter.create(getter, postulate));
return (O) this; return (O) this;
} }
public <V> O where(Getter<V> getter, Operator operator, V val) { public <V> O where(Getter<V> getter, Operator operator, V val) {
addFilter(Filter.create(getter, operator, val)); addFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }
public <V> O where(Filter<V> filter) { public <V> O where(Filter<V> filter) {
addFilter(filter); addFilter(filter);
return (O) this; return (O) this;
} }
public <V> O and(Getter<V> getter, Postulate<V> postulate) { public <V> O and(Getter<V> getter, Postulate<V> postulate) {
addFilter(Filter.create(getter, postulate)); addFilter(Filter.create(getter, postulate));
return (O) this; return (O) this;
} }
public <V> O and(Getter<V> getter, Operator operator, V val) { public <V> O and(Getter<V> getter, Operator operator, V val) {
addFilter(Filter.create(getter, operator, val)); addFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }
public <V> O and(Filter<V> filter) { public <V> O and(Filter<V> filter) {
addFilter(filter); addFilter(filter);
return (O) this; return (O) this;
} }
public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) { public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) {
addIfFilter(Filter.create(getter, postulate)); addIfFilter(Filter.create(getter, postulate));
return (O) this; return (O) this;
} }
public <V> O onlyIf(Getter<V> getter, Operator operator, V val) { public <V> O onlyIf(Getter<V> getter, Operator operator, V val) {
addIfFilter(Filter.create(getter, operator, val)); addIfFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }
public <V> O onlyIf(Filter<V> filter) { public <V> O onlyIf(Filter<V> filter) {
addIfFilter(filter); addIfFilter(filter);
return (O) this; return (O) this;
} }
private void addFilter(Filter<?> filter) { private void addFilter(Filter<?> filter) {
if (filters == null) { if (filters == null) {
filters = new LinkedList<Filter<?>>(); filters = new LinkedList<Filter<?>>();
} }
filters.add(filter); filters.add(filter);
} }
private void addIfFilter(Filter<?> filter) { private void addIfFilter(Filter<?> filter) {
if (ifFilters == null) { if (ifFilters == null) {
ifFilters = new LinkedList<Filter<?>>(); ifFilters = new LinkedList<Filter<?>>();
} }
ifFilters.add(filter); ifFilters.add(filter);
} }
@Override
protected boolean isIdempotentOperation() {
if (filters == null) {
return super.isIdempotentOperation();
}
return filters
.stream()
.anyMatch(
filter -> {
HelenusPropertyNode node = filter.getNode();
if (node != null) {
HelenusProperty prop = node.getProperty();
if (prop != null) {
return prop.isIdempotent();
}
}
return false;
})
|| super.isIdempotentOperation();
}
protected List<Facet> bindFacetValues(List<Facet> facets) {
if (facets == null) {
return new ArrayList<Facet>();
}
List<Facet> boundFacets = new ArrayList<>();
Map<HelenusProperty, Filter> filterMap = new HashMap<>(filters.size());
filters.forEach(f -> filterMap.put(f.getNode().getProperty(), f));
for (Facet facet : facets) {
if (facet instanceof UnboundFacet) {
UnboundFacet unboundFacet = (UnboundFacet) facet;
UnboundFacet.Binder binder = unboundFacet.binder();
if (filters != null) {
for (HelenusProperty prop : unboundFacet.getProperties()) {
Filter filter = filterMap.get(prop);
if (filter != null) {
Object[] postulates = filter.postulateValues();
for (Object p : postulates) {
binder.setValueForProperty(prop, p.toString());
}
}
}
}
if (binder.isBound()) {
boundFacets.add(binder.bind());
}
} else {
boundFacets.add(facet);
}
}
return boundFacets;
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,98 +15,97 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.LinkedHashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import net.helenus.core.*; import net.helenus.core.*;
import net.helenus.mapping.HelenusProperty;
public abstract class AbstractFilterOptionalOperation< public abstract class AbstractFilterOptionalOperation<E, O extends AbstractFilterOptionalOperation<E, O>>
E, O extends AbstractFilterOptionalOperation<E, O>> extends
extends AbstractOptionalOperation<E, O> { AbstractOptionalOperation<E, O> {
protected Map<HelenusProperty, Filter<?>> filters = null; protected List<Filter<?>> filters = null;
protected List<Filter<?>> ifFilters = null; protected List<Filter<?>> ifFilters = null;
public AbstractFilterOptionalOperation(AbstractSessionOperations sessionOperations) { public AbstractFilterOptionalOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public <V> O where(Getter<V> getter, Postulate<V> postulate) { public <V> O where(Getter<V> getter, Postulate<V> postulate) {
addFilter(Filter.create(getter, postulate)); addFilter(Filter.create(getter, postulate));
return (O) this; return (O) this;
} }
public <V> O where(Getter<V> getter, Operator operator, V val) { public <V> O where(Getter<V> getter, Operator operator, V val) {
addFilter(Filter.create(getter, operator, val)); addFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }
public <V> O where(Filter<V> filter) { public <V> O where(Filter<V> filter) {
addFilter(filter); addFilter(filter);
return (O) this; return (O) this;
} }
public <V> O and(Getter<V> getter, Postulate<V> postulate) { public <V> O and(Getter<V> getter, Postulate<V> postulate) {
addFilter(Filter.create(getter, postulate)); addFilter(Filter.create(getter, postulate));
return (O) this; return (O) this;
} }
public <V> O and(Getter<V> getter, Operator operator, V val) { public <V> O and(Getter<V> getter, Operator operator, V val) {
addFilter(Filter.create(getter, operator, val)); addFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }
public <V> O and(Filter<V> filter) { public <V> O and(Filter<V> filter) {
addFilter(filter); addFilter(filter);
return (O) this; return (O) this;
} }
public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) { public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) {
addIfFilter(Filter.create(getter, postulate)); addIfFilter(Filter.create(getter, postulate));
return (O) this; return (O) this;
} }
public <V> O onlyIf(Getter<V> getter, Operator operator, V val) { public <V> O onlyIf(Getter<V> getter, Operator operator, V val) {
addIfFilter(Filter.create(getter, operator, val)); addIfFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }
public <V> O onlyIf(Filter<V> filter) { public <V> O onlyIf(Filter<V> filter) {
addIfFilter(filter); addIfFilter(filter);
return (O) this; return (O) this;
} }
private void addFilter(Filter<?> filter) { private void addFilter(Filter<?> filter) {
if (filters == null) { if (filters == null) {
filters = new LinkedHashMap<HelenusProperty, Filter<?>>(); filters = new LinkedList<Filter<?>>();
} }
filters.put(filter.getNode().getProperty(), filter); filters.add(filter);
} }
private void addIfFilter(Filter<?> filter) {
if (ifFilters == null) {
ifFilters = new LinkedList<Filter<?>>();
}
ifFilters.add(filter);
}
private void addIfFilter(Filter<?> filter) {
if (ifFilters == null) {
ifFilters = new LinkedList<Filter<?>>();
}
ifFilters.add(filter);
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,98 +15,96 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.LinkedHashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import net.helenus.core.*; import net.helenus.core.*;
import net.helenus.mapping.HelenusProperty;
public abstract class AbstractFilterStreamOperation< public abstract class AbstractFilterStreamOperation<E, O extends AbstractFilterStreamOperation<E, O>>
E, O extends AbstractFilterStreamOperation<E, O>> extends AbstractStreamOperation<E, O> {
extends AbstractStreamOperation<E, O> {
protected Map<HelenusProperty, Filter<?>> filters = null; protected List<Filter<?>> filters = null;
protected List<Filter<?>> ifFilters = null; protected List<Filter<?>> ifFilters = null;
public AbstractFilterStreamOperation(AbstractSessionOperations sessionOperations) { public AbstractFilterStreamOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public <V> O where(Getter<V> getter, Postulate<V> postulate) { public <V> O where(Getter<V> getter, Postulate<V> postulate) {
addFilter(Filter.create(getter, postulate)); addFilter(Filter.create(getter, postulate));
return (O) this; return (O) this;
} }
public <V> O where(Getter<V> getter, Operator operator, V val) { public <V> O where(Getter<V> getter, Operator operator, V val) {
if (val != null) addFilter(Filter.create(getter, operator, val)); addFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }
public <V> O where(Filter<V> filter) { public <V> O where(Filter<V> filter) {
addFilter(filter); addFilter(filter);
return (O) this; return (O) this;
} }
public <V> O and(Getter<V> getter, Postulate<V> postulate) { public <V> O and(Getter<V> getter, Postulate<V> postulate) {
addFilter(Filter.create(getter, postulate)); addFilter(Filter.create(getter, postulate));
return (O) this; return (O) this;
} }
public <V> O and(Getter<V> getter, Operator operator, V val) { public <V> O and(Getter<V> getter, Operator operator, V val) {
if (val != null) addFilter(Filter.create(getter, operator, val)); addFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }
public <V> O and(Filter<V> filter) { public <V> O and(Filter<V> filter) {
addFilter(filter); addFilter(filter);
return (O) this; return (O) this;
} }
public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) { public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) {
addIfFilter(Filter.create(getter, postulate)); addIfFilter(Filter.create(getter, postulate));
return (O) this; return (O) this;
} }
public <V> O onlyIf(Getter<V> getter, Operator operator, V val) { public <V> O onlyIf(Getter<V> getter, Operator operator, V val) {
if (val != null) addIfFilter(Filter.create(getter, operator, val)); addIfFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }
public <V> O onlyIf(Filter<V> filter) { public <V> O onlyIf(Filter<V> filter) {
addIfFilter(filter); addIfFilter(filter);
return (O) this; return (O) this;
} }
private void addFilter(Filter<?> filter) { private void addFilter(Filter<?> filter) {
if (filters == null) { if (filters == null) {
filters = new LinkedHashMap<HelenusProperty, Filter<?>>(); filters = new LinkedList<Filter<?>>();
} }
filters.put(filter.getNode().getProperty(), filter); filters.add(filter);
} }
private void addIfFilter(Filter<?> filter) {
if (ifFilters == null) {
ifFilters = new LinkedList<Filter<?>>();
}
ifFilters.add(filter);
}
private void addIfFilter(Filter<?> filter) {
if (ifFilters == null) {
ifFilters = new LinkedList<Filter<?>>();
}
ifFilters.add(filter);
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,76 +15,106 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import com.codahale.metrics.Timer; import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import java.util.concurrent.CompletableFuture; import com.datastax.driver.core.ResultSetFuture;
import java.util.concurrent.CompletionException; import com.google.common.base.Function;
import java.util.concurrent.TimeoutException; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.UnitOfWork; import net.helenus.support.Fun;
import net.helenus.support.Scala;
import scala.concurrent.Future;
public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>> public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>> extends AbstractStatementOperation<E, O> {
extends AbstractStatementOperation<E, O> {
public AbstractOperation(AbstractSessionOperations sessionOperations) { public abstract E transform(ResultSet resultSet);
super(sessionOperations);
}
public abstract E transform(ResultSet resultSet); public boolean cacheable() {
return false;
}
public PreparedOperation<E> prepare() { public String getCacheKey() {
return new PreparedOperation<E>(prepareStatement(), this); return "";
} }
public E sync() throws TimeoutException { public AbstractOperation(AbstractSessionOperations sessionOperations) {
final Timer.Context context = requestLatency.time(); super(sessionOperations);
try { }
ResultSet resultSet =
this.execute(
sessionOps, null, queryExecutionTimeout, queryTimeoutUnits, showValues, false);
return transform(resultSet);
} finally {
context.stop();
}
}
public E sync(UnitOfWork uow) throws TimeoutException { public PreparedOperation<E> prepare() {
if (uow == null) return sync(); return new PreparedOperation<E>(prepareStatement(), this);
}
final Timer.Context context = requestLatency.time(); public ListenableFuture<PreparedOperation<E>> prepareAsync() {
try {
ResultSet resultSet =
execute(sessionOps, uow, queryExecutionTimeout, queryTimeoutUnits, showValues, true);
E result = transform(resultSet);
return result;
} finally {
context.stop();
}
}
public CompletableFuture<E> async() { final O _this = (O) this;
return CompletableFuture.<E>supplyAsync(
() -> { return Futures.transform(prepareStatementAsync(), new Function<PreparedStatement, PreparedOperation<E>>() {
try {
return sync(); @Override
} catch (TimeoutException ex) { public PreparedOperation<E> apply(PreparedStatement preparedStatement) {
throw new CompletionException(ex); return new PreparedOperation<E>(preparedStatement, _this);
} }
});
} });
}
public Future<PreparedOperation<E>> prepareFuture() {
return Scala.asFuture(prepareAsync());
}
public E sync() {
ResultSet resultSet = sessionOps.executeAsync(options(buildStatement()), showValues).getUninterruptibly();
E result = transform(resultSet);
if (cacheable()) {
sessionOps.cache(getCacheKey(), result);
}
return result;
}
public ListenableFuture<E> async() {
ResultSetFuture resultSetFuture = sessionOps.executeAsync(options(buildStatement()), showValues);
ListenableFuture<E> future = Futures.transform(resultSetFuture, new Function<ResultSet, E>() {
@Override
public E apply(ResultSet resultSet) {
E result = transform(resultSet);
if (cacheable()) {
sessionOps.cache(getCacheKey(), result);
}
return transform(resultSet);
}
}, sessionOps.getExecutor());
return future;
}
public Future<E> future() {
return Scala.asFuture(async());
}
public <A> Future<Fun.Tuple2<E, A>> future(A a) {
return Scala.asFuture(async(), a);
}
public <A, B> Future<Fun.Tuple3<E, A, B>> future(A a, B b) {
return Scala.asFuture(async(), a, b);
}
public <A, B, C> Future<Fun.Tuple4<E, A, B, C>> future(A a, B b, C c) {
return Scala.asFuture(async(), a, b, c);
}
public <A, B, C, D> Future<Fun.Tuple5<E, A, B, C, D>> future(A a, B b, C c, D d) {
return Scala.asFuture(async(), a, b, c, d);
}
public CompletableFuture<E> async(UnitOfWork uow) {
if (uow == null) return async();
CompletableFuture<E> f =
CompletableFuture.<E>supplyAsync(
() -> {
try {
return sync();
} catch (TimeoutException ex) {
throw new CompletionException(ex);
}
});
uow.addFuture(f);
return f;
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,240 +15,118 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import static net.helenus.core.HelenusSession.deleted; import java.util.Optional;
import com.codahale.metrics.Timer;
import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeoutException;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Helenus;
import net.helenus.core.UnitOfWork;
import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet;
import net.helenus.mapping.MappingUtil;
import net.helenus.support.Fun; import net.helenus.support.Fun;
import org.apache.commons.lang3.SerializationUtils; import net.helenus.support.Scala;
import scala.Option;
import scala.Some;
import scala.concurrent.Future;
public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOperation<E, O>> public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOperation<E, O>>
extends AbstractStatementOperation<E, O> { extends
AbstractStatementOperation<E, O> {
public AbstractOptionalOperation(AbstractSessionOperations sessionOperations) { public AbstractOptionalOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public abstract Optional<E> transform(ResultSet resultSet); public abstract Optional<E> transform(ResultSet resultSet);
public PreparedOptionalOperation<E> prepare() { public PreparedOptionalOperation<E> prepare() {
return new PreparedOptionalOperation<E>(prepareStatement(), this); return new PreparedOptionalOperation<E>(prepareStatement(), this);
} }
public ListenableFuture<PreparedOptionalOperation<E>> prepareAsync() { public ListenableFuture<PreparedOptionalOperation<E>> prepareAsync() {
final O _this = (O) this;
return Futures.transform(
prepareStatementAsync(),
new Function<PreparedStatement, PreparedOptionalOperation<E>>() {
@Override
public PreparedOptionalOperation<E> apply(PreparedStatement preparedStatement) {
return new PreparedOptionalOperation<E>(preparedStatement, _this);
}
});
}
public Optional<E> sync() throws TimeoutException { final O _this = (O) this;
final Timer.Context context = requestLatency.time();
try {
Optional<E> result = Optional.empty();
E cacheResult = null;
boolean updateCache = isSessionCacheable() && !ignoreCache();
if (updateCache) { return Futures.transform(prepareStatementAsync(),
List<Facet> facets = bindFacetValues(); new Function<PreparedStatement, PreparedOptionalOperation<E>>() {
if (facets != null && facets.size() > 0) {
if (facets.stream().filter(f -> !f.fixed()).distinct().count() > 0) {
String tableName = CacheUtil.schemaName(facets);
cacheResult = (E) sessionOps.checkCache(tableName, facets);
if (cacheResult != null) {
result = Optional.of(cacheResult);
updateCache = false;
sessionCacheHits.mark();
cacheHits.mark();
} else {
sessionCacheMiss.mark();
cacheMiss.mark();
}
}
} else {
//TODO(gburd): look in statement cache for results
}
}
if (!result.isPresent()) { @Override
// Formulate the query and execute it against the Cassandra cluster. public PreparedOptionalOperation<E> apply(PreparedStatement preparedStatement) {
ResultSet resultSet = return new PreparedOptionalOperation<E>(preparedStatement, _this);
this.execute( }
sessionOps,
null,
queryExecutionTimeout,
queryTimeoutUnits,
showValues,
isSessionCacheable());
// Transform the query result set into the desired shape. });
result = transform(resultSet);
}
if (updateCache && result.isPresent()) { }
E r = result.get();
Class<?> resultClass = r.getClass();
if (!(resultClass.getEnclosingClass() != null
&& resultClass.getEnclosingClass() == Fun.class)) {
List<Facet> facets = getFacets();
if (facets != null && facets.size() > 1) {
sessionOps.updateCache(r, facets);
}
}
}
return result;
} finally {
context.stop();
}
}
public Optional<E> sync(UnitOfWork uow) throws TimeoutException { public Future<PreparedOptionalOperation<E>> prepareFuture() {
if (uow == null) return sync(); return Scala.asFuture(prepareAsync());
}
final Timer.Context context = requestLatency.time(); public Optional<E> sync() {
try {
Optional<E> result = Optional.empty(); ResultSet resultSet = sessionOps.executeAsync(options(buildStatement()), showValues).getUninterruptibly();
E cachedResult = null;
final boolean updateCache;
if (!ignoreCache()) { return transform(resultSet);
Stopwatch timer = Stopwatch.createStarted(); }
try {
List<Facet> facets = bindFacetValues();
if (facets != null && facets.size() > 0) {
if (facets.stream().filter(f -> !f.fixed()).distinct().count() > 0) {
cachedResult = checkCache(uow, facets);
if (cachedResult != null) {
updateCache = false;
result = Optional.of(cachedResult);
uowCacheHits.mark();
cacheHits.mark();
uow.recordCacheAndDatabaseOperationCount(1, 0);
} else {
uowCacheMiss.mark();
if (isSessionCacheable()) {
String tableName = CacheUtil.schemaName(facets);
cachedResult = (E) sessionOps.checkCache(tableName, facets);
if (cachedResult != null) {
Class<?> iface = MappingUtil.getMappingInterface(cachedResult);
if (Helenus.entity(iface).isDraftable()) {
result = Optional.of(cachedResult);
} else {
result =
Optional.of(
(E)
SerializationUtils.<Serializable>clone(
(Serializable) cachedResult));
}
updateCache = false;
sessionCacheHits.mark();
cacheHits.mark();
uow.recordCacheAndDatabaseOperationCount(1, 0);
} else {
updateCache = true;
sessionCacheMiss.mark();
cacheMiss.mark();
uow.recordCacheAndDatabaseOperationCount(-1, 0);
}
} else {
updateCache = false;
}
}
} else {
//TODO(gburd): look in statement cache for results
updateCache = false; //true;
cacheMiss.mark();
uow.recordCacheAndDatabaseOperationCount(-1, 0);
}
} else {
updateCache = false;
}
} finally {
timer.stop();
uow.addCacheLookupTime(timer);
}
} else {
updateCache = false;
}
// Check to see if we fetched the object from the cache public ListenableFuture<Optional<E>> async() {
if (result.isPresent()) {
// If we fetched the `deleted` object then the result is null (really
// Optional.empty()).
if (result.get() == deleted) {
result = Optional.empty();
}
} else {
// Formulate the query and execute it against the Cassandra cluster. ResultSetFuture resultSetFuture = sessionOps.executeAsync(options(buildStatement()), showValues);
ResultSet resultSet =
execute(sessionOps, uow, queryExecutionTimeout, queryTimeoutUnits, showValues, true);
// Transform the query result set into the desired shape. ListenableFuture<Optional<E>> future = Futures.transform(resultSetFuture,
result = transform(resultSet); new Function<ResultSet, Optional<E>>() {
}
// If we have a result, it wasn't from the UOW cache, and we're caching things @Override
// then we need to put this result into the cache for future requests to find. public Optional<E> apply(ResultSet resultSet) {
if (updateCache && result.isPresent()) { return transform(resultSet);
E r = result.get(); }
if (!(r instanceof Fun) && r != deleted) {
cacheUpdate(uow, r, getFacets());
}
}
return result; }, sessionOps.getExecutor());
} finally {
context.stop();
}
}
public CompletableFuture<Optional<E>> async() { return future;
return CompletableFuture.<Optional<E>>supplyAsync( }
() -> {
try { public ListenableFuture<Option<E>> asyncForScala() {
return sync();
} catch (TimeoutException ex) { ResultSetFuture resultSetFuture = sessionOps.executeAsync(options(buildStatement()), showValues);
throw new CompletionException(ex);
} ListenableFuture<Option<E>> future = Futures.transform(resultSetFuture, new Function<ResultSet, Option<E>>() {
});
} @Override
public Option<E> apply(ResultSet resultSet) {
Optional<E> optional = transform(resultSet);
if (optional.isPresent()) {
return new Some<E>(optional.get());
} else {
return Option.empty();
}
}
}, sessionOps.getExecutor());
return future;
}
public Future<Option<E>> future() {
return Scala.asFuture(asyncForScala());
}
public <A> Future<Fun.Tuple2<Option<E>, A>> future(A a) {
return Scala.asFuture(asyncForScala(), a);
}
public <A, B> Future<Fun.Tuple3<Option<E>, A, B>> future(A a, B b) {
return Scala.asFuture(asyncForScala(), a, b);
}
public <A, B, C> Future<Fun.Tuple4<Option<E>, A, B, C>> future(A a, B b, C c) {
return Scala.asFuture(asyncForScala(), a, b, c);
}
public <A, B, C, D> Future<Fun.Tuple5<Option<E>, A, B, C, D>> future(A a, B b, C c, D d) {
return Scala.asFuture(asyncForScala(), a, b, c, d);
}
public CompletableFuture<Optional<E>> async(UnitOfWork uow) {
if (uow == null) return async();
CompletableFuture<Optional<E>> f =
CompletableFuture.<Optional<E>>supplyAsync(
() -> {
try {
return sync();
} catch (TimeoutException ex) {
throw new CompletionException(ex);
}
});
uow.addFuture(f);
return f;
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +15,9 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.ConsistencyLevel; import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.RegularStatement; import com.datastax.driver.core.RegularStatement;
@ -26,331 +28,211 @@ import com.datastax.driver.core.policies.FallthroughRetryPolicy;
import com.datastax.driver.core.policies.RetryPolicy; import com.datastax.driver.core.policies.RetryPolicy;
import com.datastax.driver.core.querybuilder.BuiltStatement; import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.UnitOfWork;
import net.helenus.core.cache.Facet;
import net.helenus.core.cache.UnboundFacet;
import net.helenus.core.reflect.MapExportable;
import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.value.BeanColumnValueProvider;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
import net.helenus.support.Scala;
import scala.concurrent.Future;
public abstract class AbstractStatementOperation<E, O extends AbstractStatementOperation<E, O>> {
final Logger logger = LoggerFactory.getLogger(getClass());
protected final AbstractSessionOperations sessionOps;
public abstract Statement buildStatement();
protected boolean showValues = true;
private ConsistencyLevel consistencyLevel;
private ConsistencyLevel serialConsistencyLevel;
private RetryPolicy retryPolicy;
private boolean enableTracing = false;
private long[] defaultTimestamp = null;
private int[] fetchSize = null;
public AbstractStatementOperation(AbstractSessionOperations sessionOperations) {
this.sessionOps = sessionOperations;
}
public O showValues(boolean enabled) {
this.showValues = enabled;
return (O) this;
}
public O defaultTimestamp(long timestamp) {
this.defaultTimestamp = new long[1];
this.defaultTimestamp[0] = timestamp;
return (O) this;
}
public O retryPolicy(RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
return (O) this;
}
public O defaultRetryPolicy() {
this.retryPolicy = DefaultRetryPolicy.INSTANCE;
return (O) this;
}
public O downgradingConsistencyRetryPolicy() {
this.retryPolicy = DowngradingConsistencyRetryPolicy.INSTANCE;
return (O) this;
}
public O fallthroughRetryPolicy() {
this.retryPolicy = FallthroughRetryPolicy.INSTANCE;
return (O) this;
}
public O consistency(ConsistencyLevel level) {
this.consistencyLevel = level;
return (O) this;
}
public O consistencyAny() {
this.consistencyLevel = ConsistencyLevel.ANY;
return (O) this;
}
public O consistencyOne() {
this.consistencyLevel = ConsistencyLevel.ONE;
return (O) this;
}
public O consistencyQuorum() {
this.consistencyLevel = ConsistencyLevel.QUORUM;
return (O) this;
}
public O consistencyAll() {
this.consistencyLevel = ConsistencyLevel.ALL;
return (O) this;
}
public O serialConsistency(ConsistencyLevel level) {
this.serialConsistencyLevel = level;
return (O) this;
}
public O serialConsistencyAny() {
this.serialConsistencyLevel = ConsistencyLevel.ANY;
return (O) this;
}
public O serialConsistencyOne() {
this.serialConsistencyLevel = ConsistencyLevel.ONE;
return (O) this;
}
public O serialConsistencyQuorum() {
this.serialConsistencyLevel = ConsistencyLevel.QUORUM;
return (O) this;
}
public O serialConsistencyAll() {
this.serialConsistencyLevel = ConsistencyLevel.ALL;
return (O) this;
}
public O disableTracing() {
this.enableTracing = false;
return (O) this;
}
public O enableTracing() {
this.enableTracing = true;
return (O) this;
}
public O tracing(boolean enable) {
this.enableTracing = enable;
return (O) this;
}
public O fetchSize(int fetchSize) {
this.fetchSize = new int[1];
this.fetchSize[0] = fetchSize;
return (O) this;
}
protected Statement options(Statement statement) {
if (defaultTimestamp != null) {
statement.setDefaultTimestamp(defaultTimestamp[0]);
}
if (consistencyLevel != null) {
statement.setConsistencyLevel(consistencyLevel);
}
if (serialConsistencyLevel != null) {
statement.setSerialConsistencyLevel(serialConsistencyLevel);
}
if (retryPolicy != null) {
statement.setRetryPolicy(retryPolicy);
}
if (enableTracing) {
statement.enableTracing();
} else {
statement.disableTracing();
}
if (fetchSize != null) {
statement.setFetchSize(fetchSize[0]);
}
return statement;
}
public Statement statement() {
return buildStatement();
}
public String cql() {
Statement statement = buildStatement();
if (statement == null) return "";
if (statement instanceof BuiltStatement) {
BuiltStatement buildStatement = (BuiltStatement) statement;
return buildStatement.setForceNoValues(true).getQueryString();
} else {
return statement.toString();
}
}
public PreparedStatement prepareStatement() {
Statement statement = buildStatement();
if (statement instanceof RegularStatement) {
RegularStatement regularStatement = (RegularStatement) statement;
return sessionOps.prepare(regularStatement);
}
throw new HelenusException("only RegularStatements can be prepared");
}
public ListenableFuture<PreparedStatement> prepareStatementAsync() {
Statement statement = buildStatement();
if (statement instanceof RegularStatement) {
RegularStatement regularStatement = (RegularStatement) statement;
return sessionOps.prepareAsync(regularStatement);
}
throw new HelenusException("only RegularStatements can be prepared");
}
public Future<PreparedStatement> prepareStatementFuture() {
return Scala.asFuture(prepareStatementAsync());
}
public abstract class AbstractStatementOperation<E, O extends AbstractStatementOperation<E, O>>
extends Operation<E> {
private boolean ignoreCache = false;
private ConsistencyLevel consistencyLevel;
private ConsistencyLevel serialConsistencyLevel;
private RetryPolicy retryPolicy;
private boolean enableTracing = false;
private long[] defaultTimestamp = null;
private int[] fetchSize = null;
protected boolean idempotent = false;
public AbstractStatementOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations);
this.consistencyLevel = sessionOperations.getDefaultConsistencyLevel();
this.idempotent = sessionOperations.getDefaultQueryIdempotency();
}
public abstract Statement buildStatement(boolean cached);
public O uncached(boolean enabled) {
ignoreCache = !enabled;
return (O) this;
}
public O uncached() {
ignoreCache = true;
return (O) this;
}
public O showValues(boolean enabled) {
this.showValues = enabled;
return (O) this;
}
public O defaultTimestamp(long timestamp) {
this.defaultTimestamp = new long[1];
this.defaultTimestamp[0] = timestamp;
return (O) this;
}
public O retryPolicy(RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
return (O) this;
}
public O defaultRetryPolicy() {
this.retryPolicy = DefaultRetryPolicy.INSTANCE;
return (O) this;
}
public O idempotent() {
this.idempotent = true;
return (O) this;
}
public O isIdempotent(boolean idempotent) {
this.idempotent = idempotent;
return (O) this;
}
public O downgradingConsistencyRetryPolicy() {
this.retryPolicy = DowngradingConsistencyRetryPolicy.INSTANCE;
return (O) this;
}
public O fallthroughRetryPolicy() {
this.retryPolicy = FallthroughRetryPolicy.INSTANCE;
return (O) this;
}
public O consistency(ConsistencyLevel level) {
this.consistencyLevel = level;
return (O) this;
}
public O consistencyAny() {
this.consistencyLevel = ConsistencyLevel.ANY;
return (O) this;
}
public O consistencyOne() {
this.consistencyLevel = ConsistencyLevel.ONE;
return (O) this;
}
public O consistencyQuorum() {
this.consistencyLevel = ConsistencyLevel.QUORUM;
return (O) this;
}
public O consistencyAll() {
this.consistencyLevel = ConsistencyLevel.ALL;
return (O) this;
}
public O consistencyLocalOne() {
this.consistencyLevel = ConsistencyLevel.LOCAL_ONE;
return (O) this;
}
public O consistencyLocalQuorum() {
this.consistencyLevel = ConsistencyLevel.LOCAL_QUORUM;
return (O) this;
}
public O consistencyEachQuorum() {
this.consistencyLevel = ConsistencyLevel.EACH_QUORUM;
return (O) this;
}
public O serialConsistency(ConsistencyLevel level) {
this.serialConsistencyLevel = level;
return (O) this;
}
public O serialConsistencyAny() {
this.serialConsistencyLevel = ConsistencyLevel.ANY;
return (O) this;
}
public O serialConsistencyOne() {
this.serialConsistencyLevel = ConsistencyLevel.ONE;
return (O) this;
}
public O serialConsistencyQuorum() {
this.serialConsistencyLevel = ConsistencyLevel.QUORUM;
return (O) this;
}
public O serialConsistencyAll() {
this.serialConsistencyLevel = ConsistencyLevel.ALL;
return (O) this;
}
public O serialConsistencyLocal() {
this.serialConsistencyLevel = ConsistencyLevel.LOCAL_SERIAL;
return (O) this;
}
public O serialConsistencyLocalQuorum() {
this.serialConsistencyLevel = ConsistencyLevel.LOCAL_QUORUM;
return (O) this;
}
public O disableTracing() {
this.enableTracing = false;
return (O) this;
}
public O enableTracing() {
this.enableTracing = true;
return (O) this;
}
public O tracing(boolean enable) {
this.enableTracing = enable;
return (O) this;
}
public O fetchSize(int fetchSize) {
this.fetchSize = new int[1];
this.fetchSize[0] = fetchSize;
return (O) this;
}
public O queryTimeoutMs(long ms) {
this.queryExecutionTimeout = ms;
this.queryTimeoutUnits = TimeUnit.MILLISECONDS;
return (O) this;
}
public O queryTimeout(long timeout, TimeUnit units) {
this.queryExecutionTimeout = timeout;
this.queryTimeoutUnits = units;
return (O) this;
}
public Statement options(Statement statement) {
if (defaultTimestamp != null) {
statement.setDefaultTimestamp(defaultTimestamp[0]);
}
if (consistencyLevel != null) {
statement.setConsistencyLevel(consistencyLevel);
}
if (serialConsistencyLevel != null) {
statement.setSerialConsistencyLevel(serialConsistencyLevel);
}
if (retryPolicy != null) {
statement.setRetryPolicy(retryPolicy);
}
if (enableTracing) {
statement.enableTracing();
} else {
statement.disableTracing();
}
if (fetchSize != null) {
statement.setFetchSize(fetchSize[0]);
}
if (isIdempotentOperation()) {
statement.setIdempotent(true);
}
return statement;
}
@Override
protected boolean isIdempotentOperation() {
return idempotent;
}
public Statement statement() {
return buildStatement(false);
}
public String cql() {
Statement statement = buildStatement(false);
if (statement == null) return "";
if (statement instanceof BuiltStatement) {
BuiltStatement buildStatement = (BuiltStatement) statement;
return buildStatement.setForceNoValues(true).getQueryString();
} else {
return statement.toString();
}
}
public PreparedStatement prepareStatement() {
Statement statement = buildStatement(true);
if (statement instanceof RegularStatement) {
RegularStatement regularStatement = (RegularStatement) statement;
return sessionOps.prepare(regularStatement);
}
throw new HelenusException("only RegularStatements can be prepared");
}
public ListenableFuture<PreparedStatement> prepareStatementAsync() {
Statement statement = buildStatement(true);
if (statement instanceof RegularStatement) {
RegularStatement regularStatement = (RegularStatement) statement;
return sessionOps.prepareAsync(regularStatement);
}
throw new HelenusException("only RegularStatements can be prepared");
}
protected boolean ignoreCache() {
return ignoreCache;
}
protected E checkCache(UnitOfWork uow, List<Facet> facets) {
E result = null;
Optional<Object> optionalCachedResult = Optional.empty();
if (!facets.isEmpty()) {
optionalCachedResult = uow.cacheLookup(facets);
if (optionalCachedResult.isPresent()) {
result = (E) optionalCachedResult.get();
}
}
return result;
}
protected Object cacheUpdate(UnitOfWork uow, E pojo, List<Facet> identifyingFacets) {
List<Facet> facets = new ArrayList<>();
Map<String, Object> valueMap =
pojo instanceof MapExportable ? ((MapExportable) pojo).toMap() : null;
for (Facet facet : identifyingFacets) {
if (facet instanceof UnboundFacet) {
UnboundFacet unboundFacet = (UnboundFacet) facet;
UnboundFacet.Binder binder = unboundFacet.binder();
for (HelenusProperty prop : unboundFacet.getProperties()) {
Object value;
if (valueMap == null) {
value = BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
if (value != null) {
binder.setValueForProperty(prop, value.toString());
}
} else {
value = valueMap.get(prop.getPropertyName());
if (value != null) {
binder.setValueForProperty(prop, value.toString());
}
}
}
if (binder.isBound()) {
facets.add(binder.bind());
}
} else {
facets.add(facet);
}
}
// Cache the value (pojo), the statement key, and the fully bound facets.
return uow.cacheUpdate(pojo, facets);
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,246 +15,123 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import static net.helenus.core.HelenusSession.deleted; import java.util.stream.Stream;
import com.codahale.metrics.Timer;
import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Stopwatch; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Helenus;
import net.helenus.core.UnitOfWork;
import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet;
import net.helenus.mapping.MappingUtil;
import net.helenus.support.Fun; import net.helenus.support.Fun;
import org.apache.commons.lang3.SerializationUtils; import net.helenus.support.Scala;
import scala.concurrent.Future;
public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperation<E, O>> public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperation<E, O>>
extends AbstractStatementOperation<E, O> { extends
AbstractStatementOperation<E, O> {
public AbstractStreamOperation(AbstractSessionOperations sessionOperations) { public AbstractStreamOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public abstract Stream<E> transform(ResultSet resultSet); public abstract Stream<E> transform(ResultSet resultSet);
public PreparedStreamOperation<E> prepare() { public PreparedStreamOperation<E> prepare() {
return new PreparedStreamOperation<E>(prepareStatement(), this); return new PreparedStreamOperation<E>(prepareStatement(), this);
} }
public ListenableFuture<PreparedStreamOperation<E>> prepareAsync() { public ListenableFuture<PreparedStreamOperation<E>> prepareAsync() {
final O _this = (O) this;
return Futures.transform(
prepareStatementAsync(),
new Function<PreparedStatement, PreparedStreamOperation<E>>() {
@Override
public PreparedStreamOperation<E> apply(PreparedStatement preparedStatement) {
return new PreparedStreamOperation<E>(preparedStatement, _this);
}
});
}
public Stream<E> sync() throws TimeoutException { final O _this = (O) this;
final Timer.Context context = requestLatency.time();
try {
Stream<E> resultStream = null;
E cacheResult = null;
boolean updateCache = isSessionCacheable();
if (!ignoreCache() && isSessionCacheable()) { return Futures.transform(prepareStatementAsync(),
List<Facet> facets = bindFacetValues(); new Function<PreparedStatement, PreparedStreamOperation<E>>() {
if (facets != null && facets.size() > 0) {
if (facets.stream().filter(f -> !f.fixed()).distinct().count() > 0) { @Override
String tableName = CacheUtil.schemaName(facets); public PreparedStreamOperation<E> apply(PreparedStatement preparedStatement) {
cacheResult = (E) sessionOps.checkCache(tableName, facets); return new PreparedStreamOperation<E>(preparedStatement, _this);
if (cacheResult != null) { }
resultStream = Stream.of(cacheResult);
updateCache = false; });
sessionCacheHits.mark();
cacheHits.mark(); }
} else {
sessionCacheMiss.mark(); public Future<PreparedStreamOperation<E>> prepareFuture() {
cacheMiss.mark(); return Scala.asFuture(prepareAsync());
}
public Stream<E> sync() {
ListenableFuture<Stream<E>> future = async();
Futures.addCallback(future, new FutureCallback<String>() {
@Override
public void onSuccess(String contents) {
//...process web site contents
} }
} else {
//TODO(gburd): look in statement cache for results
}
}
}
if (resultStream == null) { @Override
// Formulate the query and execute it against the Cassandra cluster. public void onFailure(Throwable throwable) {
ResultSet resultSet = log.error("Exception in task", throwable);
this.execute(
sessionOps,
null,
queryExecutionTimeout,
queryTimeoutUnits,
showValues,
isSessionCacheable());
// Transform the query result set into the desired shape.
resultStream = transform(resultSet);
}
if (updateCache && resultStream != null) {
List<Facet> facets = getFacets();
if (facets != null && facets.size() > 1) {
List<E> again = new ArrayList<>();
resultStream.forEach(
result -> {
Class<?> resultClass = result.getClass();
if (!(resultClass.getEnclosingClass() != null
&& resultClass.getEnclosingClass() == Fun.class)) {
sessionOps.updateCache(result, facets);
}
again.add(result);
});
resultStream = again.stream();
}
}
return resultStream;
} finally {
context.stop();
}
}
public Stream<E> sync(UnitOfWork uow) throws TimeoutException {
if (uow == null) return sync();
final Timer.Context context = requestLatency.time();
try {
Stream<E> resultStream = null;
E cachedResult = null;
final boolean updateCache;
if (!ignoreCache()) {
Stopwatch timer = Stopwatch.createStarted();
try {
List<Facet> facets = bindFacetValues();
if (facets != null && facets.size() > 0) {
if (facets.stream().filter(f -> !f.fixed()).distinct().count() > 0) {
cachedResult = checkCache(uow, facets);
if (cachedResult != null) {
updateCache = false;
resultStream = Stream.of(cachedResult);
uowCacheHits.mark();
cacheHits.mark();
uow.recordCacheAndDatabaseOperationCount(1, 0);
} else {
uowCacheMiss.mark();
if (isSessionCacheable()) {
String tableName = CacheUtil.schemaName(facets);
cachedResult = (E) sessionOps.checkCache(tableName, facets);
if (cachedResult != null) {
Class<?> iface = MappingUtil.getMappingInterface(cachedResult);
E result = null;
if (Helenus.entity(iface).isDraftable()) {
result = cachedResult;
} else {
result =
(E) SerializationUtils.<Serializable>clone((Serializable) cachedResult);
}
updateCache = false;
resultStream = Stream.of(result);
sessionCacheHits.mark();
cacheHits.mark();
uow.recordCacheAndDatabaseOperationCount(1, 0);
} else {
updateCache = true;
sessionCacheMiss.mark();
cacheMiss.mark();
uow.recordCacheAndDatabaseOperationCount(-1, 0);
}
} else {
updateCache = false;
}
}
} else {
//TODO(gburd): look in statement cache for results
updateCache = false; //true;
cacheMiss.mark();
uow.recordCacheAndDatabaseOperationCount(-1, 0);
} }
} else {
updateCache = false;
}
} finally {
timer.stop();
uow.addCacheLookupTime(timer);
}
} else {
updateCache = false;
}
// Check to see if we fetched the object from the cache
if (resultStream == null) {
ResultSet resultSet =
execute(sessionOps, uow, queryExecutionTimeout, queryTimeoutUnits, showValues, true);
resultStream = transform(resultSet);
}
// If we have a result and we're caching then we need to put it into the cache
// for future requests to find.
if (resultStream != null) {
if (updateCache) {
List<E> again = new ArrayList<>();
List<Facet> facets = getFacets();
resultStream.forEach(
result -> {
Class<?> resultClass = result.getClass();
if (result != deleted
&& !(resultClass.getEnclosingClass() != null
&& resultClass.getEnclosingClass() == Fun.class)) {
result = (E) cacheUpdate(uow, result, facets);
}
again.add(result);
});
resultStream = again.stream();
}
}
return resultStream;
} finally {
context.stop();
}
}
public CompletableFuture<Stream<E>> async() {
return CompletableFuture.<Stream<E>>supplyAsync(
() -> {
try {
return sync();
} catch (TimeoutException ex) {
throw new CompletionException(ex);
}
}); });
} }
public ListenableFuture<Stream<E>> async() {
ResultSetFuture resultSetFuture = sessionOps.executeAsync(options(buildStatement()), showValues);
ListenableFuture<Stream<E>> future = Futures.transform(resultSetFuture, new Function<ResultSet, Stream<E>>() {
@Override
public Stream<E> apply(ResultSet resultSet) {
return transform(resultSet);
}
}, sessionOps.getExecutor());
return future;
}
public ListenableFuture<scala.collection.immutable.Stream<E>> asyncForScala() {
ResultSetFuture resultSetFuture = sessionOps.executeAsync(options(buildStatement()), showValues);
ListenableFuture<scala.collection.immutable.Stream<E>> future = Futures.transform(resultSetFuture,
new Function<ResultSet, scala.collection.immutable.Stream<E>>() {
@Override
public scala.collection.immutable.Stream<E> apply(ResultSet resultSet) {
Stream<E> stream = transform(resultSet);
return scala.collection.JavaConversions.asScalaIterator(stream.iterator()).toStream();
}
}, sessionOps.getExecutor());
return future;
}
public Future<scala.collection.immutable.Stream<E>> future() {
return Scala.asFuture(asyncForScala());
}
public <A> Future<Fun.Tuple2<scala.collection.immutable.Stream<E>, A>> future(A a) {
return Scala.asFuture(asyncForScala(), a);
}
public <A, B> Future<Fun.Tuple3<scala.collection.immutable.Stream<E>, A, B>> future(A a, B b) {
return Scala.asFuture(asyncForScala(), a, b);
}
public <A, B, C> Future<Fun.Tuple4<scala.collection.immutable.Stream<E>, A, B, C>> future(A a, B b, C c) {
return Scala.asFuture(asyncForScala(), a, b, c);
}
public <A, B, C, D> Future<Fun.Tuple5<scala.collection.immutable.Stream<E>, A, B, C, D>> future(A a, B b, C c,
D d) {
return Scala.asFuture(asyncForScala(), a, b, c, d);
}
public CompletableFuture<Stream<E>> async(UnitOfWork uow) {
if (uow == null) return async();
CompletableFuture<Stream<E>> f =
CompletableFuture.<Stream<E>>supplyAsync(
() -> {
try {
return sync();
} catch (TimeoutException ex) {
throw new CompletionException(ex);
}
});
uow.addFuture(f);
return f;
}
} }

View file

@ -1,140 +0,0 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core.operation;
import com.codahale.metrics.Timer;
import com.datastax.driver.core.AtomicMonotonicTimestampGenerator;
import com.datastax.driver.core.BatchStatement;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.TimestampGenerator;
import com.google.common.base.Stopwatch;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.UnitOfWork;
import net.helenus.support.HelenusException;
public class BatchOperation extends Operation<Long> {
//TODO(gburd): find the way to get the driver's timestamp generator
private static final TimestampGenerator timestampGenerator =
new AtomicMonotonicTimestampGenerator();
private final BatchStatement batch;
private List<AbstractOperation<?, ?>> operations = new ArrayList<AbstractOperation<?, ?>>();
private boolean logged = true;
public BatchOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations);
batch = new BatchStatement();
}
public void add(AbstractOperation<?, ?> operation) {
operations.add(operation);
}
@Override
public BatchStatement buildStatement(boolean cached) {
batch.addAll(
operations.stream().map(o -> o.buildStatement(cached)).collect(Collectors.toList()));
batch.setConsistencyLevel(sessionOps.getDefaultConsistencyLevel());
return batch;
}
public BatchOperation logged() {
logged = true;
return this;
}
public BatchOperation setLogged(boolean logStatements) {
logged = logStatements;
return this;
}
public Long sync() {
if (operations.size() == 0) return 0L;
final Timer.Context context = requestLatency.time();
try {
batch.setDefaultTimestamp(timestampGenerator.next());
ResultSet resultSet =
this.execute(
sessionOps, null, queryExecutionTimeout, queryTimeoutUnits, showValues, false);
if (!resultSet.wasApplied()) {
throw new HelenusException("Failed to apply batch.");
}
} catch (TimeoutException e) {
throw new HelenusException(e);
} finally {
context.stop();
}
return batch.getDefaultTimestamp();
}
public Long sync(UnitOfWork uow) {
if (operations.size() == 0) return 0L;
if (uow == null) return sync();
final Timer.Context context = requestLatency.time();
final Stopwatch timer = Stopwatch.createStarted();
try {
uow.recordCacheAndDatabaseOperationCount(0, 1);
batch.setDefaultTimestamp(timestampGenerator.next());
ResultSet resultSet =
this.execute(
sessionOps, uow, queryExecutionTimeout, queryTimeoutUnits, showValues, false);
if (!resultSet.wasApplied()) {
throw new HelenusException("Failed to apply batch.");
}
} catch (TimeoutException e) {
throw new HelenusException(e);
} finally {
context.stop();
timer.stop();
}
uow.addDatabaseTime("Cassandra", timer);
return batch.getDefaultTimestamp();
}
public void addAll(BatchOperation batch) {
batch.operations.forEach(o -> this.operations.add(o));
}
public String toString() {
return toString(true); //TODO(gburd): sessionOps.showQueryValues()
}
public String toString(boolean showValues) {
StringBuilder s = new StringBuilder();
s.append("BEGIN ");
if (!logged) {
s.append("UNLOGGED ");
}
s.append("BATCH ");
if (batch.getDefaultTimestamp() > -9223372036854775808L) {
s.append("USING TIMESTAMP ").append(String.valueOf(batch.getDefaultTimestamp())).append(" ");
}
s.append(
operations
.stream()
.map(o -> Operation.queryString(o.buildStatement(showValues), showValues))
.collect(Collectors.joining(" ")));
s.append(" APPLY BATCH;");
return s.toString();
}
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,27 +21,23 @@ import com.datastax.driver.core.Statement;
public final class BoundOperation<E> extends AbstractOperation<E, BoundOperation<E>> { public final class BoundOperation<E> extends AbstractOperation<E, BoundOperation<E>> {
private final BoundStatement boundStatement; private final BoundStatement boundStatement;
private final AbstractOperation<E, ?> delegate; private final AbstractOperation<E, ?> delegate;
public BoundOperation(BoundStatement boundStatement, AbstractOperation<E, ?> operation) { public BoundOperation(BoundStatement boundStatement, AbstractOperation<E, ?> operation) {
super(operation.sessionOps); super(operation.sessionOps);
this.boundStatement = boundStatement; this.boundStatement = boundStatement;
this.delegate = operation; this.delegate = operation;
} }
@Override @Override
public E transform(ResultSet resultSet) { public E transform(ResultSet resultSet) {
return delegate.transform(resultSet); return delegate.transform(resultSet);
} }
@Override @Override
public Statement buildStatement(boolean cached) { public Statement buildStatement() {
return boundStatement; return boundStatement;
} }
@Override
public boolean isSessionCacheable() {
return delegate.isSessionCacheable();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,36 +15,31 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.Optional;
import com.datastax.driver.core.BoundStatement; import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Statement; import com.datastax.driver.core.Statement;
import java.util.Optional;
public final class BoundOptionalOperation<E> public final class BoundOptionalOperation<E> extends AbstractOptionalOperation<E, BoundOptionalOperation<E>> {
extends AbstractOptionalOperation<E, BoundOptionalOperation<E>> {
private final BoundStatement boundStatement; private final BoundStatement boundStatement;
private final AbstractOptionalOperation<E, ?> delegate; private final AbstractOptionalOperation<E, ?> delegate;
public BoundOptionalOperation( public BoundOptionalOperation(BoundStatement boundStatement, AbstractOptionalOperation<E, ?> operation) {
BoundStatement boundStatement, AbstractOptionalOperation<E, ?> operation) { super(operation.sessionOps);
super(operation.sessionOps); this.boundStatement = boundStatement;
this.boundStatement = boundStatement; this.delegate = operation;
this.delegate = operation; }
}
@Override @Override
public Optional<E> transform(ResultSet resultSet) { public Optional<E> transform(ResultSet resultSet) {
return delegate.transform(resultSet); return delegate.transform(resultSet);
} }
@Override @Override
public Statement buildStatement(boolean cached) { public Statement buildStatement() {
return boundStatement; return boundStatement;
} }
@Override
public boolean isSessionCacheable() {
return delegate.isSessionCacheable();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,43 +15,31 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.stream.Stream;
import com.datastax.driver.core.BoundStatement; import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Statement; import com.datastax.driver.core.Statement;
import java.util.List;
import java.util.stream.Stream;
import net.helenus.core.cache.Facet;
public final class BoundStreamOperation<E> public final class BoundStreamOperation<E> extends AbstractStreamOperation<E, BoundStreamOperation<E>> {
extends AbstractStreamOperation<E, BoundStreamOperation<E>> {
private final BoundStatement boundStatement; private final BoundStatement boundStatement;
private final AbstractStreamOperation<E, ?> delegate; private final AbstractStreamOperation<E, ?> delegate;
public BoundStreamOperation( public BoundStreamOperation(BoundStatement boundStatement, AbstractStreamOperation<E, ?> operation) {
BoundStatement boundStatement, AbstractStreamOperation<E, ?> operation) { super(operation.sessionOps);
super(operation.sessionOps); this.boundStatement = boundStatement;
this.boundStatement = boundStatement; this.delegate = operation;
this.delegate = operation; }
}
@Override @Override
public List<Facet> bindFacetValues() { public Stream<E> transform(ResultSet resultSet) {
return delegate.bindFacetValues(); return delegate.transform(resultSet);
} }
@Override @Override
public Stream<E> transform(ResultSet resultSet) { public Statement buildStatement() {
return delegate.transform(resultSet); return boundStatement;
} }
@Override
public Statement buildStatement(boolean cached) {
return boundStatement;
}
@Override
public boolean isSessionCacheable() {
return delegate.isSessionCacheable();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,6 +20,7 @@ import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select; import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Select.Where; import com.datastax.driver.core.querybuilder.Select.Where;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Filter; import net.helenus.core.Filter;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
@ -29,57 +29,54 @@ import net.helenus.support.HelenusMappingException;
public final class CountOperation extends AbstractFilterOperation<Long, CountOperation> { public final class CountOperation extends AbstractFilterOperation<Long, CountOperation> {
private HelenusEntity entity; private HelenusEntity entity;
public CountOperation(AbstractSessionOperations sessionOperations) { public CountOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public CountOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) { public CountOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
super(sessionOperations); super(sessionOperations);
this.entity = entity; this.entity = entity;
//TODO(gburd): cache SELECT COUNT results within the scope of a UOW }
}
@Override @Override
public BuiltStatement buildStatement(boolean cached) { public BuiltStatement buildStatement() {
if (filters != null && !filters.isEmpty()) { if (filters != null && !filters.isEmpty()) {
filters.forEach(f -> addPropertyNode(f.getNode())); filters.forEach(f -> addPropertyNode(f.getNode()));
} }
if (entity == null) { if (entity == null) {
throw new HelenusMappingException("unknown entity"); throw new HelenusMappingException("unknown entity");
} }
Select select = QueryBuilder.select().countAll().from(entity.getName().toCql()); Select select = QueryBuilder.select().countAll().from(entity.getName().toCql());
if (filters != null && !filters.isEmpty()) { if (filters != null && !filters.isEmpty()) {
Where where = select.where(); Where where = select.where();
for (Filter<?> filter : filters) { for (Filter<?> filter : filters) {
where.and(filter.getClause(sessionOps.getValuePreparer())); where.and(filter.getClause(sessionOps.getValuePreparer()));
} }
} }
return select; return select;
} }
@Override @Override
public Long transform(ResultSet resultSet) { public Long transform(ResultSet resultSet) {
return resultSet.one().getLong(0); return resultSet.one().getLong(0);
} }
private void addPropertyNode(HelenusPropertyNode p) {
if (entity == null) {
entity = p.getEntity();
} else if (entity != p.getEntity()) {
throw new HelenusMappingException("you can count columns only in single entity "
+ entity.getMappingInterface() + " or " + p.getEntity().getMappingInterface());
}
}
private void addPropertyNode(HelenusPropertyNode p) {
if (entity == null) {
entity = p.getEntity();
} else if (entity != p.getEntity()) {
throw new HelenusMappingException(
"you can count columns only in single entity "
+ entity.getMappingInterface()
+ " or "
+ p.getEntity().getMappingInterface());
}
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,155 +20,106 @@ import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.Delete; import com.datastax.driver.core.querybuilder.Delete;
import com.datastax.driver.core.querybuilder.Delete.Where; import com.datastax.driver.core.querybuilder.Delete.Where;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import java.util.List;
import java.util.concurrent.TimeoutException;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Filter; import net.helenus.core.Filter;
import net.helenus.core.UnitOfWork;
import net.helenus.core.cache.Facet;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.support.HelenusException;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public final class DeleteOperation extends AbstractFilterOperation<ResultSet, DeleteOperation> { public final class DeleteOperation extends AbstractFilterOperation<ResultSet, DeleteOperation> {
private HelenusEntity entity; private HelenusEntity entity;
private boolean ifExists = false; private boolean ifExists = false;
private int[] ttl; private int[] ttl;
private long[] timestamp; private long[] timestamp;
public DeleteOperation(AbstractSessionOperations sessionOperations) { public DeleteOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public DeleteOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) { public DeleteOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
super(sessionOperations); super(sessionOperations);
this.entity = entity; this.entity = entity;
} }
@Override @Override
public BuiltStatement buildStatement(boolean cached) { public BuiltStatement buildStatement() {
if (filters != null && !filters.isEmpty()) { if (filters != null && !filters.isEmpty()) {
filters.forEach(f -> addPropertyNode(f.getNode())); filters.forEach(f -> addPropertyNode(f.getNode()));
} }
if (entity == null) { if (entity == null) {
throw new HelenusMappingException("unknown entity"); throw new HelenusMappingException("unknown entity");
} }
if (filters != null && !filters.isEmpty()) { if (filters != null && !filters.isEmpty()) {
Delete delete = QueryBuilder.delete().from(entity.getName().toCql()); Delete delete = QueryBuilder.delete().from(entity.getName().toCql());
if (this.ifExists) { if (this.ifExists) {
delete.ifExists(); delete.ifExists();
} }
Where where = delete.where(); Where where = delete.where();
for (Filter<?> filter : filters) { for (Filter<?> filter : filters) {
where.and(filter.getClause(sessionOps.getValuePreparer())); where.and(filter.getClause(sessionOps.getValuePreparer()));
} }
if (ifFilters != null && !ifFilters.isEmpty()) { if (ifFilters != null && !ifFilters.isEmpty()) {
for (Filter<?> filter : ifFilters) { for (Filter<?> filter : ifFilters) {
delete.onlyIf(filter.getClause(sessionOps.getValuePreparer())); delete.onlyIf(filter.getClause(sessionOps.getValuePreparer()));
} }
} }
if (this.ttl != null) { if (this.ttl != null) {
delete.using(QueryBuilder.ttl(this.ttl[0])); delete.using(QueryBuilder.ttl(this.ttl[0]));
} }
if (this.timestamp != null) { if (this.timestamp != null) {
delete.using(QueryBuilder.timestamp(this.timestamp[0])); delete.using(QueryBuilder.timestamp(this.timestamp[0]));
} }
return delete; return delete;
} else { } else {
return QueryBuilder.truncate(entity.getName().toCql()); return QueryBuilder.truncate(entity.getName().toCql());
} }
} }
@Override @Override
public ResultSet transform(ResultSet resultSet) { public ResultSet transform(ResultSet resultSet) {
return resultSet; return resultSet;
} }
public DeleteOperation ifExists() { public DeleteOperation ifExists() {
this.ifExists = true; this.ifExists = true;
return this; return this;
} }
public DeleteOperation usingTtl(int ttl) { public DeleteOperation usingTtl(int ttl) {
this.ttl = new int[1]; this.ttl = new int[1];
this.ttl[0] = ttl; this.ttl[0] = ttl;
return this; return this;
} }
public DeleteOperation usingTimestamp(long timestamp) { public DeleteOperation usingTimestamp(long timestamp) {
this.timestamp = new long[1]; this.timestamp = new long[1];
this.timestamp[0] = timestamp; this.timestamp[0] = timestamp;
return this; return this;
} }
private void addPropertyNode(HelenusPropertyNode p) { private void addPropertyNode(HelenusPropertyNode p) {
if (entity == null) { if (entity == null) {
entity = p.getEntity(); entity = p.getEntity();
} else if (entity != p.getEntity()) { } else if (entity != p.getEntity()) {
throw new HelenusMappingException( throw new HelenusMappingException("you can delete rows only in single entity "
"you can delete rows only in single entity " + entity.getMappingInterface() + " or " + p.getEntity().getMappingInterface());
+ entity.getMappingInterface() }
+ " or " }
+ p.getEntity().getMappingInterface());
}
}
public List<Facet> bindFacetValues() {
return bindFacetValues(getFacets());
}
protected boolean isIdempotentOperation() {
return true;
}
@Override
public ResultSet sync() throws TimeoutException {
ResultSet result = super.sync();
if (entity.isCacheable()) {
sessionOps.cacheEvict(bindFacetValues());
}
return result;
}
@Override
public ResultSet sync(UnitOfWork uow) throws TimeoutException {
if (uow == null) {
return sync();
}
ResultSet result = super.sync(uow);
uow.cacheEvict(bindFacetValues());
return result;
}
public ResultSet batch(UnitOfWork uow) throws TimeoutException {
if (uow == null) {
throw new HelenusException("UnitOfWork cannot be null when batching operations.");
}
uow.cacheEvict(bindFacetValues());
uow.batch(this);
return null;
}
@Override
public List<Facet> getFacets() {
return entity.getFacets();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,409 +15,154 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.*;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement; import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.Insert; import com.datastax.driver.core.querybuilder.Insert;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import java.util.*;
import java.util.concurrent.TimeoutException; import com.google.common.base.Predicates;
import java.util.function.Function; import com.google.common.collect.Lists;
import java.util.stream.Collectors; import com.google.common.collect.Maps;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Getter; import net.helenus.core.Getter;
import net.helenus.core.Helenus;
import net.helenus.core.UnitOfWork;
import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet;
import net.helenus.core.cache.UnboundFacet;
import net.helenus.core.reflect.DefaultPrimitiveTypes;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.core.reflect.MapExportable; import net.helenus.core.reflect.MapExportable;
import net.helenus.mapping.ColumnType;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.MappingUtil; import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.value.BeanColumnValueProvider; import net.helenus.mapping.value.BeanColumnValueProvider;
import net.helenus.support.Fun; import net.helenus.support.Fun;
import net.helenus.support.HelenusException;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public final class InsertOperation<T> extends AbstractOperation<T, InsertOperation<T>> { public final class InsertOperation extends AbstractOperation<ResultSet, InsertOperation> {
private final List<Fun.Tuple2<HelenusPropertyNode, Object>> values = private HelenusEntity entity;
new ArrayList<Fun.Tuple2<HelenusPropertyNode, Object>>();
private final T pojo;
private final Class<?> resultType;
private final Set<String> readSet;
private HelenusEntity entity;
private boolean ifNotExists;
private int[] ttl; private final List<Fun.Tuple2<HelenusPropertyNode, Object>> values = new ArrayList<Fun.Tuple2<HelenusPropertyNode, Object>>();
private long[] timestamp; private boolean ifNotExists;
private long writeTime = 0L;
public InsertOperation(AbstractSessionOperations sessionOperations, boolean ifNotExists) { private int[] ttl;
super(sessionOperations); private long[] timestamp;
this.pojo = null; public InsertOperation(AbstractSessionOperations sessionOperations, boolean ifNotExists) {
this.readSet = null; super(sessionOperations);
this.ifNotExists = ifNotExists;
this.resultType = ResultSet.class;
}
public InsertOperation( this.ifNotExists = ifNotExists;
AbstractSessionOperations sessionOperations, }
HelenusEntity entity,
Class<?> resultType,
boolean ifNotExists) {
super(sessionOperations);
this.pojo = null; public InsertOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity, Object pojo,
this.readSet = null; boolean ifNotExists) {
this.ifNotExists = ifNotExists; super(sessionOperations);
this.resultType = resultType;
this.entity = entity;
}
public InsertOperation( this.entity = entity;
AbstractSessionOperations sessionOperations, Class<?> resultType, boolean ifNotExists) { this.ifNotExists = ifNotExists;
super(sessionOperations); Set<String> keys = (pojo instanceof MapExportable) ? ((MapExportable)pojo).toMap().keySet() : null;
Collection<HelenusProperty> properties = entity.getOrderedProperties();
this.pojo = null; for (HelenusProperty prop : properties) {
this.readSet = null;
this.ifNotExists = ifNotExists;
this.resultType = resultType;
}
public InsertOperation( // Skip properties that are not in the map of the pojo we're storing. This creates a path
AbstractSessionOperations sessionOperations, // for entity instances to be {in,up}serted without including all columns in the INSERT statement.
HelenusEntity entity, if (keys == null || keys.contains(prop.getPropertyName())) {
T pojo,
Set<String> mutations,
Set<String> read,
boolean ifNotExists) {
super(sessionOperations);
this.pojo = pojo; Object value = BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop);
this.readSet = read; value = sessionOps.getValuePreparer().prepareColumnValue(value, prop);
this.entity = entity;
this.ifNotExists = ifNotExists;
this.resultType = entity.getMappingInterface();
Collection<HelenusProperty> properties = entity.getOrderedProperties(); if (value != null) {
Set<String> keys = (mutations == null) ? null : mutations; HelenusPropertyNode node = new HelenusPropertyNode(prop, Optional.empty());
values.add(Fun.Tuple2.of(node, value));
}
for (HelenusProperty prop : properties) {
boolean addProp = false;
switch (prop.getColumnType()) {
case PARTITION_KEY:
case CLUSTERING_COLUMN:
addProp = true;
break;
default:
addProp = (keys == null || keys.contains(prop.getPropertyName()));
}
if (addProp) {
Object value = BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop);
value = sessionOps.getValuePreparer().prepareColumnValue(value, prop);
if (value != null) {
HelenusPropertyNode node = new HelenusPropertyNode(prop, Optional.empty());
values.add(Fun.Tuple2.of(node, value));
}
}
}
}
public InsertOperation<T> ifNotExists() {
this.ifNotExists = true;
return this;
}
public InsertOperation<T> ifNotExists(boolean enable) {
this.ifNotExists = enable;
return this;
}
public <V> InsertOperation<T> value(Getter<V> getter, V val) {
Objects.requireNonNull(getter, "getter is empty");
if (val != null) {
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
Object value = sessionOps.getValuePreparer().prepareColumnValue(val, node.getProperty());
if (value != null) {
values.add(Fun.Tuple2.of(node, value));
}
}
return this;
}
@Override
public BuiltStatement buildStatement(boolean cached) {
List<HelenusEntity> entities =
values
.stream()
.map(t -> t._1.getProperty().getEntity())
.distinct()
.collect(Collectors.toList());
if (entities.size() != 1) {
throw new HelenusMappingException(
"you can insert only single entity at a time, found: "
+ entities
.stream()
.map(e -> e.getMappingInterface().toString())
.collect(Collectors.joining(", ")));
}
HelenusEntity entity = entities.get(0);
if (this.entity != null) {
if (this.entity != entity) {
throw new HelenusMappingException(
"you can insert only single entity at a time, found: "
+ this.entity.getMappingInterface().toString()
+ ", "
+ entity.getMappingInterface().toString());
}
} else {
this.entity = entity;
}
if (values.isEmpty()) return null;
if (entity == null) {
throw new HelenusMappingException("unknown entity");
}
Insert insert = QueryBuilder.insertInto(entity.getName().toCql());
if (ifNotExists) {
insert.ifNotExists();
}
values.forEach(
t -> {
insert.value(t._1.getColumnName(), t._2);
});
//TODO(gburd): IF NOT EXISTS when @Constraints.Relationship is 1:1 or 1:m
if (this.ttl != null) {
insert.using(QueryBuilder.ttl(this.ttl[0]));
}
if (this.timestamp != null) {
insert.using(QueryBuilder.timestamp(this.timestamp[0]));
}
return insert;
}
private T newInstance(Class<?> iface) {
if (values.size() > 0) {
boolean immutable = entity.isDraftable();
Collection<HelenusProperty> properties = entity.getOrderedProperties();
Map<String, Object> backingMap = new HashMap<String, Object>(properties.size());
// First, add all the inserted values into our new map.
values.forEach(t -> backingMap.put(t._1.getProperty().getPropertyName(), t._2));
// Then, fill in all the rest of the properties.
for (HelenusProperty prop : properties) {
String key = prop.getPropertyName();
if (backingMap.containsKey(key)) {
// Some values man need to be converted (e.g. from String to Enum). This is done
// within the BeanColumnValueProvider below.
Optional<Function<Object, Object>> converter =
prop.getReadConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
backingMap.put(key, converter.get().apply(backingMap.get(key)));
}
} else {
// If we started this operation with an instance of this type, use values from
// that.
if (pojo != null) {
backingMap.put(
key, BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, immutable));
} else {
// Otherwise we'll use default values for the property type if available.
Class<?> propType = prop.getJavaType();
if (propType.isPrimitive()) {
DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(propType);
if (type == null) {
throw new HelenusException("unknown primitive type " + propType);
}
backingMap.put(key, type.getDefaultValue());
} }
}
}
}
// Lastly, create a new proxy object for the entity and return the new instance. }
return (T) Helenus.map(iface, backingMap);
}
return null;
}
@Override }
public T transform(ResultSet resultSet) {
if ((ifNotExists == true) && (resultSet.wasApplied() == false)) {
throw new HelenusException("Statement was not applied due to consistency constraints");
}
Class<?> iface = entity.getMappingInterface(); public InsertOperation ifNotExists() {
if (resultType == iface) { this.ifNotExists = true;
T o = newInstance(iface); return this;
if (o == null) { }
// Oddly, this insert didn't change anything so simply return the pojo.
return (T) pojo;
}
return o;
}
return (T) resultSet;
}
public InsertOperation<T> usingTtl(int ttl) { public InsertOperation ifNotExists(boolean enable) {
this.ttl = new int[1]; this.ifNotExists = enable;
this.ttl[0] = ttl; return this;
return this; }
}
public InsertOperation<T> usingTimestamp(long timestamp) { public <V> InsertOperation value(Getter<V> getter, V val) {
this.timestamp = new long[1];
this.timestamp[0] = timestamp;
return this;
}
protected void adjustTtlAndWriteTime(MapExportable pojo) { Objects.requireNonNull(getter, "getter is empty");
if (ttl != null || writeTime != 0L) {
List<String> columnNames =
values
.stream()
.map(t -> t._1.getProperty())
.filter(
prop -> {
switch (prop.getColumnType()) {
case PARTITION_KEY:
case CLUSTERING_COLUMN:
return false;
default:
return true;
}
})
.map(prop -> prop.getColumnName().toCql(false))
.collect(Collectors.toList());
if (columnNames.size() > 0) { if (val != null) {
if (ttl != null) { HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
columnNames.forEach(name -> pojo.put(CacheUtil.ttlKey(name), ttl)); Object value = sessionOps.getValuePreparer().prepareColumnValue(val, node.getProperty());
}
if (writeTime != 0L) {
columnNames.forEach(name -> pojo.put(CacheUtil.writeTimeKey(name), writeTime));
}
}
}
}
@Override if (value != null) {
protected boolean isIdempotentOperation() { values.add(Fun.Tuple2.of(node, value));
return values.stream().map(v -> v._1.getProperty()).allMatch(prop -> prop.isIdempotent()) }
|| super.isIdempotentOperation(); }
}
@Override return this;
public T sync() throws TimeoutException { }
T result = super.sync();
if (entity.isCacheable() && result != null) {
adjustTtlAndWriteTime((MapExportable) result);
sessionOps.updateCache(result, bindFacetValues());
}
return result;
}
@Override @Override
public T sync(UnitOfWork uow) throws TimeoutException { public BuiltStatement buildStatement() {
if (uow == null) {
return sync();
}
T result = super.sync(uow);
if (result != null && pojo != null && !(pojo == result) && pojo.equals(result)) {
// To preserve object identity we need to find this object in cache
// because it was unchanged by the INSERT but pojo in this case was
// the result of a draft.build().
T cachedValue = (T) uow.cacheLookup(bindFacetValues());
if (cachedValue != null) {
result = cachedValue;
}
}
Class<?> iface = entity.getMappingInterface();
if (resultType == iface) {
if (entity != null && MapExportable.class.isAssignableFrom(entity.getMappingInterface())) {
adjustTtlAndWriteTime((MapExportable) result);
}
cacheUpdate(uow, result, bindFacetValues());
}
return result;
}
public T batch(UnitOfWork uow) throws TimeoutException { values.forEach(t -> addPropertyNode(t._1));
if (uow == null) {
throw new HelenusException("UnitOfWork cannot be null when batching operations.");
}
if (this.entity != null) { if (values.isEmpty())
Class<?> iface = this.entity.getMappingInterface(); return null;
if (resultType == iface) {
final T result = (pojo == null) ? newInstance(iface) : pojo;
if (result != null) {
adjustTtlAndWriteTime((MapExportable) result);
cacheUpdate(uow, result, bindFacetValues());
}
uow.batch(this);
return (T) result;
}
}
return sync(uow); if (entity == null) {
} throw new HelenusMappingException("unknown entity");
}
@Override Insert insert = QueryBuilder.insertInto(entity.getName().toCql());
public List<Facet> bindFacetValues() {
List<Facet> facets = getFacets();
if (facets == null || facets.size() == 0) {
return new ArrayList<Facet>();
}
List<Facet> boundFacets = new ArrayList<>();
Map<HelenusProperty, Object> valuesMap = new HashMap<>(values.size());
values.forEach(t -> valuesMap.put(t._1.getProperty(), t._2));
for (Facet facet : facets) { if (ifNotExists) {
if (facet instanceof UnboundFacet) { insert.ifNotExists();
UnboundFacet unboundFacet = (UnboundFacet) facet; }
UnboundFacet.Binder binder = unboundFacet.binder();
for (HelenusProperty prop : unboundFacet.getProperties()) {
Object value = valuesMap.get(prop);
if (value != null) {
binder.setValueForProperty(prop, value.toString());
}
}
if (binder.isBound()) {
boundFacets.add(binder.bind());
}
} else {
boundFacets.add(facet);
}
}
return boundFacets;
}
@Override values.forEach(t -> {
public List<Facet> getFacets() { insert.value(t._1.getColumnName(), t._2);
if (entity != null) { });
return entity.getFacets();
} else { if (this.ttl != null) {
return new ArrayList<Facet>(); insert.using(QueryBuilder.ttl(this.ttl[0]));
} }
} if (this.timestamp != null) {
insert.using(QueryBuilder.timestamp(this.timestamp[0]));
}
return insert;
}
@Override
public ResultSet transform(ResultSet resultSet) {
return resultSet;
}
public InsertOperation usingTtl(int ttl) {
this.ttl = new int[1];
this.ttl[0] = ttl;
return this;
}
public InsertOperation usingTimestamp(long timestamp) {
this.timestamp = new long[1];
this.timestamp[0] = timestamp;
return this;
}
private void addPropertyNode(HelenusPropertyNode p) {
if (entity == null) {
entity = p.getEntity();
} else if (entity != p.getEntity()) {
throw new HelenusMappingException("you can insert only single entity " + entity.getMappingInterface()
+ " or " + p.getEntity().getMappingInterface());
}
}
} }

View file

@ -1,211 +0,0 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core.operation;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.datastax.driver.core.*;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.google.common.base.Stopwatch;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.UnitOfWork;
import net.helenus.core.cache.Facet;
import net.helenus.support.HelenusException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class Operation<E> {
private static final Logger LOG = LoggerFactory.getLogger(Operation.class);
protected final AbstractSessionOperations sessionOps;
protected boolean showValues;
protected long queryExecutionTimeout = 10;
protected TimeUnit queryTimeoutUnits = TimeUnit.SECONDS;
protected final Meter uowCacheHits;
protected final Meter uowCacheMiss;
protected final Meter sessionCacheHits;
protected final Meter sessionCacheMiss;
protected final Meter cacheHits;
protected final Meter cacheMiss;
protected final Timer requestLatency;
Operation(AbstractSessionOperations sessionOperations) {
this.sessionOps = sessionOperations;
this.showValues = sessionOps.showValues();
MetricRegistry metrics = sessionOperations.getMetricRegistry();
if (metrics == null) {
metrics = new MetricRegistry();
}
this.uowCacheHits = metrics.meter("net.helenus.UOW-cache-hits");
this.uowCacheMiss = metrics.meter("net.helenus.UOW-cache-miss");
this.sessionCacheHits = metrics.meter("net.helenus.session-cache-hits");
this.sessionCacheMiss = metrics.meter("net.helenus.session-cache-miss");
this.cacheHits = metrics.meter("net.helenus.cache-hits");
this.cacheMiss = metrics.meter("net.helenus.cache-miss");
this.requestLatency = metrics.timer("net.helenus.request-latency");
}
public static String queryString(BatchOperation operation, boolean includeValues) {
return operation.toString(includeValues);
}
public static String queryString(Statement statement, boolean includeValues) {
String query = null;
if (statement instanceof BuiltStatement) {
BuiltStatement builtStatement = (BuiltStatement) statement;
if (includeValues) {
RegularStatement regularStatement = builtStatement.setForceNoValues(true);
query = regularStatement.getQueryString();
} else {
query = builtStatement.getQueryString();
}
} else if (statement instanceof RegularStatement) {
RegularStatement regularStatement = (RegularStatement) statement;
query = regularStatement.getQueryString();
} else {
query = statement.toString();
}
return query;
}
public ResultSet execute(
AbstractSessionOperations session,
UnitOfWork uow,
long timeout,
TimeUnit units,
boolean showValues,
boolean cached)
throws TimeoutException {
Statement statement = options(buildStatement(cached));
if (session.isShowCql()) {
String stmt =
(this instanceof BatchOperation)
? queryString((BatchOperation) this, showValues)
: queryString(statement, showValues);
session.getPrintStream().println(stmt);
} else if (LOG.isDebugEnabled()) {
String stmt =
(this instanceof BatchOperation)
? queryString((BatchOperation) this, showValues)
: queryString(statement, showValues);
LOG.info("CQL> " + stmt);
}
Stopwatch timer = Stopwatch.createStarted();
try {
ResultSetFuture futureResultSet = session.executeAsync(statement, uow, timer);
if (uow != null) uow.recordCacheAndDatabaseOperationCount(0, 1);
ResultSet resultSet = futureResultSet.getUninterruptibly(timeout, units);
ColumnDefinitions columnDefinitions = resultSet.getColumnDefinitions();
if (LOG.isDebugEnabled()) {
ExecutionInfo ei = resultSet.getExecutionInfo();
Host qh = ei.getQueriedHost();
String oh =
ei.getTriedHosts()
.stream()
.map(Host::getAddress)
.map(InetAddress::toString)
.collect(Collectors.joining(", "));
ConsistencyLevel cl = ei.getAchievedConsistencyLevel();
if (cl == null) {
cl = statement.getConsistencyLevel();
}
int se = ei.getSpeculativeExecutions();
String warn = ei.getWarnings().stream().collect(Collectors.joining(", "));
String ri =
String.format(
"%s %s ~%s %s %s%s%sspec-retries: %d",
"server v" + qh.getCassandraVersion(),
qh.getAddress().toString(),
(oh != null && !oh.equals("")) ? " [tried: " + oh + "]" : "",
qh.getDatacenter(),
qh.getRack(),
(cl != null)
? (" consistency: "
+ cl.name()
+ " "
+ (cl.isDCLocal() ? " DC " : "")
+ (cl.isSerial() ? " SC " : ""))
: "",
(warn != null && !warn.equals("")) ? ": " + warn : "",
se);
if (uow != null) uow.setInfo(ri);
else LOG.debug(ri);
}
if (!resultSet.wasApplied()
&& !(columnDefinitions.size() > 1 || !columnDefinitions.contains("[applied]"))) {
throw new HelenusException("Operation Failed");
}
return resultSet;
} finally {
timer.stop();
if (uow != null) uow.addDatabaseTime("Cassandra", timer);
log(statement, uow, timer, showValues);
}
}
void log(Statement statement, UnitOfWork uow, Stopwatch timer, boolean showValues) {
if (LOG.isInfoEnabled()) {
String uowString = "";
if (uow != null) {
uowString = "UOW(" + uow.hashCode() + ")";
}
String timerString = "";
if (timer != null) {
timerString = String.format(" %s ", timer.toString());
}
LOG.info(
String.format(
"%s%s%s", uowString, timerString, Operation.queryString(statement, showValues)));
}
}
protected boolean isIdempotentOperation() {
return false;
}
public Statement options(Statement statement) {
return statement;
}
public Statement buildStatement(boolean cached) {
return null;
}
public List<Facet> getFacets() {
return new ArrayList<Facet>();
}
public List<Facet> bindFacetValues() {
return null;
}
public boolean isSessionCacheable() {
return false;
}
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,27 +20,28 @@ import com.datastax.driver.core.PreparedStatement;
public final class PreparedOperation<E> { public final class PreparedOperation<E> {
private final PreparedStatement preparedStatement; private final PreparedStatement preparedStatement;
private final AbstractOperation<E, ?> operation; private final AbstractOperation<E, ?> operation;
public PreparedOperation(PreparedStatement statement, AbstractOperation<E, ?> operation) { public PreparedOperation(PreparedStatement statement, AbstractOperation<E, ?> operation) {
this.preparedStatement = statement; this.preparedStatement = statement;
this.operation = operation; this.operation = operation;
} }
public PreparedStatement getPreparedStatement() { public PreparedStatement getPreparedStatement() {
return preparedStatement; return preparedStatement;
} }
public BoundOperation<E> bind(Object... params) { public BoundOperation<E> bind(Object... params) {
BoundStatement boundStatement = preparedStatement.bind(params); BoundStatement boundStatement = preparedStatement.bind(params);
return new BoundOperation<E>(boundStatement, operation); return new BoundOperation<E>(boundStatement, operation);
} }
@Override
public String toString() {
return preparedStatement.getQueryString();
}
@Override
public String toString() {
return preparedStatement.getQueryString();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,28 +20,28 @@ import com.datastax.driver.core.PreparedStatement;
public final class PreparedOptionalOperation<E> { public final class PreparedOptionalOperation<E> {
private final PreparedStatement preparedStatement; private final PreparedStatement preparedStatement;
private final AbstractOptionalOperation<E, ?> operation; private final AbstractOptionalOperation<E, ?> operation;
public PreparedOptionalOperation( public PreparedOptionalOperation(PreparedStatement statement, AbstractOptionalOperation<E, ?> operation) {
PreparedStatement statement, AbstractOptionalOperation<E, ?> operation) { this.preparedStatement = statement;
this.preparedStatement = statement; this.operation = operation;
this.operation = operation; }
}
public PreparedStatement getPreparedStatement() { public PreparedStatement getPreparedStatement() {
return preparedStatement; return preparedStatement;
} }
public BoundOptionalOperation<E> bind(Object... params) { public BoundOptionalOperation<E> bind(Object... params) {
BoundStatement boundStatement = preparedStatement.bind(params); BoundStatement boundStatement = preparedStatement.bind(params);
return new BoundOptionalOperation<E>(boundStatement, operation); return new BoundOptionalOperation<E>(boundStatement, operation);
} }
@Override
public String toString() {
return preparedStatement.getQueryString();
}
@Override
public String toString() {
return preparedStatement.getQueryString();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,26 +20,28 @@ import com.datastax.driver.core.PreparedStatement;
public final class PreparedStreamOperation<E> { public final class PreparedStreamOperation<E> {
private final PreparedStatement preparedStatement; private final PreparedStatement preparedStatement;
private final AbstractStreamOperation<E, ?> operation; private final AbstractStreamOperation<E, ?> operation;
public PreparedStreamOperation( public PreparedStreamOperation(PreparedStatement statement, AbstractStreamOperation<E, ?> operation) {
PreparedStatement statement, AbstractStreamOperation<E, ?> operation) { this.preparedStatement = statement;
this.preparedStatement = statement; this.operation = operation;
this.operation = operation; }
}
public PreparedStatement getPreparedStatement() { public PreparedStatement getPreparedStatement() {
return preparedStatement; return preparedStatement;
} }
public BoundStreamOperation<E> bind(Object... params) { public BoundStreamOperation<E> bind(Object... params) {
BoundStatement boundStatement = preparedStatement.bind(params);
return new BoundStreamOperation<E>(boundStatement, operation); BoundStatement boundStatement = preparedStatement.bind(params);
}
return new BoundStreamOperation<E>(boundStatement, operation);
}
@Override
public String toString() {
return preparedStatement.getQueryString();
}
@Override
public String toString() {
return preparedStatement.getQueryString();
}
} }

View file

@ -1,72 +1,50 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors *
* * Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. * You may obtain a copy of the License at
* You may obtain a copy of the License at *
* * http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0 *
* * Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and * limitations under the License.
* limitations under the License. */
*/ package net.helenus.core.operation;
package net.helenus.core.operation;
import java.util.Optional;
import com.datastax.driver.core.ResultSet; import java.util.function.Function;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.List; import com.datastax.driver.core.ResultSet;
import java.util.Optional; import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.function.Function;
import net.helenus.core.cache.Facet; public final class SelectFirstOperation<E> extends AbstractFilterOptionalOperation<E, SelectFirstOperation<E>> {
public final class SelectFirstOperation<E> private final SelectOperation<E> src;
extends AbstractFilterOptionalOperation<E, SelectFirstOperation<E>> {
public SelectFirstOperation(SelectOperation<E> src) {
private final SelectOperation<E> delegate; super(src.sessionOps);
public SelectFirstOperation(SelectOperation<E> delegate) { this.src = src;
super(delegate.sessionOps); this.filters = src.filters;
this.ifFilters = src.ifFilters;
this.delegate = delegate; }
this.filters = delegate.filters;
this.ifFilters = delegate.ifFilters; public <R> SelectFirstTransformingOperation<R, E> map(Function<E, R> fn) {
} return new SelectFirstTransformingOperation<R, E>(src, fn);
}
public <R> SelectFirstTransformingOperation<R, E> map(Function<E, R> fn) {
return new SelectFirstTransformingOperation<R, E>(delegate, fn); @Override
} public BuiltStatement buildStatement() {
return src.buildStatement();
@Override }
public BuiltStatement buildStatement(boolean cached) {
return delegate.buildStatement(cached); @Override
} public Optional<E> transform(ResultSet resultSet) {
return src.transform(resultSet).findFirst();
@Override }
public List<Facet> getFacets() {
return delegate.getFacets(); }
}
@Override
public List<Facet> bindFacetValues() {
return delegate.bindFacetValues();
}
@Override
public Optional<E> transform(ResultSet resultSet) {
return delegate.transform(resultSet).findFirst();
}
@Override
public boolean isSessionCacheable() {
return delegate.isSessionCacheable();
}
@Override
public boolean ignoreCache() {
return delegate.ignoreCache();
}
}

View file

@ -1,65 +1,50 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors *
* * Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. * You may obtain a copy of the License at
* You may obtain a copy of the License at *
* * http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0 *
* * Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and * limitations under the License.
* limitations under the License. */
*/ package net.helenus.core.operation;
package net.helenus.core.operation;
import java.util.Optional;
import com.datastax.driver.core.ResultSet; import java.util.function.Function;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.List; import com.datastax.driver.core.ResultSet;
import java.util.Optional; import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.function.Function;
import net.helenus.core.cache.Facet; public final class SelectFirstTransformingOperation<R, E>
extends
public final class SelectFirstTransformingOperation<R, E> AbstractFilterOptionalOperation<R, SelectFirstTransformingOperation<R, E>> {
extends AbstractFilterOptionalOperation<R, SelectFirstTransformingOperation<R, E>> {
private final SelectOperation<E> src;
private final SelectOperation<E> delegate; private final Function<E, R> fn;
private final Function<E, R> fn;
public SelectFirstTransformingOperation(SelectOperation<E> src, Function<E, R> fn) {
public SelectFirstTransformingOperation(SelectOperation<E> delegate, Function<E, R> fn) { super(src.sessionOps);
super(delegate.sessionOps);
this.src = src;
this.delegate = delegate; this.fn = fn;
this.fn = fn; this.filters = src.filters;
this.filters = delegate.filters; this.ifFilters = src.ifFilters;
this.ifFilters = delegate.ifFilters; }
}
@Override
@Override public BuiltStatement buildStatement() {
public List<Facet> bindFacetValues() { return src.buildStatement();
return delegate.bindFacetValues(); }
}
@Override
@Override public Optional<R> transform(ResultSet resultSet) {
public BuiltStatement buildStatement(boolean cached) { return src.transform(resultSet).findFirst().map(fn);
return delegate.buildStatement(cached); }
}
}
@Override
public Optional<R> transform(ResultSet resultSet) {
return delegate.transform(resultSet).findFirst().map(fn);
}
@Override
public boolean isSessionCacheable() {
return delegate.isSessionCacheable();
}
@Override
public boolean ignoreCache() {
return delegate.ignoreCache();
}
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +15,11 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row; import com.datastax.driver.core.Row;
import com.datastax.driver.core.querybuilder.BuiltStatement; import com.datastax.driver.core.querybuilder.BuiltStatement;
@ -24,355 +28,231 @@ import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select; import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Select.Selection; import com.datastax.driver.core.querybuilder.Select.Selection;
import com.datastax.driver.core.querybuilder.Select.Where; import com.datastax.driver.core.querybuilder.Select.Where;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import net.helenus.core.*; import net.helenus.core.*;
import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet;
import net.helenus.core.cache.UnboundFacet;
import net.helenus.core.reflect.Entity;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.MappingUtil; import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.OrderingDirection; import net.helenus.mapping.OrderingDirection;
import net.helenus.mapping.value.ColumnValueProvider; import net.helenus.mapping.value.ColumnValueProvider;
import net.helenus.mapping.value.ValueProviderMap; import net.helenus.mapping.value.ValueProviderMap;
import net.helenus.support.Fun; import net.helenus.support.Fun;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, SelectOperation<E>> { public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, SelectOperation<E>> {
private static final Logger LOG = LoggerFactory.getLogger(SelectOperation.class); protected Function<Row, E> rowMapper = null;
protected final List<HelenusPropertyNode> props = new ArrayList<HelenusPropertyNode>();
protected final List<HelenusPropertyNode> props = new ArrayList<HelenusPropertyNode>(); protected List<Ordering> ordering = null;
protected Function<Row, E> rowMapper = null; protected Integer limit = null;
protected List<Ordering> ordering = null; protected boolean allowFiltering = false;
protected Integer limit = null;
protected boolean allowFiltering = false;
protected String alternateTableName = null; public SelectOperation(AbstractSessionOperations sessionOperations) {
protected boolean isCacheable = false; super(sessionOperations);
protected boolean implementsEntityType = false;
@SuppressWarnings("unchecked") this.rowMapper = new Function<Row, E>() {
public SelectOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations);
this.rowMapper = @Override
new Function<Row, E>() { public E apply(Row source) {
@Override ColumnValueProvider valueProvider = sessionOps.getValueProvider();
public E apply(Row source) { Object[] arr = new Object[props.size()];
ColumnValueProvider valueProvider = sessionOps.getValueProvider(); int i = 0;
Object[] arr = new Object[props.size()]; for (HelenusPropertyNode p : props) {
Object value = valueProvider.getColumnValue(source, -1, p.getProperty());
arr[i++] = value;
}
int i = 0; return (E) Fun.ArrayTuple.of(arr);
for (HelenusPropertyNode p : props) { }
Object value = valueProvider.getColumnValue(source, -1, p.getProperty());
arr[i++] = value;
}
return (E) Fun.ArrayTuple.of(arr); };
} }
};
}
public SelectOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) { public SelectOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
super(sessionOperations); super(sessionOperations);
entity entity.getOrderedProperties().stream().map(p -> new HelenusPropertyNode(p, Optional.empty()))
.getOrderedProperties() .forEach(p -> this.props.add(p));
.stream()
.map(p -> new HelenusPropertyNode(p, Optional.empty()))
.forEach(p -> this.props.add(p));
this.isCacheable = entity.isCacheable(); }
this.implementsEntityType = Entity.class.isAssignableFrom(entity.getMappingInterface());
}
public SelectOperation( public SelectOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity,
AbstractSessionOperations sessionOperations, Function<Row, E> rowMapper) {
HelenusEntity entity,
Function<Row, E> rowMapper) {
super(sessionOperations); super(sessionOperations);
this.rowMapper = rowMapper; this.rowMapper = rowMapper;
entity entity.getOrderedProperties().stream().map(p -> new HelenusPropertyNode(p, Optional.empty()))
.getOrderedProperties() .forEach(p -> this.props.add(p));
.stream()
.map(p -> new HelenusPropertyNode(p, Optional.empty()))
.forEach(p -> this.props.add(p));
this.isCacheable = entity.isCacheable(); }
this.implementsEntityType = Entity.class.isAssignableFrom(entity.getMappingInterface());
}
public SelectOperation( public SelectOperation(AbstractSessionOperations sessionOperations, Function<Row, E> rowMapper,
AbstractSessionOperations sessionOperations, HelenusPropertyNode... props) {
Function<Row, E> rowMapper,
HelenusPropertyNode... props) {
super(sessionOperations); super(sessionOperations);
this.rowMapper = rowMapper;
Collections.addAll(this.props, props);
}
this.rowMapper = rowMapper; public CountOperation count() {
Collections.addAll(this.props, props);
HelenusEntity entity = props[0].getEntity(); HelenusEntity entity = null;
this.isCacheable = entity.isCacheable(); for (HelenusPropertyNode prop : props) {
this.implementsEntityType = Entity.class.isAssignableFrom(entity.getMappingInterface());
}
public CountOperation count() { if (entity == null) {
entity = prop.getEntity();
} else if (entity != prop.getEntity()) {
throw new HelenusMappingException("you can count records only from a single entity "
+ entity.getMappingInterface() + " or " + prop.getEntity().getMappingInterface());
}
}
HelenusEntity entity = null; return new CountOperation(sessionOps, entity);
for (HelenusPropertyNode prop : props) { }
if (entity == null) { public SelectFirstOperation<E> single() {
entity = prop.getEntity(); limit(1);
} else if (entity != prop.getEntity()) { return new SelectFirstOperation<E>(this);
throw new HelenusMappingException( }
"you can count records only from a single entity "
+ entity.getMappingInterface()
+ " or "
+ prop.getEntity().getMappingInterface());
}
}
return new CountOperation(sessionOps, entity); public <R> SelectTransformingOperation<R, E> mapTo(Class<R> entityClass) {
}
public <V extends E> SelectOperation<E> from(Class<V> materializedViewClass) { Objects.requireNonNull(entityClass, "entityClass is null");
Objects.requireNonNull(materializedViewClass);
HelenusEntity entity = Helenus.entity(materializedViewClass);
this.alternateTableName = entity.getName().toCql();
this.props.clear();
entity
.getOrderedProperties()
.stream()
.map(p -> new HelenusPropertyNode(p, Optional.empty()))
.forEach(p -> this.props.add(p));
return this;
}
public SelectFirstOperation<E> single() { HelenusEntity entity = Helenus.entity(entityClass);
limit(1);
return new SelectFirstOperation<E>(this);
}
public <R> SelectTransformingOperation<R, E> mapTo(Class<R> entityClass) { this.rowMapper = null;
Objects.requireNonNull(entityClass, "entityClass is null"); return new SelectTransformingOperation<R, E>(this, (r) -> {
HelenusEntity entity = Helenus.entity(entityClass); Map<String, Object> map = new ValueProviderMap(r, sessionOps.getValueProvider(), entity);
return (R) Helenus.map(entityClass, map);
this.rowMapper = null; });
}
return new SelectTransformingOperation<R, E>( public <R> SelectTransformingOperation<R, E> map(Function<E, R> fn) {
this, return new SelectTransformingOperation<R, E>(this, fn);
(r) -> { }
Map<String, Object> map = new ValueProviderMap(r, sessionOps.getValueProvider(), entity);
return (R) Helenus.map(entityClass, map);
});
}
public <R> SelectTransformingOperation<R, E> map(Function<E, R> fn) { public SelectOperation<E> column(Getter<?> getter) {
return new SelectTransformingOperation<R, E>(this, fn); HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter);
} this.props.add(p);
return this;
}
public SelectOperation<E> column(Getter<?> getter) { public SelectOperation<E> orderBy(Getter<?> getter, OrderingDirection direction) {
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter); getOrCreateOrdering().add(new Ordered(getter, direction).getOrdering());
this.props.add(p); return this;
return this; }
}
public SelectOperation<E> orderBy(Getter<?> getter, OrderingDirection direction) { public SelectOperation<E> orderBy(Ordered ordered) {
getOrCreateOrdering().add(new Ordered(getter, direction).getOrdering()); getOrCreateOrdering().add(ordered.getOrdering());
return this; return this;
} }
public SelectOperation<E> orderBy(Ordered ordered) { public SelectOperation<E> limit(Integer limit) {
getOrCreateOrdering().add(ordered.getOrdering()); this.limit = limit;
return this; return this;
} }
public SelectOperation<E> limit(Integer limit) { public SelectOperation<E> allowFiltering() {
this.limit = limit; this.allowFiltering = true;
return this; return this;
} }
public SelectOperation<E> allowFiltering() { @Override
this.allowFiltering = true; public BuiltStatement buildStatement() {
return this;
}
@Override HelenusEntity entity = null;
public boolean isSessionCacheable() { Selection selection = QueryBuilder.select();
return isCacheable;
}
@Override for (HelenusPropertyNode prop : props) {
public List<Facet> getFacets() { selection = selection.column(prop.getColumnName());
HelenusEntity entity = props.get(0).getEntity();
return entity.getFacets();
}
@Override if (prop.getProperty().caseSensitiveIndex()) {
public List<Facet> bindFacetValues() { allowFiltering = true;
HelenusEntity entity = props.get(0).getEntity(); }
List<Facet> boundFacets = new ArrayList<>();
for (Facet facet : entity.getFacets()) { if (entity == null) {
if (facet instanceof UnboundFacet) { entity = prop.getEntity();
UnboundFacet unboundFacet = (UnboundFacet) facet; } else if (entity != prop.getEntity()) {
UnboundFacet.Binder binder = unboundFacet.binder(); throw new HelenusMappingException("you can select columns only from a single entity "
for (HelenusProperty prop : unboundFacet.getProperties()) { + entity.getMappingInterface() + " or " + prop.getEntity().getMappingInterface());
if (filters != null) { }
Filter filter = filters.get(prop); }
if (filter != null) {
Object[] postulates = filter.postulateValues(); if (entity == null) {
for (Object p : postulates) { throw new HelenusMappingException("no entity or table to select data");
binder.setValueForProperty(prop, p.toString()); }
}
} Select select = selection.from(entity.getName().toCql());
}
if (ordering != null && !ordering.isEmpty()) {
select.orderBy(ordering.toArray(new Ordering[ordering.size()]));
}
if (limit != null) {
select.limit(limit);
}
if (filters != null && !filters.isEmpty()) {
Where where = select.where();
for (Filter<?> filter : filters) {
where.and(filter.getClause(sessionOps.getValuePreparer()));
}
}
if (ifFilters != null && !ifFilters.isEmpty()) {
logger.error("onlyIf conditions " + ifFilters + " would be ignored in the statement " + select);
}
if (allowFiltering) {
select.allowFiltering();
}
return select;
}
@Override
public Optional<E> sync() {
if (true) {
} else {
return super.sync();
} }
if (binder.isBound()) { }
boundFacets.add(binder.bind());
}
} else {
boundFacets.add(facet);
}
}
return boundFacets;
}
@Override @SuppressWarnings("unchecked")
public BuiltStatement buildStatement(boolean cached) { @Override
public Stream<E> transform(ResultSet resultSet) {
HelenusEntity entity = null; if (rowMapper != null) {
Selection selection = QueryBuilder.select();
for (HelenusPropertyNode prop : props) { return StreamSupport
String columnName = prop.getColumnName(); .stream(Spliterators.spliteratorUnknownSize(resultSet.iterator(), Spliterator.ORDERED), false)
selection = selection.column(columnName); .map(rowMapper);
}
if (entity == null) { else {
entity = prop.getEntity();
} else if (entity != prop.getEntity()) {
throw new HelenusMappingException(
"you can select columns only from a single entity "
+ entity.getMappingInterface()
+ " or "
+ prop.getEntity().getMappingInterface());
}
if (cached && implementsEntityType) { return (Stream<E>) StreamSupport
switch (prop.getProperty().getColumnType()) { .stream(Spliterators.spliteratorUnknownSize(resultSet.iterator(), Spliterator.ORDERED), false);
case PARTITION_KEY:
case CLUSTERING_COLUMN:
break;
default:
if (entity.equals(prop.getEntity())) {
if (!prop.getProperty().getDataType().isCollectionType()) {
columnName = prop.getProperty().getColumnName().toCql(false);
selection.ttl(columnName).as('"' + CacheUtil.ttlKey(columnName) + '"');
selection.writeTime(columnName).as('"' + CacheUtil.writeTimeKey(columnName) + '"');
}
}
break;
}
}
}
if (entity == null) { }
throw new HelenusMappingException("no entity or table to select data"); }
}
String tableName = alternateTableName == null ? entity.getName().toCql() : alternateTableName; private List<Ordering> getOrCreateOrdering() {
Select select = selection.from(tableName); if (ordering == null) {
ordering = new ArrayList<Ordering>();
}
return ordering;
}
if (ordering != null && !ordering.isEmpty()) {
select.orderBy(ordering.toArray(new Ordering[ordering.size()]));
}
if (limit != null) {
select.limit(limit);
}
if (filters != null && !filters.isEmpty()) {
Where where = select.where();
boolean isFirstIndex = true;
for (Filter<?> filter : filters.values()) {
where.and(filter.getClause(sessionOps.getValuePreparer()));
HelenusProperty filterProp = filter.getNode().getProperty();
HelenusProperty prop =
props
.stream()
.map(HelenusPropertyNode::getProperty)
.filter(thisProp -> thisProp.getPropertyName().equals(filterProp.getPropertyName()))
.findFirst()
.orElse(null);
if (allowFiltering == false && prop != null) {
switch (prop.getColumnType()) {
case PARTITION_KEY:
break;
case CLUSTERING_COLUMN:
default:
// When using non-Cassandra-standard 2i types or when using more than one
// indexed column or non-indexed columns the query must include ALLOW FILTERING.
if (prop.caseSensitiveIndex() == false) {
allowFiltering = true;
} else if (prop.getIndexName() != null) {
allowFiltering |= !isFirstIndex;
isFirstIndex = false;
} else {
allowFiltering = true;
}
}
}
}
}
if (ifFilters != null && !ifFilters.isEmpty()) {
LOG.error("onlyIf conditions " + ifFilters + " would be ignored in the statement " + select);
}
if (allowFiltering) {
select.allowFiltering();
}
return select;
}
@SuppressWarnings("unchecked")
@Override
public Stream<E> transform(ResultSet resultSet) {
if (rowMapper != null) {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(resultSet.iterator(), Spliterator.ORDERED), false)
.map(rowMapper);
} else {
return (Stream<E>)
StreamSupport.stream(
Spliterators.spliteratorUnknownSize(resultSet.iterator(), Spliterator.ORDERED),
false);
}
}
private List<Ordering> getOrCreateOrdering() {
if (ordering == null) {
ordering = new ArrayList<Ordering>();
}
return ordering;
}
} }

View file

@ -1,70 +1,50 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors *
* * Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. * You may obtain a copy of the License at
* You may obtain a copy of the License at *
* * http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0 *
* * Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and * limitations under the License.
* limitations under the License. */
*/ package net.helenus.core.operation;
package net.helenus.core.operation;
import java.util.function.Function;
import com.datastax.driver.core.ResultSet; import java.util.stream.Stream;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.List; import com.datastax.driver.core.ResultSet;
import java.util.function.Function; import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.stream.Stream;
import net.helenus.core.cache.Facet; public final class SelectTransformingOperation<R, E>
extends
public final class SelectTransformingOperation<R, E> AbstractFilterStreamOperation<R, SelectTransformingOperation<R, E>> {
extends AbstractFilterStreamOperation<R, SelectTransformingOperation<R, E>> {
private final SelectOperation<E> src;
private final SelectOperation<E> delegate; private final Function<E, R> fn;
private final Function<E, R> fn;
public SelectTransformingOperation(SelectOperation<E> src, Function<E, R> fn) {
public SelectTransformingOperation(SelectOperation<E> delegate, Function<E, R> fn) { super(src.sessionOps);
super(delegate.sessionOps);
this.src = src;
this.delegate = delegate; this.fn = fn;
this.fn = fn; this.filters = src.filters;
this.filters = delegate.filters; this.ifFilters = src.ifFilters;
this.ifFilters = delegate.ifFilters; }
}
@Override
@Override public BuiltStatement buildStatement() {
public List<Facet> bindFacetValues() { return src.buildStatement();
return delegate.bindFacetValues(); }
}
@Override
@Override public Stream<R> transform(ResultSet resultSet) {
public List<Facet> getFacets() { return src.transform(resultSet).map(fn);
return delegate.getFacets(); }
}
}
@Override
public BuiltStatement buildStatement(boolean cached) {
return delegate.buildStatement(cached);
}
@Override
public Stream<R> transform(ResultSet resultSet) {
return delegate.transform(resultSet).map(fn);
}
@Override
public boolean isSessionCacheable() {
return delegate.isSessionCacheable();
}
@Override
public boolean ignoreCache() {
return delegate.ignoreCache();
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,41 +19,36 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public enum DefaultPrimitiveTypes { public enum DefaultPrimitiveTypes {
BOOLEAN(boolean.class, false),
BYTE(byte.class, (byte) 0x0),
CHAR(char.class, (char) 0x0),
SHORT(short.class, (short) 0),
INT(int.class, 0),
LONG(long.class, 0L),
FLOAT(float.class, 0.0f),
DOUBLE(double.class, 0.0);
private static final Map<Class<?>, DefaultPrimitiveTypes> map = BOOLEAN(boolean.class, false), BYTE(byte.class, (byte) 0x0), CHAR(char.class, (char) 0x0), SHORT(short.class,
new HashMap<Class<?>, DefaultPrimitiveTypes>(); (short) 0), INT(int.class, 0), LONG(long.class, 0L), FLOAT(float.class, 0.0f), DOUBLE(double.class, 0.0);
static { private final Class<?> primitiveClass;
for (DefaultPrimitiveTypes type : DefaultPrimitiveTypes.values()) { private final Object defaultValue;
map.put(type.getPrimitiveClass(), type);
}
}
private final Class<?> primitiveClass; private final static Map<Class<?>, DefaultPrimitiveTypes> map = new HashMap<Class<?>, DefaultPrimitiveTypes>();
private final Object defaultValue;
private DefaultPrimitiveTypes(Class<?> primitiveClass, Object defaultValue) { static {
this.primitiveClass = primitiveClass; for (DefaultPrimitiveTypes type : DefaultPrimitiveTypes.values()) {
this.defaultValue = defaultValue; map.put(type.getPrimitiveClass(), type);
} }
}
public static DefaultPrimitiveTypes lookup(Class<?> primitiveClass) { private DefaultPrimitiveTypes(Class<?> primitiveClass, Object defaultValue) {
return map.get(primitiveClass); this.primitiveClass = primitiveClass;
} this.defaultValue = defaultValue;
}
public Class<?> getPrimitiveClass() { public static DefaultPrimitiveTypes lookup(Class<?> primitiveClass) {
return primitiveClass; return map.get(primitiveClass);
} }
public Class<?> getPrimitiveClass() {
return primitiveClass;
}
public Object getDefaultValue() {
return defaultValue;
}
public Object getDefaultValue() {
return defaultValue;
}
} }

View file

@ -1,28 +0,0 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core.reflect;
import java.util.Set;
public interface Drafted<T> extends MapExportable {
Set<String> mutated();
T build();
Set<String> read();
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,18 +15,15 @@
*/ */
package net.helenus.core.reflect; package net.helenus.core.reflect;
import com.datastax.driver.core.Metadata;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
public interface DslExportable { public interface DslExportable {
String GET_ENTITY_METHOD = "getHelenusMappingEntity"; public static final String GET_ENTITY_METHOD = "getHelenusMappingEntity";
String GET_PARENT_METHOD = "getParentDslHelenusPropertyNode"; public static final String GET_PARENT_METHOD = "getParentDslHelenusPropertyNode";
String SET_METADATA_METHOD = "setCassandraMetadataForHelenusSession";
HelenusEntity getHelenusMappingEntity(); HelenusEntity getHelenusMappingEntity();
HelenusPropertyNode getParentDslHelenusPropertyNode(); HelenusPropertyNode getParentDslHelenusPropertyNode();
void setCassandraMetadataForHelenusSession(Metadata metadata);
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,14 +15,18 @@
*/ */
package net.helenus.core.reflect; package net.helenus.core.reflect;
import com.datastax.driver.core.*; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import com.datastax.driver.core.*;
import net.helenus.core.Helenus; import net.helenus.core.Helenus;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusMappingEntity; import net.helenus.mapping.HelenusMappingEntity;
@ -36,178 +39,144 @@ import net.helenus.support.HelenusException;
public class DslInvocationHandler<E> implements InvocationHandler { public class DslInvocationHandler<E> implements InvocationHandler {
private final Class<E> iface; private final HelenusEntity entity;
private final ClassLoader classLoader; private final Optional<HelenusPropertyNode> parent;
private final Optional<HelenusPropertyNode> parent;
private final Map<Method, HelenusProperty> map = new HashMap<Method, HelenusProperty>();
private final Map<Method, Object> udtMap = new HashMap<Method, Object>();
private final Map<Method, Object> tupleMap = new HashMap<Method, Object>();
private HelenusEntity entity = null;
private Metadata metadata = null;
public DslInvocationHandler( private final Map<Method, HelenusProperty> map = new HashMap<Method, HelenusProperty>();
Class<E> iface,
ClassLoader classLoader,
Optional<HelenusPropertyNode> parent,
Metadata metadata) {
this.metadata = metadata; private final Map<Method, Object> udtMap = new HashMap<Method, Object>();
this.parent = parent; private final Map<Method, Object> tupleMap = new HashMap<Method, Object>();
this.iface = iface;
this.classLoader = classLoader;
}
public void setCassandraMetadataForHelenusSession(Metadata metadata) { public DslInvocationHandler(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent, Metadata metadata) {
if (metadata != null) {
this.metadata = metadata;
entity = init(metadata);
}
}
private HelenusEntity init(Metadata metadata) { this.entity = new HelenusMappingEntity(iface, metadata);
HelenusEntity entity = new HelenusMappingEntity(iface, metadata); this.parent = parent;
Collection<HelenusProperty> properties = entity.getOrderedProperties();
if (properties != null) {
for (HelenusProperty prop : properties) {
map.put(prop.getGetterMethod(), prop); if (this.entity != null) {
for (HelenusProperty prop : entity.getOrderedProperties()) {
AbstractDataType type = prop.getDataType(); map.put(prop.getGetterMethod(), prop);
Class<?> javaType = prop.getJavaType();
if (type instanceof UDTDataType && !UDTValue.class.isAssignableFrom(javaType)) { AbstractDataType type = prop.getDataType();
Class<?> javaType = prop.getJavaType();
Object childDsl = if (type instanceof UDTDataType && !UDTValue.class.isAssignableFrom(javaType)) {
Helenus.dsl(
javaType,
classLoader,
Optional.of(new HelenusPropertyNode(prop, parent)),
metadata);
udtMap.put(prop.getGetterMethod(), childDsl); Object childDsl = Helenus.dsl(javaType, classLoader,
} Optional.of(new HelenusPropertyNode(prop, parent)), metadata);
if (type instanceof DTDataType) { udtMap.put(prop.getGetterMethod(), childDsl);
DTDataType dataType = (DTDataType) type; }
if (dataType.getDataType() instanceof TupleType if (type instanceof DTDataType) {
&& !TupleValue.class.isAssignableFrom(javaType)) { DTDataType dataType = (DTDataType) type;
Object childDsl = if (dataType.getDataType() instanceof TupleType && !TupleValue.class.isAssignableFrom(javaType)) {
Helenus.dsl(
javaType,
classLoader,
Optional.of(new HelenusPropertyNode(prop, parent)),
metadata);
tupleMap.put(prop.getGetterMethod(), childDsl); Object childDsl = Helenus.dsl(javaType, classLoader,
} Optional.of(new HelenusPropertyNode(prop, parent)), metadata);
}
}
}
return entity; tupleMap.put(prop.getGetterMethod(), childDsl);
}
@Override }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { }
HelenusEntity entity = this.entity;
String methodName = method.getName();
if ("equals".equals(methodName) && method.getParameterCount() == 1) {
Object otherObj = args[0];
if (otherObj == null) {
return false;
}
if (Proxy.isProxyClass(otherObj.getClass())) {
return this == Proxy.getInvocationHandler(otherObj);
}
return false;
}
if (DslExportable.SET_METADATA_METHOD.equals(methodName)
&& args.length == 1
&& args[0] instanceof Metadata) {
if (metadata == null) {
this.setCassandraMetadataForHelenusSession((Metadata) args[0]);
}
return null;
}
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new HelenusException("invalid getter method " + method);
}
if ("hashCode".equals(methodName)) {
return hashCode();
}
if (DslExportable.GET_PARENT_METHOD.equals(methodName)) {
return parent.get();
}
if (entity == null) {
entity = init(metadata);
}
if ("toString".equals(methodName)) {
return entity.toString();
}
if (DslExportable.GET_ENTITY_METHOD.equals(methodName)) {
return entity;
}
HelenusProperty prop = map.get(method);
if (prop == null) {
prop = entity.getProperty(methodName);
}
if (prop != null) {
AbstractDataType type = prop.getDataType();
if (type instanceof UDTDataType) {
Object childDsl = udtMap.get(method);
if (childDsl != null) {
return childDsl;
}
}
if (type instanceof DTDataType) {
DTDataType dataType = (DTDataType) type;
DataType dt = dataType.getDataType();
switch (dt.getName()) {
case TUPLE:
Object childDsl = tupleMap.get(method);
if (childDsl != null) {
return childDsl;
} }
break;
case SET:
return new SetDsl(new HelenusPropertyNode(prop, parent));
case LIST:
return new ListDsl(new HelenusPropertyNode(prop, parent));
case MAP:
return new MapDsl(new HelenusPropertyNode(prop, parent));
default:
break;
} }
} }
throw new DslPropertyException(new HelenusPropertyNode(prop, parent)); @Override
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if ("equals".equals(methodName) && method.getParameterCount() == 1) {
Object otherObj = args[0];
if (otherObj == null) {
return false;
}
if (Proxy.isProxyClass(otherObj.getClass())) {
return this == Proxy.getInvocationHandler(otherObj);
}
return false;
}
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new HelenusException("invalid getter method " + method);
}
if ("hashCode".equals(methodName)) {
return hashCode();
}
if ("toString".equals(methodName)) {
return entity.toString();
}
if (DslExportable.GET_ENTITY_METHOD.equals(methodName)) {
return entity;
}
if (DslExportable.GET_PARENT_METHOD.equals(methodName)) {
return parent.get();
}
HelenusProperty prop = map.get(method);
if (prop == null) {
prop = entity.getProperty(methodName);
}
if (prop != null) {
AbstractDataType type = prop.getDataType();
if (type instanceof UDTDataType) {
Object childDsl = udtMap.get(method);
if (childDsl != null) {
return childDsl;
}
}
if (type instanceof DTDataType) {
DTDataType dataType = (DTDataType) type;
DataType dt = dataType.getDataType();
switch (dt.getName()) {
case TUPLE :
Object childDsl = tupleMap.get(method);
if (childDsl != null) {
return childDsl;
}
break;
case SET :
return new SetDsl(new HelenusPropertyNode(prop, parent));
case LIST :
return new ListDsl(new HelenusPropertyNode(prop, parent));
case MAP :
return new MapDsl(new HelenusPropertyNode(prop, parent));
default :
break;
}
}
throw new DslPropertyException(new HelenusPropertyNode(prop, parent));
}
throw new HelenusException("invalid method call " + method);
}
throw new HelenusException("invalid method call " + method);
}
} }

View file

@ -1,73 +0,0 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
*
* 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.
*/
package net.helenus.core.reflect;
import net.helenus.core.Getter;
public interface Entity {
String WRITTEN_AT_METHOD = "writtenAt";
String TTL_OF_METHOD = "ttlOf";
String TOKEN_OF_METHOD = "tokenOf";
/**
* The write time for the property in question referenced by the getter.
*
* @param getter the property getter
* @return the timestamp associated with the property identified by the getter
*/
default Long writtenAt(Getter getter) {
return 0L;
}
/**
* The write time for the property in question referenced by the property name.
*
* @param prop the name of a property in this entity
* @return the timestamp associated with the property identified by the property name if it exists
*/
default Long writtenAt(String prop) {
return 0L;
};
/**
* The time-to-live for the property in question referenced by the getter.
*
* @param getter the property getter
* @return the time-to-live in seconds associated with the property identified by the getter
*/
default Integer ttlOf(Getter getter) {
return 0;
};
/**
* The time-to-live for the property in question referenced by the property name.
*
* @param prop the name of a property in this entity
* @return the time-to-live in seconds associated with the property identified by the property name if it exists
*/
default Integer ttlOf(String prop) {
return 0;
};
/**
* The token (partition identifier) for this entity which can change over time if
* the cluster grows or shrinks but should be stable otherwise.
*
* @return the token for the entity
*/
default Long tokenOf() { return 0L; }
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,7 +19,9 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidator;
import net.helenus.core.SessionRepository; import net.helenus.core.SessionRepository;
import net.helenus.mapping.*; import net.helenus.mapping.*;
import net.helenus.mapping.type.AbstractDataType; import net.helenus.mapping.type.AbstractDataType;
@ -28,84 +29,77 @@ import net.helenus.support.HelenusMappingException;
public final class HelenusNamedProperty implements HelenusProperty { public final class HelenusNamedProperty implements HelenusProperty {
private final String name; private final String name;
public HelenusNamedProperty(String name) { public HelenusNamedProperty(String name) {
this.name = name; this.name = name;
} }
@Override @Override
public HelenusEntity getEntity() { public HelenusEntity getEntity() {
throw new HelenusMappingException("will never called"); throw new HelenusMappingException("will never called");
} }
@Override @Override
public String getPropertyName() { public String getPropertyName() {
return name; return name;
} }
@Override @Override
public Method getGetterMethod() { public Method getGetterMethod() {
throw new HelenusMappingException("will never called"); throw new HelenusMappingException("will never called");
} }
@Override @Override
public IdentityName getColumnName() { public IdentityName getColumnName() {
return IdentityName.of(name, false); return IdentityName.of(name, false);
} }
@Override @Override
public Optional<IdentityName> getIndexName() { public Optional<IdentityName> getIndexName() {
return Optional.empty(); return Optional.empty();
} }
@Override @Override
public boolean caseSensitiveIndex() { public boolean caseSensitiveIndex() { return false; }
return false;
}
@Override @Override
public boolean isIdempotent() { public Class<?> getJavaType() {
return false; throw new HelenusMappingException("will never called");
} }
@Override @Override
public Class<?> getJavaType() { public AbstractDataType getDataType() {
throw new HelenusMappingException("will never called"); throw new HelenusMappingException("will never called");
} }
@Override @Override
public AbstractDataType getDataType() { public ColumnType getColumnType() {
throw new HelenusMappingException("will never called"); return ColumnType.COLUMN;
} }
@Override @Override
public ColumnType getColumnType() { public int getOrdinal() {
return ColumnType.COLUMN; return 0;
} }
@Override @Override
public int getOrdinal() { public OrderingDirection getOrdering() {
return 0; return OrderingDirection.ASC;
} }
@Override @Override
public OrderingDirection getOrdering() { public Optional<Function<Object, Object>> getReadConverter(SessionRepository repository) {
return OrderingDirection.ASC; return Optional.empty();
} }
@Override @Override
public Optional<Function<Object, Object>> getReadConverter(SessionRepository repository) { public Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository) {
return Optional.empty(); return Optional.empty();
} }
@Override @Override
public Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository) { public ConstraintValidator<? extends Annotation, ?>[] getValidators() {
return Optional.empty(); return MappingUtil.EMPTY_VALIDATORS;
} }
@Override
public ConstraintValidator<? extends Annotation, ?>[] getValidators() {
return MappingUtil.EMPTY_VALIDATORS;
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,89 +17,92 @@ package net.helenus.core.reflect;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
public final class HelenusPropertyNode implements Iterable<HelenusProperty> { public final class HelenusPropertyNode implements Iterable<HelenusProperty> {
private final HelenusProperty prop; private final HelenusProperty prop;
private final Optional<HelenusPropertyNode> next; private final Optional<HelenusPropertyNode> next;
public HelenusPropertyNode(HelenusProperty prop, Optional<HelenusPropertyNode> next) { public HelenusPropertyNode(HelenusProperty prop, Optional<HelenusPropertyNode> next) {
this.prop = prop; this.prop = prop;
this.next = next; this.next = next;
} }
public String getColumnName() { public String getColumnName() {
if (next.isPresent()) { if (next.isPresent()) {
List<String> columnNames = new ArrayList<String>(); List<String> columnNames = new ArrayList<String>();
for (HelenusProperty p : this) { for (HelenusProperty p : this) {
columnNames.add(p.getColumnName().toCql(true)); columnNames.add(p.getColumnName().toCql(true));
} }
Collections.reverse(columnNames); Collections.reverse(columnNames);
if (prop instanceof HelenusNamedProperty) { if (prop instanceof HelenusNamedProperty) {
int size = columnNames.size(); int size = columnNames.size();
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
for (int i = 0; i != size - 1; ++i) { for (int i = 0; i != size - 1; ++i) {
if (str.length() != 0) { if (str.length() != 0) {
str.append("."); str.append(".");
} }
str.append(columnNames.get(i)); str.append(columnNames.get(i));
} }
str.append("[").append(columnNames.get(size - 1)).append("]"); str.append("[").append(columnNames.get(size - 1)).append("]");
return str.toString(); return str.toString();
} else { } else {
return columnNames.stream().collect(Collectors.joining(".")); return columnNames.stream().collect(Collectors.joining("."));
} }
} else { } else {
return prop.getColumnName().toCql(); return prop.getColumnName().toCql();
} }
} }
public HelenusEntity getEntity() { public HelenusEntity getEntity() {
if (next.isPresent()) { if (next.isPresent()) {
HelenusProperty last = prop; HelenusProperty last = prop;
for (HelenusProperty p : this) { for (HelenusProperty p : this) {
last = p; last = p;
} }
return last.getEntity(); return last.getEntity();
} else { } else {
return prop.getEntity(); return prop.getEntity();
} }
} }
public HelenusProperty getProperty() { public HelenusProperty getProperty() {
return prop; return prop;
} }
public Optional<HelenusPropertyNode> getNext() { public Optional<HelenusPropertyNode> getNext() {
return next; return next;
} }
public Iterator<HelenusProperty> iterator() { public Iterator<HelenusProperty> iterator() {
return new PropertyNodeIterator(Optional.of(this)); return new PropertyNodeIterator(Optional.of(this));
} }
private static class PropertyNodeIterator implements Iterator<HelenusProperty> { private static class PropertyNodeIterator implements Iterator<HelenusProperty> {
private Optional<HelenusPropertyNode> next; private Optional<HelenusPropertyNode> next;
public PropertyNodeIterator(Optional<HelenusPropertyNode> next) { public PropertyNodeIterator(Optional<HelenusPropertyNode> next) {
this.next = next; this.next = next;
} }
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return next.isPresent(); return next.isPresent();
} }
@Override
public HelenusProperty next() {
HelenusPropertyNode node = next.get();
next = node.next;
return node.prop;
}
}
@Override
public HelenusProperty next() {
HelenusPropertyNode node = next.get();
next = node.next;
return node.prop;
}
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,164 +16,165 @@
package net.helenus.core.reflect; package net.helenus.core.reflect;
import java.util.*; import java.util.*;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
import net.helenus.support.DslPropertyException; import net.helenus.support.DslPropertyException;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public final class ListDsl<V> implements List<V> { public final class ListDsl<V> implements List<V> {
private final HelenusPropertyNode parent; private final HelenusPropertyNode parent;
public ListDsl(HelenusPropertyNode parent) { public ListDsl(HelenusPropertyNode parent) {
this.parent = parent; this.parent = parent;
} }
public HelenusPropertyNode getParent() { public HelenusPropertyNode getParent() {
return parent; return parent;
} }
@Override @Override
public V get(int index) { public V get(int index) {
HelenusProperty prop = new HelenusNamedProperty(Integer.toString(index)); HelenusProperty prop = new HelenusNamedProperty(Integer.toString(index));
throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent))); throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent)));
} }
@Override @Override
public int size() { public int size() {
throwShouldNeverCall(); throwShouldNeverCall();
return 0; return 0;
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean contains(Object o) { public boolean contains(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public Iterator<V> iterator() { public Iterator<V> iterator() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public Object[] toArray() { public Object[] toArray() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public <T> T[] toArray(T[] a) { public <T> T[] toArray(T[] a) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public boolean add(V e) { public boolean add(V e) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean containsAll(Collection<?> c) { public boolean containsAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean addAll(Collection<? extends V> c) { public boolean addAll(Collection<? extends V> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean addAll(int index, Collection<? extends V> c) { public boolean addAll(int index, Collection<? extends V> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean removeAll(Collection<?> c) { public boolean removeAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean retainAll(Collection<?> c) { public boolean retainAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public void clear() { public void clear() {
throwShouldNeverCall(); throwShouldNeverCall();
} }
@Override @Override
public V set(int index, V element) { public V set(int index, V element) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public void add(int index, V element) { public void add(int index, V element) {
throwShouldNeverCall(); throwShouldNeverCall();
} }
@Override @Override
public V remove(int index) { public V remove(int index) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public int indexOf(Object o) { public int indexOf(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return 0; return 0;
} }
@Override @Override
public int lastIndexOf(Object o) { public int lastIndexOf(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return 0; return 0;
} }
@Override @Override
public ListIterator<V> listIterator() { public ListIterator<V> listIterator() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public ListIterator<V> listIterator(int index) { public ListIterator<V> listIterator(int index) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public List<V> subList(int fromIndex, int toIndex) { public List<V> subList(int fromIndex, int toIndex) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
private void throwShouldNeverCall() { private void throwShouldNeverCall() {
throw new HelenusMappingException("should be never called"); throw new HelenusMappingException("should be never called");
} }
@Override @Override
public String toString() { public String toString() {
return "ListDsl"; return "ListDsl";
} }
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,98 +19,100 @@ import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
import net.helenus.support.DslPropertyException; import net.helenus.support.DslPropertyException;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public final class MapDsl<K, V> implements Map<K, V> { public final class MapDsl<K, V> implements Map<K, V> {
private final HelenusPropertyNode parent; private final HelenusPropertyNode parent;
public MapDsl(HelenusPropertyNode parent) { public MapDsl(HelenusPropertyNode parent) {
this.parent = parent; this.parent = parent;
} }
public HelenusPropertyNode getParent() { public HelenusPropertyNode getParent() {
return parent; return parent;
} }
@Override @Override
public V get(Object key) { public V get(Object key) {
HelenusProperty prop = new HelenusNamedProperty(key.toString()); HelenusProperty prop = new HelenusNamedProperty(key.toString());
throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent))); throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent)));
} }
@Override @Override
public int size() { public int size() {
throwShouldNeverCall(); throwShouldNeverCall();
return 0; return 0;
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean containsKey(Object key) { public boolean containsKey(Object key) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean containsValue(Object value) { public boolean containsValue(Object value) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public V put(K key, V value) { public V put(K key, V value) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public V remove(Object key) { public V remove(Object key) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public void putAll(Map<? extends K, ? extends V> m) { public void putAll(Map<? extends K, ? extends V> m) {
throwShouldNeverCall(); throwShouldNeverCall();
} }
@Override @Override
public void clear() { public void clear() {
throwShouldNeverCall(); throwShouldNeverCall();
} }
@Override @Override
public Set<K> keySet() { public Set<K> keySet() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public Collection<V> values() { public Collection<V> values() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public Set<java.util.Map.Entry<K, V>> entrySet() { public Set<java.util.Map.Entry<K, V>> entrySet() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
private void throwShouldNeverCall() { private void throwShouldNeverCall() {
throw new HelenusMappingException("should be never called"); throw new HelenusMappingException("should be never called");
} }
@Override
public String toString() {
return "MapDsl";
}
@Override
public String toString() {
return "MapDsl";
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,25 +16,11 @@
package net.helenus.core.reflect; package net.helenus.core.reflect;
import java.util.Map; import java.util.Map;
import java.util.Set;
import net.helenus.core.Getter;
public interface MapExportable { public interface MapExportable {
String TO_MAP_METHOD = "toMap";
String TO_READ_SET_METHOD = "toReadSet";
String PUT_METHOD = "put";
Map<String, Object> toMap(); public static final String TO_MAP_METHOD = "toMap";
default Map<String, Object> toMap(boolean mutable) { Map<String, Object> toMap();
return null;
}
default Set<String> toReadSet() {
return null;
}
default void put(String key, Object value) {}
default <T> void put(Getter<T> getter, T value) {}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,279 +15,97 @@
*/ */
package net.helenus.core.reflect; package net.helenus.core.reflect;
import com.google.common.collect.ImmutableList; import java.lang.invoke.MethodHandle;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.*; import java.util.Collections;
import net.helenus.core.Getter; import java.util.Map;
import net.helenus.core.Helenus;
import net.helenus.core.cache.CacheUtil;
import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.annotation.Transient;
import net.helenus.mapping.value.ValueProviderMap;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
public class MapperInvocationHandler<E> implements InvocationHandler, Serializable { public class MapperInvocationHandler<E> implements InvocationHandler {
private static final long serialVersionUID = -7044209982830584984L;
private Map<String, Object> src; private final Map<String, Object> src;
private final Set<String> read = new HashSet<String>(); private final Class<E> iface;
private final Class<E> iface;
public MapperInvocationHandler(Class<E> iface, Map<String, Object> src) { public MapperInvocationHandler(Class<E> iface, Map<String, Object> src) {
this.src = src; this.src = src;
this.iface = iface; this.iface = iface;
} }
private Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable { @Override
// NOTE: This is reflection magic to invoke (non-recursively) a default method public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// implemented on an interface
// that we've proxied (in ReflectionDslInstantiator). I found the answer in this
// article.
// https://zeroturnaround.com/rebellabs/recognize-and-conquer-java-proxies-default-methods-and-method-handles/
// First, we need an instance of a private inner-class found in MethodHandles. if (method.isDefault()) {
Constructor<MethodHandles.Lookup> constructor = // NOTE: This is reflection magic to invoke (non-recursively) a default method implemented on an interface
MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class); // that we've proxied (in ReflectionDslInstantiator). I found the answer in this article.
constructor.setAccessible(true); // https://zeroturnaround.com/rebellabs/recognize-and-conquer-java-proxies-default-methods-and-method-handles/
// Now we need to lookup and invoke special the default method on the interface // First, we need an instance of a private inner-class found in MethodHandles.
// class. Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
final Class<?> declaringClass = method.getDeclaringClass(); constructor.setAccessible(true);
Object result =
constructor
.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
.unreflectSpecial(method, declaringClass)
.bindTo(proxy)
.invokeWithArguments(args);
return result;
}
private Object writeReplace() { // Now we need to lookup and invoke special the default method on the interface class.
return new SerializationProxy<E>(this); final Class<?> declaringClass = method.getDeclaringClass();
} Object result = constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
.unreflectSpecial(method, declaringClass)
private void readObject(ObjectInputStream stream) throws InvalidObjectException { .bindTo(proxy)
throw new InvalidObjectException("Proxy required."); .invokeWithArguments(args);
} return result;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Transient, default methods should simply be invoked as-is.
if (method.isDefault() && method.getDeclaredAnnotation(Transient.class) != null) {
return invokeDefault(proxy, method, args);
}
String methodName = method.getName();
if ("equals".equals(methodName) && method.getParameterCount() == 1) {
Object otherObj = args[0];
if (otherObj == null) {
return false;
}
if (Proxy.isProxyClass(otherObj.getClass())) {
if (this == Proxy.getInvocationHandler(otherObj)) {
return true;
} }
}
if (otherObj instanceof MapExportable) {
return MappingUtil.compareMaps((MapExportable) otherObj, src);
}
return false;
}
if (MapExportable.PUT_METHOD.equals(methodName) && method.getParameterCount() == 2) { String methodName = method.getName();
final String key;
if (args[0] instanceof String) {
key = (String) args[0];
} else if (args[0] instanceof Getter) {
key = MappingUtil.resolveMappingProperty((Getter) args[0]).getProperty().getPropertyName();
} else {
key = null;
}
if (key != null) {
final Object value = (Object) args[1];
if (src instanceof ValueProviderMap) {
this.src = fromValueProviderMap(src);
}
src.put(key, value);
}
return null;
}
if (Entity.WRITTEN_AT_METHOD.equals(methodName) && method.getParameterCount() == 1) { if ("equals".equals(methodName) && method.getParameterCount() == 1) {
final String key; Object otherObj = args[0];
if (args[0] instanceof String) { if (otherObj == null) {
key = CacheUtil.writeTimeKey((String) args[0]); return false;
} else if (args[0] instanceof Getter) { }
Getter getter = (Getter) args[0]; if (Proxy.isProxyClass(otherObj.getClass())) {
key = return this == Proxy.getInvocationHandler(otherObj);
CacheUtil.writeTimeKey( }
MappingUtil.resolveMappingProperty(getter) return false;
.getProperty() }
.getColumnName()
.toCql(false));
} else {
return 0L;
}
Long v = (Long) src.get(key);
if (v != null) {
return v;
}
return 0L;
}
if (Entity.TOKEN_OF_METHOD.equals(methodName) && method.getParameterCount() == 0) { if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
Long v = (Long) src.get(""); throw new HelenusException("invalid getter method " + method);
if (v != null) { }
return v;
}
return 0L;
}
if (Entity.TTL_OF_METHOD.equals(methodName) && method.getParameterCount() == 1) { if ("hashCode".equals(methodName)) {
final String key; return hashCode();
if (args[0] instanceof String) { }
key = CacheUtil.ttlKey((String) args[0]);
} else if (args[0] instanceof Getter) {
Getter getter = (Getter) args[0];
key =
CacheUtil.ttlKey(
MappingUtil.resolveMappingProperty(getter)
.getProperty()
.getColumnName()
.toCql(false));
} else {
return 0;
}
int v[] = (int[]) src.get(key);
if (v != null) {
return v[0];
}
return 0;
}
if (MapExportable.TO_MAP_METHOD.equals(methodName)) { if ("toString".equals(methodName)) {
if (method.getParameterCount() == 1 && args[0] instanceof Boolean) { return iface.getSimpleName() + ": " + src.toString();
if ((boolean) args[0] == true) { }
return fromValueProviderMap(src, true);
}
}
return Collections.unmodifiableMap(src);
}
if (MapExportable.TO_READ_SET_METHOD.equals(methodName)) { if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
return read; return Collections.unmodifiableMap(src);
} }
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) { Object value = src.get(methodName);
throw new HelenusException("invalid getter method " + method);
}
if ("hashCode".equals(methodName)) { if (value == null) {
return hashCode();
}
if ("toString".equals(methodName)) { Class<?> returnType = method.getReturnType();
return iface.getSimpleName() + ": " + src.toString();
}
if ("writeReplace".equals(methodName)) { if (returnType.isPrimitive()) {
return new SerializationProxy(this);
}
if ("readObject".equals(methodName)) { DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(returnType);
throw new InvalidObjectException("Proxy required."); if (type == null) {
} throw new HelenusException("unknown primitive type " + returnType);
}
if ("dsl".equals(methodName)) { return type.getDefaultValue();
return Helenus.dsl(iface);
}
final Object value = src.get(methodName); }
read.add(methodName);
if (value == null) { }
Class<?> returnType = method.getReturnType(); return value;
}
// Default implementations of non-Transient methods in entities are the default
// value when the map contains 'null'.
if (method.isDefault()) {
return invokeDefault(proxy, method, args);
}
// Otherwise, if the return type of the method is a primitive Java type then
// we'll return the standard default values to avoid a NPE in user code.
if (returnType.isPrimitive()) {
DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(returnType);
if (type == null) {
throw new HelenusException("unknown primitive type " + returnType);
}
return type.getDefaultValue();
}
}
return value;
}
static Map<String, Object> fromValueProviderMap(Map v) {
return fromValueProviderMap(v, false);
}
static Map<String, Object> fromValueProviderMap(Map v, boolean mutable) {
if (v instanceof ValueProviderMap) {
Map<String, Object> m = new HashMap<String, Object>(v.size());
Set<String> keys = v.keySet();
for (String key : keys) {
Object value = v.get(key);
if (value != null && mutable) {
if (ImmutableList.class.isAssignableFrom(value.getClass())) {
m.put(key, new ArrayList((List) value));
} else if (ImmutableMap.class.isAssignableFrom(value.getClass())) {
m.put(key, new HashMap((Map) value));
} else if (ImmutableSet.class.isAssignableFrom(value.getClass())) {
m.put(key, new HashSet((Set) value));
} else {
m.put(key, value);
}
} else {
m.put(key, value);
}
}
return m;
}
return v;
}
static class SerializationProxy<E> implements Serializable {
private static final long serialVersionUID = -5617583940055969353L;
private final Class<E> iface;
private final Map<String, Object> src;
public SerializationProxy(MapperInvocationHandler mapper) {
this.iface = mapper.iface;
if (mapper.src instanceof ValueProviderMap) {
this.src = fromValueProviderMap(mapper.src);
} else {
this.src = mapper.src;
}
}
Object readResolve() throws ObjectStreamException {
return new MapperInvocationHandler(iface, src);
}
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,25 +15,22 @@
*/ */
package net.helenus.core.reflect; package net.helenus.core.reflect;
import com.datastax.driver.core.Metadata;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Optional; import java.util.Optional;
import com.datastax.driver.core.Metadata;
import net.helenus.core.DslInstantiator; import net.helenus.core.DslInstantiator;
public enum ReflectionDslInstantiator implements DslInstantiator { public enum ReflectionDslInstantiator implements DslInstantiator {
INSTANCE;
@Override INSTANCE;
@SuppressWarnings("unchecked")
public <E> E instantiate( @Override
Class<E> iface, @SuppressWarnings("unchecked")
ClassLoader classLoader, public <E> E instantiate(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent, Metadata metadata) {
Optional<HelenusPropertyNode> parent, DslInvocationHandler<E> handler = new DslInvocationHandler<E>(iface, classLoader, parent, metadata);
Metadata metadata) { E proxy = (E) Proxy.newProxyInstance(classLoader, new Class[]{iface, DslExportable.class}, handler);
DslInvocationHandler<E> handler = return proxy;
new DslInvocationHandler<E>(iface, classLoader, parent, metadata); }
E proxy =
(E) Proxy.newProxyInstance(classLoader, new Class[] {iface, DslExportable.class}, handler);
return proxy;
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,14 +19,17 @@ import net.helenus.support.HelenusMappingException;
public final class ReflectionInstantiator { public final class ReflectionInstantiator {
private ReflectionInstantiator() {} private ReflectionInstantiator() {
}
public static <T> T instantiateClass(Class<T> clazz) { public static <T> T instantiateClass(Class<T> clazz) {
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new HelenusMappingException("invalid class " + clazz, e);
}
}
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new HelenusMappingException("invalid class " + clazz, e);
}
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,23 +15,23 @@
*/ */
package net.helenus.core.reflect; package net.helenus.core.reflect;
import java.io.Serializable;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Map; import java.util.Map;
import net.helenus.core.MapperInstantiator; import net.helenus.core.MapperInstantiator;
public enum ReflectionMapperInstantiator implements MapperInstantiator { public enum ReflectionMapperInstantiator implements MapperInstantiator {
INSTANCE;
@Override INSTANCE;
@SuppressWarnings("unchecked")
public <E> E instantiate(Class<E> iface, Map<String, Object> src, ClassLoader classLoader) { @Override
@SuppressWarnings("unchecked")
public <E> E instantiate(Class<E> iface, Map<String, Object> src, ClassLoader classLoader) {
MapperInvocationHandler<E> handler = new MapperInvocationHandler<E>(iface, src);
E proxy = (E) Proxy.newProxyInstance(classLoader, new Class[]{iface, MapExportable.class}, handler);
return proxy;
}
MapperInvocationHandler<E> handler = new MapperInvocationHandler<E>(iface, src);
E proxy =
(E)
Proxy.newProxyInstance(
classLoader, new Class[] {iface, MapExportable.class, Serializable.class}, handler);
return proxy;
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,103 +18,104 @@ package net.helenus.core.reflect;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public final class SetDsl<V> implements Set<V> { public final class SetDsl<V> implements Set<V> {
private final HelenusPropertyNode parent; private final HelenusPropertyNode parent;
public SetDsl(HelenusPropertyNode parent) { public SetDsl(HelenusPropertyNode parent) {
this.parent = parent; this.parent = parent;
} }
public HelenusPropertyNode getParent() { public HelenusPropertyNode getParent() {
return parent; return parent;
} }
@Override @Override
public int size() { public int size() {
throwShouldNeverCall(); throwShouldNeverCall();
return 0; return 0;
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean contains(Object o) { public boolean contains(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public Iterator<V> iterator() { public Iterator<V> iterator() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public Object[] toArray() { public Object[] toArray() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public <T> T[] toArray(T[] a) { public <T> T[] toArray(T[] a) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public boolean add(V e) { public boolean add(V e) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean containsAll(Collection<?> c) { public boolean containsAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean addAll(Collection<? extends V> c) { public boolean addAll(Collection<? extends V> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean retainAll(Collection<?> c) { public boolean retainAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean removeAll(Collection<?> c) { public boolean removeAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public void clear() { public void clear() {
throwShouldNeverCall(); throwShouldNeverCall();
} }
private void throwShouldNeverCall() { private void throwShouldNeverCall() {
throw new HelenusMappingException("should be never called"); throw new HelenusMappingException("should be never called");
} }
@Override @Override
public String toString() { public String toString() {
return "SetDsl"; return "SetDsl";
} }
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,6 +16,7 @@
package net.helenus.mapping; package net.helenus.mapping;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import net.helenus.mapping.annotation.ClusteringColumn; import net.helenus.mapping.annotation.ClusteringColumn;
import net.helenus.mapping.annotation.Column; import net.helenus.mapping.annotation.Column;
import net.helenus.mapping.annotation.PartitionKey; import net.helenus.mapping.annotation.PartitionKey;
@ -25,99 +25,93 @@ import net.helenus.support.HelenusMappingException;
public final class ColumnInformation { public final class ColumnInformation {
private final IdentityName columnName; private final IdentityName columnName;
private final ColumnType columnType; private final ColumnType columnType;
private final int ordinal; private final int ordinal;
private final OrderingDirection ordering; private final OrderingDirection ordering;
public ColumnInformation(Method getter) { public ColumnInformation(Method getter) {
String columnName = null; String columnName = null;
boolean forceQuote = false; boolean forceQuote = false;
ColumnType columnTypeLocal = ColumnType.COLUMN; ColumnType columnTypeLocal = ColumnType.COLUMN;
int ordinalLocal = 0; int ordinalLocal = 0;
OrderingDirection orderingLocal = OrderingDirection.ASC; OrderingDirection orderingLocal = OrderingDirection.ASC;
PartitionKey partitionKey = getter.getDeclaredAnnotation(PartitionKey.class); PartitionKey partitionKey = getter.getDeclaredAnnotation(PartitionKey.class);
if (partitionKey != null) { if (partitionKey != null) {
columnName = partitionKey.value(); columnName = partitionKey.value();
forceQuote = partitionKey.forceQuote(); forceQuote = partitionKey.forceQuote();
columnTypeLocal = ColumnType.PARTITION_KEY; columnTypeLocal = ColumnType.PARTITION_KEY;
ordinalLocal = partitionKey.ordinal(); ordinalLocal = partitionKey.ordinal();
} }
ClusteringColumn clusteringColumn = getter.getDeclaredAnnotation(ClusteringColumn.class); ClusteringColumn clusteringColumn = getter.getDeclaredAnnotation(ClusteringColumn.class);
if (clusteringColumn != null) { if (clusteringColumn != null) {
ensureSingleColumnType(columnTypeLocal, getter); ensureSingleColumnType(columnTypeLocal, getter);
columnName = clusteringColumn.value(); columnName = clusteringColumn.value();
forceQuote = clusteringColumn.forceQuote(); forceQuote = clusteringColumn.forceQuote();
columnTypeLocal = ColumnType.CLUSTERING_COLUMN; columnTypeLocal = ColumnType.CLUSTERING_COLUMN;
ordinalLocal = clusteringColumn.ordinal(); ordinalLocal = clusteringColumn.ordinal();
orderingLocal = clusteringColumn.ordering(); orderingLocal = clusteringColumn.ordering();
} }
StaticColumn staticColumn = getter.getDeclaredAnnotation(StaticColumn.class); StaticColumn staticColumn = getter.getDeclaredAnnotation(StaticColumn.class);
if (staticColumn != null) { if (staticColumn != null) {
ensureSingleColumnType(columnTypeLocal, getter); ensureSingleColumnType(columnTypeLocal, getter);
columnName = staticColumn.value(); columnName = staticColumn.value();
forceQuote = staticColumn.forceQuote(); forceQuote = staticColumn.forceQuote();
columnTypeLocal = ColumnType.STATIC_COLUMN; columnTypeLocal = ColumnType.STATIC_COLUMN;
ordinalLocal = staticColumn.ordinal(); ordinalLocal = staticColumn.ordinal();
} }
Column column = getter.getDeclaredAnnotation(Column.class); Column column = getter.getDeclaredAnnotation(Column.class);
if (column != null) { if (column != null) {
ensureSingleColumnType(columnTypeLocal, getter); ensureSingleColumnType(columnTypeLocal, getter);
columnName = column.value(); columnName = column.value();
forceQuote = column.forceQuote(); forceQuote = column.forceQuote();
columnTypeLocal = ColumnType.COLUMN; columnTypeLocal = ColumnType.COLUMN;
ordinalLocal = column.ordinal(); ordinalLocal = column.ordinal();
} }
if (columnName == null || columnName.isEmpty()) { if (columnName == null || columnName.isEmpty()) {
columnName = MappingUtil.getDefaultColumnName(getter); columnName = MappingUtil.getDefaultColumnName(getter);
} }
this.columnName = new IdentityName(columnName, forceQuote); this.columnName = new IdentityName(columnName, forceQuote);
this.columnType = columnTypeLocal; this.columnType = columnTypeLocal;
this.ordinal = ordinalLocal; this.ordinal = ordinalLocal;
this.ordering = orderingLocal; this.ordering = orderingLocal;
} }
public IdentityName getColumnName() { public IdentityName getColumnName() {
return columnName; return columnName;
} }
public ColumnType getColumnType() { public ColumnType getColumnType() {
return columnType; return columnType;
} }
public int getOrdinal() { public int getOrdinal() {
return ordinal; return ordinal;
} }
public OrderingDirection getOrdering() { public OrderingDirection getOrdering() {
return ordering; return ordering;
} }
private void ensureSingleColumnType(ColumnType columnTypeLocal, Method getter) { private void ensureSingleColumnType(ColumnType columnTypeLocal, Method getter) {
if (columnTypeLocal != ColumnType.COLUMN) { if (columnTypeLocal != ColumnType.COLUMN) {
throw new HelenusMappingException( throw new HelenusMappingException("property can be annotated only by a single column type " + getter);
"property can be annotated only by a single column type " + getter); }
}
} }
@Override
public String toString() {
return "ColumnInformation [columnName=" + columnName + ", columnType=" + columnType + ", ordinal=" + ordinal
+ ", ordering=" + ordering + "]";
}
@Override
public String toString() {
return "ColumnInformation [columnName="
+ columnName
+ ", columnType="
+ columnType
+ ", ordinal="
+ ordinal
+ ", ordering="
+ ordering
+ "]";
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,8 +16,5 @@
package net.helenus.mapping; package net.helenus.mapping;
public enum ColumnType { public enum ColumnType {
PARTITION_KEY, PARTITION_KEY, CLUSTERING_COLUMN, STATIC_COLUMN, COLUMN;
CLUSTERING_COLUMN,
STATIC_COLUMN,
COLUMN;
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,24 +16,19 @@
package net.helenus.mapping; package net.helenus.mapping;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import net.helenus.core.cache.Facet;
public interface HelenusEntity { public interface HelenusEntity {
HelenusEntityType getType(); HelenusEntityType getType();
boolean isCacheable(); boolean isCacheable();
Class<?> getMappingInterface(); Class<?> getMappingInterface();
IdentityName getName(); IdentityName getName();
Collection<HelenusProperty> getOrderedProperties(); Collection<HelenusProperty> getOrderedProperties();
HelenusProperty getProperty(String name); HelenusProperty getProperty(String name);
List<Facet> getFacets();
boolean isDraftable();
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,8 +16,5 @@
package net.helenus.mapping; package net.helenus.mapping;
public enum HelenusEntityType { public enum HelenusEntityType {
TABLE, TABLE, TUPLE, UDT;
VIEW,
TUPLE,
UDT;
} }

View file

@ -1,7 +1,6 @@
/* /*
* *
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
@ -16,356 +15,256 @@
*/ */
package net.helenus.mapping; package net.helenus.mapping;
import com.datastax.driver.core.DefaultMetadata;
import com.datastax.driver.core.Metadata;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
import javax.validation.ConstraintValidator;
import com.datastax.driver.core.*;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken;
import net.helenus.config.HelenusSettings; import net.helenus.config.HelenusSettings;
import net.helenus.core.Helenus; import net.helenus.core.Helenus;
import net.helenus.core.annotation.Cacheable; import net.helenus.core.annotation.Cacheable;
import net.helenus.core.cache.Facet;
import net.helenus.core.cache.UnboundFacet;
import net.helenus.mapping.annotation.*; import net.helenus.mapping.annotation.*;
import net.helenus.mapping.validator.DistinctValidator;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
public final class HelenusMappingEntity implements HelenusEntity { public final class HelenusMappingEntity implements HelenusEntity {
private final Class<?> iface; private final Class<?> iface;
private final HelenusEntityType type; private final HelenusEntityType type;
private final IdentityName name; private final IdentityName name;
private final boolean cacheable; private final boolean cacheable;
private final boolean draftable; private final ImmutableMap<String, Method> methods;
private final ImmutableMap<String, Method> methods; private final ImmutableMap<String, HelenusProperty> props;
private final ImmutableMap<String, HelenusProperty> props; private final ImmutableList<HelenusProperty> orderedProps;
private final ImmutableList<HelenusProperty> orderedProps;
private final List<Facet> facets;
public HelenusMappingEntity(Class<?> iface, Metadata metadata) { public HelenusMappingEntity(Class<?> iface, Metadata metadata) {
this(iface, autoDetectType(iface), metadata); this(iface, autoDetectType(iface), metadata);
} }
public HelenusMappingEntity(Class<?> iface, HelenusEntityType type, Metadata metadata) { public HelenusMappingEntity(Class<?> iface, HelenusEntityType type, Metadata metadata) {
if (iface == null || !iface.isInterface()) { if (iface == null || !iface.isInterface()) {
throw new IllegalArgumentException("invalid parameter " + iface); throw new IllegalArgumentException("invalid parameter " + iface);
} }
this.iface = iface; this.iface = iface;
this.type = Objects.requireNonNull(type, "type is empty"); this.type = Objects.requireNonNull(type, "type is empty");
this.name = resolveName(iface, type); this.name = resolveName(iface, type);
HelenusSettings settings = Helenus.settings(); HelenusSettings settings = Helenus.settings();
Map<String, Method> methods = new HashMap<String, Method>();
for (Method m : iface.getDeclaredMethods()) {
methods.put(m.getName(), m);
}
for (Class<?> c : ClassUtils.getAllInterfaces(iface)) { List<Method> methods = new ArrayList<Method>();
if (c.getDeclaredAnnotation(Table.class) != null
|| c.getDeclaredAnnotation(InheritedTable.class) != null) { methods.addAll(Arrays.asList(iface.getDeclaredMethods()));
for (Method m : c.getDeclaredMethods()) { for (Class<?> c : iface.getInterfaces()) {
Method o = methods.get(m.getName()); methods.addAll(Arrays.asList(c.getDeclaredMethods()));
if (o != null) {
// Prefer overridden method implementation.
if (o.getDeclaringClass().isAssignableFrom(m.getDeclaringClass())) {
methods.put(m.getName(), m);
}
} else {
methods.put(m.getName(), m);
}
} }
}
}
List<HelenusProperty> propsLocal = new ArrayList<HelenusProperty>(); List<HelenusProperty> propsLocal = new ArrayList<HelenusProperty>();
ImmutableMap.Builder<String, HelenusProperty> propsBuilder = ImmutableMap.builder(); ImmutableMap.Builder<String, HelenusProperty> propsBuilder = ImmutableMap.builder();
ImmutableMap.Builder<String, Method> methodsBuilder = ImmutableMap.builder(); ImmutableMap.Builder<String, Method> methodsBuilder = ImmutableMap.builder();
for (Method method : methods.values()) { for (Method method : methods) {
if (settings.getGetterMethodDetector().apply(method)) { if (settings.getGetterMethodDetector().apply(method)) {
methodsBuilder.put(method.getName(), method); methodsBuilder.put(method.getName(), method);
if (metadata != null) { if (metadata != null) {
HelenusProperty prop = new HelenusMappingProperty(this, method, metadata); HelenusProperty prop = new HelenusMappingProperty(this, method, metadata);
propsBuilder.put(prop.getPropertyName(), prop); propsBuilder.put(prop.getPropertyName(), prop);
propsLocal.add(prop); propsLocal.add(prop);
}
}
}
this.methods = methodsBuilder.build();
this.props = propsBuilder.build();
Collections.sort(propsLocal, TypeAndOrdinalColumnComparator.INSTANCE);
this.orderedProps = ImmutableList.copyOf(propsLocal);
validateOrdinals();
cacheable = (null != iface.getDeclaredAnnotation(Cacheable.class));
}
@Override
public HelenusEntityType getType() {
return type;
}
@Override
public boolean isCacheable() {
return cacheable;
}
@Override
public Class<?> getMappingInterface() {
return iface;
}
@Override
public Collection<HelenusProperty> getOrderedProperties() {
return orderedProps;
}
@Override
public HelenusProperty getProperty(String name) {
HelenusProperty property = props.get(name);
if (property == null && methods.containsKey(name)) {
property = new HelenusMappingProperty(this, methods.get(name), new DefaultMetadata());
return property; //TODO(gburd): review adding these into the props map...
} }
} return props.get(name);
} }
this.methods = methodsBuilder.build(); @Override
this.props = propsBuilder.build(); public IdentityName getName() {
return name;
}
Collections.sort(propsLocal, TypeAndOrdinalColumnComparator.INSTANCE); private static IdentityName resolveName(Class<?> iface, HelenusEntityType type) {
this.orderedProps = ImmutableList.copyOf(propsLocal);
validateOrdinals(); switch (type) {
// Caching case TABLE :
cacheable = (null != iface.getDeclaredAnnotation(Cacheable.class)); return MappingUtil.getTableName(iface, true);
// Draft case TUPLE :
Class<?> draft; return IdentityName.of(MappingUtil.getDefaultEntityName(iface), false);
try {
draft = Class.forName(iface.getName() + "$Draft");
} catch (Exception ignored) {
draft = null;
}
draftable = (draft != null);
// Materialized view case UDT :
List<HelenusProperty> primaryKeyProperties = new ArrayList<>(); return MappingUtil.getUserDefinedTypeName(iface, true);
ImmutableList.Builder<Facet> facetsBuilder = ImmutableList.builder(); }
if (iface.getDeclaredAnnotation(MaterializedView.class) == null) {
facetsBuilder.add(new Facet("table", name.toCql()).setFixed());
} else {
facetsBuilder.add(
new Facet("table", Helenus.entity(iface.getInterfaces()[0]).getName().toCql())
.setFixed());
}
for (HelenusProperty prop : orderedProps) {
switch (prop.getColumnType()) {
case PARTITION_KEY:
case CLUSTERING_COLUMN:
primaryKeyProperties.add(prop);
break;
default:
if (primaryKeyProperties != null && primaryKeyProperties.size() > 0) {
facetsBuilder.add(new UnboundFacet(primaryKeyProperties));
primaryKeyProperties = null;
}
for (ConstraintValidator<?, ?> constraint :
MappingUtil.getValidators(prop.getGetterMethod())) {
if (constraint instanceof DistinctValidator) {
DistinctValidator validator = (DistinctValidator) constraint;
String[] values = validator.constraintAnnotation.value();
UnboundFacet facet;
if (values != null && values.length >= 1 && !(StringUtils.isBlank(values[0]))) {
List<HelenusProperty> props = new ArrayList<HelenusProperty>(values.length + 1);
props.add(prop);
for (String value : values) {
for (HelenusProperty p : orderedProps) {
String name = p.getPropertyName();
if (name.equals(value) && !name.equals(prop.getPropertyName())) {
props.add(p);
}
}
}
facet = new UnboundFacet(props, validator.alone(), validator.combined());
} else {
facet = new UnboundFacet(prop, validator.alone(), validator.combined());
}
facetsBuilder.add(facet);
break;
}
}
}
}
if (primaryKeyProperties != null && primaryKeyProperties.size() > 0) {
facetsBuilder.add(new UnboundFacet(primaryKeyProperties));
}
this.facets = facetsBuilder.build();
}
private static IdentityName resolveName(Class<?> iface, HelenusEntityType type) { throw new HelenusMappingException("invalid entity type " + type + " in " + type);
switch (type) { }
case TABLE:
return MappingUtil.getTableName(iface, true);
case VIEW: private static HelenusEntityType autoDetectType(Class<?> iface) {
return MappingUtil.getViewName(iface, true);
case TUPLE: Objects.requireNonNull(iface, "empty iface");
return IdentityName.of(MappingUtil.getDefaultEntityName(iface), false);
case UDT: if (null != iface.getDeclaredAnnotation(Table.class)) {
return MappingUtil.getUserDefinedTypeName(iface, true); return HelenusEntityType.TABLE;
} }
throw new HelenusMappingException("invalid entity type " + type + " in " + type); else if (null != iface.getDeclaredAnnotation(Tuple.class)) {
} return HelenusEntityType.TUPLE;
}
private static HelenusEntityType autoDetectType(Class<?> iface) { else if (null != iface.getDeclaredAnnotation(UDT.class)) {
return HelenusEntityType.UDT;
}
Objects.requireNonNull(iface, "empty iface"); throw new HelenusMappingException("entity must be annotated by @Table or @Tuple or @UserDefinedType " + iface);
}
if (null != iface.getDeclaredAnnotation(Table.class)) { private void validateOrdinals() {
return HelenusEntityType.TABLE;
} else if (null != iface.getDeclaredAnnotation(MaterializedView.class)) {
return HelenusEntityType.VIEW;
} else if (null != iface.getDeclaredAnnotation(Tuple.class)) {
return HelenusEntityType.TUPLE;
} else if (null != iface.getDeclaredAnnotation(UDT.class)) {
return HelenusEntityType.UDT;
}
throw new HelenusMappingException( switch (getType()) {
"entity must be annotated by @Table or @Tuple or @UserDefinedType " + iface);
}
@Override case TABLE :
public HelenusEntityType getType() { validateOrdinalsForTable();
return type; break;
}
@Override case TUPLE :
public boolean isCacheable() { validateOrdinalsInTuple();
return cacheable; break;
}
@Override default :
public boolean isDraftable() { break;
return draftable; }
}
@Override }
public Class<?> getMappingInterface() {
return iface;
}
@Override private void validateOrdinalsForTable() {
public Collection<HelenusProperty> getOrderedProperties() {
return orderedProps;
}
@Override BitSet partitionKeys = new BitSet();
public HelenusProperty getProperty(String name) { BitSet clusteringColumns = new BitSet();
HelenusProperty property = props.get(name);
if (property == null && methods.containsKey(name)) {
property = new HelenusMappingProperty(this, methods.get(name), new DefaultMetadata());
return property; // TODO(gburd): review adding these into the props map...
}
return props.get(name);
}
@Override for (HelenusProperty prop : getOrderedProperties()) {
public List<Facet> getFacets() {
return facets;
}
@Override ColumnType type = prop.getColumnType();
public IdentityName getName() {
return name;
}
private void validateOrdinals() { int ordinal = prop.getOrdinal();
switch (getType()) { switch (type) {
case TABLE:
validateOrdinalsForTable();
break;
case TUPLE: case PARTITION_KEY :
validateOrdinalsInTuple(); if (partitionKeys.get(ordinal)) {
break; throw new HelenusMappingException(
"detected two or more partition key columns with the same ordinal " + ordinal + " in "
+ prop.getEntity());
}
partitionKeys.set(ordinal);
break;
default: case CLUSTERING_COLUMN :
break; if (clusteringColumns.get(ordinal)) {
} throw new HelenusMappingException("detected two or clustering columns with the same ordinal "
} + ordinal + " in " + prop.getEntity());
}
clusteringColumns.set(ordinal);
break;
private void validateOrdinalsForTable() { default :
break;
}
BitSet partitionKeys = new BitSet(); }
BitSet clusteringColumns = new BitSet();
for (HelenusProperty prop : getOrderedProperties()) { }
ColumnType type = prop.getColumnType(); private void validateOrdinalsInTuple() {
boolean[] ordinals = new boolean[props.size()];
int ordinal = prop.getOrdinal(); getOrderedProperties().forEach(p -> {
switch (type) { int ordinal = p.getOrdinal();
case PARTITION_KEY:
if (partitionKeys.get(ordinal)) {
throw new HelenusMappingException(
"detected two or more partition key columns with the same ordinal "
+ ordinal
+ " in "
+ prop.getEntity());
}
partitionKeys.set(ordinal);
break;
case CLUSTERING_COLUMN: if (ordinal < 0 || ordinal >= ordinals.length) {
if (clusteringColumns.get(ordinal)) { throw new HelenusMappingException("invalid ordinal " + ordinal + " found for property "
throw new HelenusMappingException( + p.getPropertyName() + " in " + p.getEntity());
"detected two or clustering columns with the same ordinal " }
+ ordinal
+ " in "
+ prop.getEntity());
}
clusteringColumns.set(ordinal);
break;
default: if (ordinals[ordinal]) {
break; throw new HelenusMappingException(
} "detected two or more properties with the same ordinal " + ordinal + " in " + p.getEntity());
} }
}
private void validateOrdinalsInTuple() { ordinals[ordinal] = true;
boolean[] ordinals = new boolean[props.size()];
getOrderedProperties() });
.forEach(
p -> {
int ordinal = p.getOrdinal();
if (ordinal < 0 || ordinal >= ordinals.length) { for (int i = 0; i != ordinals.length; ++i) {
throw new HelenusMappingException( if (!ordinals[i]) {
"invalid ordinal " throw new HelenusMappingException("detected absent ordinal " + i + " in " + this);
+ ordinal }
+ " found for property " }
+ p.getPropertyName()
+ " in "
+ p.getEntity());
}
if (ordinals[ordinal]) { }
throw new HelenusMappingException(
"detected two or more properties with the same ordinal "
+ ordinal
+ " in "
+ p.getEntity());
}
ordinals[ordinal] = true; @Override
}); public String toString() {
for (int i = 0; i != ordinals.length; ++i) { StringBuilder str = new StringBuilder();
if (!ordinals[i]) { str.append(iface.getSimpleName()).append("(").append(name.getName()).append(") ")
throw new HelenusMappingException("detected absent ordinal " + i + " in " + this); .append(type.name().toLowerCase()).append(":\n");
}
}
}
@Override for (HelenusProperty prop : getOrderedProperties()) {
public String toString() { str.append(prop.toString());
str.append("\n");
}
return str.toString();
}
StringBuilder str = new StringBuilder();
str.append(iface.getSimpleName())
.append("(")
.append(name.getName())
.append(") ")
.append(type.name().toLowerCase())
.append(":\n");
for (HelenusProperty prop : getOrderedProperties()) {
str.append(prop.toString());
str.append("\n");
}
return str.toString();
}
} }

Some files were not shown because too many files have changed in this diff Show more