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
.idea
infer-out

View file

@ -3,6 +3,7 @@
<component name="EclipseCodeFormatterProjectSettings">
<option name="projectSpecificProfile">
<ProjectSpecificProfile>
<option name="formatter" value="ECLIPSE" />
<option name="pathToConfigFileJava" value="$PROJECT_DIR$/../newton/formatting/onshape-eclipse-general-preferences.epf" />
</ProjectSpecificProfile>
</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
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
@ -9,13 +9,14 @@ Fast and easy, functional style cutting edge Java 8 Cassandra client for C* 3.x
* Reactive asynchronous and synchronous API
* Provides Java mapping for Tables, Tuples, UDTs (User Defined Type), Collections, UDT Collections, Tuple Collections
* Uses lazy mapping in all cases where possible
* Supports Java 8 Futures and Guava ListenableFuture
* Supports Guava ListenableFuture and Scala Future
### Requirements
* JVM 8
* Datastax Driver 3.x
* Cassandra 3.x
* Scala 2.11+
* Maven
### Maven
@ -31,6 +32,27 @@ Latest release dependency:
</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
@ -110,6 +132,7 @@ public interface AbstractRepository {
Account repository:
```
import scala.concurrent.Future;
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>
<orderEntry type="inheritedJdk" />
<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-buffer: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-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.datastax.cassandra:cassandra-driver-extras:3.3.2" level="project" />
<orderEntry type="library" name="Maven: com.diffplug.durian:durian:3.4.0" level="project" />
<orderEntry type="library" name="Maven: org.aspectj:aspectjrt: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.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: 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: 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" 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" />
@ -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.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: 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: 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: 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-core:1.3" 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>
<groupId>net.helenus</groupId>
<artifactId>helenus-net-core</artifactId>
<version>2.1</version>
<artifactId>helenus-core</artifactId>
<version>2.0.5-SNAPSHOT</version>
<packaging>jar</packaging>
<name>helenus</name>
@ -40,9 +40,6 @@
<properties>
<dist.id>helenus</dist.id>
<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>
<repositories>
@ -106,22 +103,22 @@
<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.13.0-M1</version>
</dependency>
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId>
<version>3.3.2</version>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-extras</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.diffplug.durian</groupId>
<artifactId>durian</artifactId>
<version>3.4.0</version>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
@ -142,23 +139,25 @@
<version>4.3.10.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
<!-- Caching -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.5.3</version>
</dependency>
<!-- Metrics -->
<!-- https://mvnrepository.com/artifact/io.dropwizard.metrics/metrics-core -->
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>3.2.2</version>
<version>3.2.3</version>
</dependency>
<!-- Validation -->
@ -211,24 +210,6 @@
<scope>test</scope>
</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>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
@ -243,6 +224,13 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stephenc</groupId>
<artifactId>jamm</artifactId>
<version>0.2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
@ -277,6 +265,7 @@
<version>1.7.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>

View file

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

View file

@ -5,9 +5,7 @@ import java.util.List;
public class DefaultMetadata extends Metadata {
public DefaultMetadata() {
super(null);
}
public DefaultMetadata() { super(null); }
private DefaultMetadata(Cluster.Manager cluster) {
super(cluster);
@ -20,4 +18,5 @@ public class DefaultMetadata extends Metadata {
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,9 +1,11 @@
package com.datastax.driver.core.schemabuilder;
import static com.datastax.driver.core.schemabuilder.SchemaStatement.*;
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 {
private String indexName;
@ -16,10 +18,7 @@ public class CreateCustomIndex extends CreateIndex {
CreateCustomIndex(String indexName) {
super(indexName);
validateNotEmpty(indexName, "Index name");
validateNotKeyWord(
indexName,
String.format(
"The index name '%s' is not allowed because it is a reserved keyword", indexName));
validateNotKeyWord(indexName, String.format("The index name '%s' is not allowed because it is a reserved keyword", indexName));
this.indexName = indexName;
}
@ -43,15 +42,8 @@ public class CreateCustomIndex extends CreateIndex {
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));
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();
@ -65,26 +57,46 @@ public class CreateCustomIndex extends CreateIndex {
*/
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));
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 "";
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());
}
String getOptions() {
return "";
/**
* 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 ");
StringBuilder createStatement = new StringBuilder(STATEMENT_START).append("CREATE CUSTOM INDEX ");
if (ifNotExists) {
createStatement.append("IF NOT EXISTS ");
@ -117,39 +129,4 @@ public class CreateCustomIndex extends CreateIndex {
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.
*
* @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());
}
}
}

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

@ -17,7 +17,9 @@ package com.datastax.driver.core.schemabuilder;
import com.datastax.driver.core.CodecRegistry;
/** A built CREATE TABLE statement. */
/**
* A built CREATE TABLE statement.
*/
public class CreateTable extends Create {
public CreateTable(String keyspaceName, String tableName) {

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,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -18,6 +17,7 @@ package net.helenus.config;
import java.lang.reflect.Method;
import java.util.function.Function;
import net.helenus.core.DslInstantiator;
import net.helenus.core.MapperInstantiator;
import net.helenus.core.reflect.ReflectionDslInstantiator;
@ -45,4 +45,5 @@ public class DefaultHelenusSettings implements HelenusSettings {
public MapperInstantiator getMapperInstantiator() {
return ReflectionMapperInstantiator.INSTANCE;
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,12 +15,13 @@
*/
package net.helenus.config;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.function.Function;
import net.helenus.mapping.annotation.Transient;
import java.lang.reflect.Method;
import java.util.function.Function;
public enum GetterMethodDetector implements Function<Method, Boolean> {
INSTANCE;
@Override
@ -35,15 +35,13 @@ public enum GetterMethodDetector implements Function<Method, Boolean> {
return false;
}
if (Modifier.isStatic(method.getModifiers())) {
return false;
}
// Methods marked "Transient" are not mapped, skip them.
if (method.getDeclaredAnnotation(Transient.class) != null) {
return false;
}
return true;
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -18,6 +17,7 @@ package net.helenus.config;
import java.lang.reflect.Method;
import java.util.function.Function;
import net.helenus.core.DslInstantiator;
import net.helenus.core.MapperInstantiator;
@ -30,4 +30,5 @@ public interface HelenusSettings {
DslInstantiator getDslInstantiator();
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,118 +15,133 @@
*/
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.util.List;
import java.util.concurrent.Executor;
import net.helenus.core.cache.Facet;
import net.helenus.mapping.value.ColumnValuePreparer;
import net.helenus.mapping.value.ColumnValueProvider;
import net.helenus.support.Either;
import net.helenus.support.HelenusException;
import com.datastax.driver.core.schemabuilder.SchemaStatement;
import org.slf4j.Logger;
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 {
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();
public abstract ColumnValuePreparer getValuePreparer();
public abstract ConsistencyLevel getDefaultConsistencyLevel();
public abstract boolean getDefaultQueryIdempotency();
abstract public ColumnValuePreparer getValuePreparer();
public PreparedStatement prepare(RegularStatement statement) {
try {
log(statement, false);
return currentSession().prepare(statement);
} catch (RuntimeException e) {
throw translateException(e);
}
}
public ListenableFuture<PreparedStatement> prepareAsync(RegularStatement statement) {
try {
log(statement, false);
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, boolean showValues) {
return executeAsync(statement, showValues).getUninterruptibly();
}
public ResultSet execute(Statement statement, Stopwatch timer) {
return execute(statement, null, timer);
}
public ResultSetFuture executeAsync(Statement statement, boolean showValues) {
public ResultSet execute(Statement statement, UnitOfWork uow) {
return execute(statement, uow, null);
}
public ResultSet execute(Statement statement, UnitOfWork uow, Stopwatch timer) {
return executeAsync(statement, uow, timer).getUninterruptibly();
}
public ResultSetFuture executeAsync(Statement statement) {
return executeAsync(statement, null, null);
}
public ResultSetFuture executeAsync(Statement statement, Stopwatch timer) {
return executeAsync(statement, null, timer);
}
public ResultSetFuture executeAsync(Statement statement, UnitOfWork uow) {
return executeAsync(statement, uow, null);
}
public ResultSetFuture executeAsync(Statement statement, UnitOfWork uow, Stopwatch timer) {
try {
log(statement, showValues);
return currentSession().executeAsync(statement);
} catch (RuntimeException e) {
throw translateException(e);
}
}
public MetricRegistry getMetricRegistry() {
return null;
void log(Statement statement, boolean showValues) {
if (logger.isInfoEnabled()) {
logger.info("Execute statement " + statement);
}
public void mergeCache(Table<String, String, Either<Object, List<Facet>>> uowCache) {}
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);
}
public Object checkCache(String tableName, List<Facet> facets) {
return null;
void printCql(String cql) {
getPrintStream().println(cql);
}
public void updateCache(Object pojo, List<Facet> facets) {}
public void cacheEvict(List<Facet> facets) {}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -17,8 +16,5 @@
package net.helenus.core;
public enum AutoDdl {
VALIDATE,
UPDATE,
CREATE,
CREATE_DROP;
VALIDATE, UPDATE, CREATE, CREATE_DROP;
}

View file

@ -1,20 +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;
public class ConflictingUnitOfWorkException extends Exception {
@ -24,4 +7,5 @@ public class ConflictingUnitOfWorkException extends Exception {
ConflictingUnitOfWorkException(UnitOfWork uow) {
this.uow = uow;
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,15 +15,13 @@
*/
package net.helenus.core;
import com.datastax.driver.core.Metadata;
import java.util.Optional;
import com.datastax.driver.core.Metadata;
import net.helenus.core.reflect.HelenusPropertyNode;
public interface DslInstantiator {
<E> E instantiate(
Class<E> iface,
ClassLoader classLoader,
Optional<HelenusPropertyNode> parent,
Metadata metadata);
<E> E instantiate(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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,8 +15,10 @@
*/
package net.helenus.core;
import com.datastax.driver.core.querybuilder.Clause;
import java.util.Objects;
import com.datastax.driver.core.querybuilder.Clause;
import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.value.ColumnValuePreparer;
@ -32,6 +33,14 @@ public final class Filter<V> {
this.postulate = postulate;
}
public HelenusPropertyNode getNode() {
return node;
}
public Clause getClause(ColumnValuePreparer valuePreparer) {
return postulate.getClause(node, valuePreparer);
}
public static <V> Filter<V> equal(Getter<V> getter, V val) {
return create(getter, Operator.EQ, val);
}
@ -80,21 +89,13 @@ public final class Filter<V> {
return new Filter<V>(node, postulate);
}
public static <V> Filter<V> create(
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) {
Objects.requireNonNull(getter, "empty getter");
Objects.requireNonNull(op, "empty op");
Objects.requireNonNull(val, "empty value");
if (op == Operator.IN) {
throw new IllegalArgumentException(
"invalid usage of the 'in' operator, use Filter.in() static method");
throw new IllegalArgumentException("invalid usage of the 'in' operator, use Filter.in() static method");
}
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
@ -104,20 +105,9 @@ public final class Filter<V> {
return new Filter<V>(node, postulate);
}
public HelenusPropertyNode getNode() {
return node;
}
public Clause getClause(ColumnValuePreparer valuePreparer) {
return postulate.getClause(node, valuePreparer);
}
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -19,4 +18,5 @@ package net.helenus.core;
public interface Getter<V> {
V get();
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,15 +15,14 @@
*/
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.Metadata;
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.HelenusSettings;
import net.helenus.core.reflect.DslExportable;
@ -34,15 +32,15 @@ import net.helenus.support.HelenusMappingException;
public final class Helenus {
private static final ConcurrentMap<Class<?>, Object> dslCache =
new ConcurrentHashMap<Class<?>, Object>();
private static final ConcurrentMap<Class<?>, Metadata> metadataForEntity =
new ConcurrentHashMap<Class<?>, Metadata>();
private static final Set<HelenusSession> sessions = new HashSet<HelenusSession>();
private static volatile HelenusSettings settings = new DefaultHelenusSettings();
private static final ConcurrentMap<Class<?>, Object> dslCache = new ConcurrentHashMap<Class<?>, Object>();
private static final ConcurrentMap<Class<?>, Metadata> metadataForEntity = new ConcurrentHashMap<Class<?>, Metadata>();
private static final Set<HelenusSession> sessions = new HashSet<HelenusSession>();
private static volatile HelenusSession singleton;
private Helenus() {}
private Helenus() {
}
protected static void setSession(HelenusSession session) {
sessions.add(session);
@ -54,8 +52,7 @@ public final class Helenus {
}
public static void shutdown() {
sessions.forEach(
(session) -> {
sessions.forEach((session) -> {
session.close();
sessions.remove(session);
});
@ -82,10 +79,6 @@ public final class Helenus {
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) {
@ -111,10 +104,7 @@ public final class Helenus {
return dsl(iface, classLoader, Optional.empty(), metadata);
}
public static <E> E dsl(
Class<E> iface,
ClassLoader classLoader,
Optional<HelenusPropertyNode> parent,
public static <E> E dsl(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent,
Metadata metadata) {
Object instance = null;
@ -133,6 +123,7 @@ public final class Helenus {
if (c != null) {
instance = c;
}
}
}
@ -148,14 +139,7 @@ public final class Helenus {
}
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);
return entity(iface, metadataForEntity.get(iface));
}
public static HelenusEntity entity(Class<?> iface, Metadata metadata) {
@ -192,12 +176,12 @@ public final class Helenus {
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);
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,97 +15,73 @@
*/
package net.helenus.core;
import static net.helenus.core.Query.eq;
import com.codahale.metrics.MetricRegistry;
import com.datastax.driver.core.*;
import com.google.common.collect.Table;
import java.io.Closeable;
import java.io.PrintStream;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.cache.Cache;
import javax.cache.CacheManager;
import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet;
import net.helenus.core.cache.UnboundFacet;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import net.helenus.core.operation.*;
import net.helenus.core.reflect.Drafted;
import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.core.reflect.MapExportable;
import net.helenus.mapping.ColumnType;
import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.value.*;
import net.helenus.support.*;
import net.helenus.support.Fun;
import net.helenus.support.Fun.Tuple1;
import net.helenus.support.Fun.Tuple2;
import net.helenus.support.Fun.Tuple6;
public class HelenusSession extends AbstractSessionOperations implements Closeable {
public static final Object deleted = new Object();
import java.io.Closeable;
import java.io.PrintStream;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
public final class HelenusSession extends AbstractSessionOperations implements Closeable {
private final Session session;
private final CodecRegistry registry;
private final ConsistencyLevel defaultConsistencyLevel;
private final boolean defaultQueryIdempotency;
private final MetricRegistry metricRegistry;
private volatile String usingKeyspace;
private volatile boolean showCql;
private final PrintStream printStream;
private final SessionRepository sessionRepository;
private final Executor executor;
private final boolean dropSchemaOnClose;
private final CacheManager cacheManager;
private final RowColumnValueProvider valueProvider;
private final StatementColumnValuePreparer valuePreparer;
private final Metadata metadata;
private volatile String usingKeyspace;
private volatile boolean showCql;
private volatile boolean showValues;
private final MetricRegistry metricRegistry;
private final Cache<String, Object> sessionCache;
private UnitOfWork currentUnitOfWork;
HelenusSession(
Session session,
String usingKeyspace,
CodecRegistry registry,
boolean showCql,
boolean showValues,
PrintStream printStream,
SessionRepositoryBuilder sessionRepositoryBuilder,
Executor executor,
boolean dropSchemaOnClose,
ConsistencyLevel consistencyLevel,
boolean defaultQueryIdempotency,
CacheManager cacheManager,
MetricRegistry metricRegistry) {
HelenusSession(Session session, String usingKeyspace, CodecRegistry registry, boolean showCql,
PrintStream printStream, SessionRepositoryBuilder sessionRepositoryBuilder, Executor executor,
boolean dropSchemaOnClose, MetricRegistry metricRegistry) {
this.session = session;
this.registry = registry == null ? CodecRegistry.DEFAULT_INSTANCE : registry;
this.usingKeyspace =
Objects.requireNonNull(
usingKeyspace, "keyspace needs to be selected before creating session");
this.usingKeyspace = Objects.requireNonNull(usingKeyspace,
"keyspace needs to be selected before creating session");
this.showCql = showCql;
this.showValues = showValues;
this.printStream = printStream;
this.sessionRepository =
sessionRepositoryBuilder == null ? null : sessionRepositoryBuilder.build();
this.sessionRepository = sessionRepositoryBuilder.build();
this.executor = executor;
this.dropSchemaOnClose = dropSchemaOnClose;
this.defaultConsistencyLevel = consistencyLevel;
this.defaultQueryIdempotency = defaultQueryIdempotency;
this.metricRegistry = metricRegistry;
this.cacheManager = cacheManager;
this.valueProvider = new RowColumnValueProvider(this.sessionRepository);
this.valuePreparer = new StatementColumnValuePreparer(this.sessionRepository);
this.metadata = session == null ? null : session.getCluster().getMetadata();
}
this.metadata = session.getCluster().getMetadata();
this.currentUnitOfWork = null;
public UnitOfWork begin() {
return new UnitOfWork(this).begin();
this.metricRegistry = metricRegistry;
Caffeine<Object, Object> cacheBuilder = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.maximumSize(10_000);
if (this.metricRegistry != null) {
cacheBuilder.recordStats(() -> new MetricsStatsCounter(metricRegistry, "helenus-session-cache"));
}
public UnitOfWork begin(UnitOfWork parent) {
return new UnitOfWork(this, parent).begin();
sessionCache = cacheBuilder.build();
}
@Override
@ -145,20 +120,6 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
return this;
}
public HelenusSession showQueryValuesInLog(boolean showValues) {
this.showValues = showValues;
return this;
}
public HelenusSession showQueryValuesInLog() {
this.showValues = true;
return this;
}
public boolean showValues() {
return showValues;
}
@Override
public Executor getExecutor() {
return executor;
@ -179,201 +140,64 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
return valuePreparer;
}
@Override
public MetricRegistry getMetricRegistry() {
return metricRegistry;
}
public Metadata getMetadata() { return metadata; }
@Override
public ConsistencyLevel getDefaultConsistencyLevel() {
return defaultConsistencyLevel;
}
@Override
public boolean getDefaultQueryIdempotency() {
return defaultQueryIdempotency;
}
@Override
public Object checkCache(String tableName, List<Facet> facets) {
Object result = null;
if (cacheManager != null) {
Cache<String, Object> cache = cacheManager.getCache(tableName);
if (cache != null) {
for (String key : CacheUtil.flatKeys(tableName, facets)) {
result = cache.get(key);
if (result != null) {
return result;
}
}
}
}
return null;
}
@Override
public void cacheEvict(List<Facet> facets) {
if (cacheManager != null) {
String tableName = CacheUtil.schemaName(facets);
Cache<String, Object> cache = cacheManager.getCache(tableName);
if (cache != null) {
CacheUtil.flatKeys(tableName, facets).forEach(key -> cache.remove(key));
}
}
}
@Override
public void updateCache(Object pojo, List<Facet> facets) {
Map<String, Object> valueMap =
pojo instanceof MapExportable ? ((MapExportable) pojo).toMap() : null;
List<Facet> boundFacets = new ArrayList<>();
for (Facet facet : facets) {
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());
}
public synchronized UnitOfWork begin() {
if (currentUnitOfWork == null) {
currentUnitOfWork = new UnitOfWork(this);
return currentUnitOfWork;
} else {
value = valueMap.get(prop.getPropertyName());
if (value != null) binder.setValueForProperty(prop, value.toString());
}
}
if (binder.isBound()) {
boundFacets.add(binder.bind());
}
} else {
boundFacets.add(facet);
}
}
String tableName = CacheUtil.schemaName(facets);
List<String[]> facetCombinations = CacheUtil.flattenFacets(boundFacets);
replaceCachedFacetValues(pojo, tableName, facetCombinations);
}
@Override
public void mergeCache(Table<String, String, Either<Object, List<Facet>>> uowCache) {
if (cacheManager != null) {
List<Object> items =
uowCache
.values()
.stream()
.filter(Either::isLeft)
.map(Either::getLeft)
.distinct()
.collect(Collectors.toList());
for (Object pojo : items) {
HelenusEntity entity = Helenus.resolve(MappingUtil.getMappingInterface(pojo));
Map<String, Object> valueMap =
pojo instanceof MapExportable ? ((MapExportable) pojo).toMap() : null;
if (entity.isCacheable()) {
List<Facet> boundFacets = new ArrayList<>();
for (Facet facet : entity.getFacets()) {
if (facet instanceof UnboundFacet) {
UnboundFacet unboundFacet = (UnboundFacet) facet;
UnboundFacet.Binder binder = unboundFacet.binder();
unboundFacet
.getProperties()
.forEach(
prop -> {
if (valueMap == null) {
Object value =
BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop);
binder.setValueForProperty(prop, value.toString());
} else {
Object v = valueMap.get(prop.getPropertyName());
if (v != null) {
binder.setValueForProperty(prop, v.toString());
}
}
});
if (binder.isBound()) {
boundFacets.add(binder.bind());
}
} else {
boundFacets.add(facet);
}
}
List<String[]> facetCombinations = CacheUtil.flattenFacets(boundFacets);
String tableName = CacheUtil.schemaName(boundFacets);
replaceCachedFacetValues(pojo, tableName, facetCombinations);
return currentUnitOfWork.begin();
}
}
List<List<Facet>> deletedFacetSets =
uowCache
.values()
.stream()
.filter(Either::isRight)
.map(Either::getRight)
.collect(Collectors.toList());
for (List<Facet> facets : deletedFacetSets) {
String tableName = CacheUtil.schemaName(facets);
Cache<String, Object> cache = cacheManager.getCache(tableName);
if (cache != null) {
List<String> keys = CacheUtil.flatKeys(tableName, facets);
keys.forEach(key -> cache.remove(key));
}
}
public synchronized void commit() throws ConflictingUnitOfWorkException {
if (currentUnitOfWork != null) {
currentUnitOfWork.commit();
currentUnitOfWork = null;
}
}
private void replaceCachedFacetValues(
Object pojo, String tableName, List<String[]> facetCombinations) {
if (cacheManager != null) {
for (String[] combination : facetCombinations) {
String cacheKey = tableName + "." + Arrays.toString(combination);
Cache<String, Object> cache = cacheManager.getCache(tableName);
if (cache != null) {
if (pojo == null || pojo == HelenusSession.deleted) {
cache.remove(cacheKey);
} else {
cache.put(cacheKey, pojo);
}
}
}
public synchronized void abort() {
if (currentUnitOfWork != null) {
currentUnitOfWork.abort();
currentUnitOfWork = null;
}
}
public CacheManager getCacheManager() {
return cacheManager;
public void cache(String key, Object value) {
sessionCache.put(key, value);
}
public Metadata getMetadata() {
return metadata;
}
public <E> SelectOperation<E> select(E pojo) {
Objects.requireNonNull(
pojo, "supplied object must be a dsl for a registered entity but cannot be null");
ColumnValueProvider valueProvider = getValueProvider();
HelenusEntity entity = Helenus.resolve(pojo);
Class<?> entityClass = entity.getMappingInterface();
return new SelectOperation<E>(
this,
entity,
(r) -> {
Map<String, Object> map = new ValueProviderMap(r, valueProvider, entity);
return (E) Helenus.map(entityClass, map);
});
public Object fetch(String key) {
return sessionCache.getIfPresent(key);
}
public <E> SelectOperation<E> select(Class<E> entityClass) {
Objects.requireNonNull(entityClass, "entityClass is empty");
ColumnValueProvider valueProvider = getValueProvider();
HelenusEntity entity = Helenus.entity(entityClass);
return new SelectOperation<E>(
this,
entity,
(r) -> {
return new SelectOperation<E>(this, entity, (r) -> {
Map<String, Object> map = new ValueProviderMap(r, valueProvider, entity);
return (E) Helenus.map(entityClass, map);
E pojo = (E) Helenus.map(entityClass, map);
if (entity.isCacheable()) {
StringBuilder cacheKey = new StringBuilder();
entity.getOrderedProperties().stream().forEach(property -> {
ColumnType ct = property.getColumnType();
switch (ct) {
case PARTITION_KEY:
case CLUSTERING_COLUMN:
cacheKey.append(map.get(property.getPropertyName()).toString());
break;
}
});
cache(cacheKey.toString(), pojo);
}
return pojo;
});
}
@ -381,24 +205,9 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
return new SelectOperation<Fun.ArrayTuple>(this);
}
public <E> SelectOperation<E> selectAll(Class<E> entityClass) {
public SelectOperation<Row> selectAll(Class<?> entityClass) {
Objects.requireNonNull(entityClass, "entityClass is empty");
HelenusEntity entity = Helenus.entity(entityClass);
return new SelectOperation<E>(
this,
entity,
(r) -> {
Map<String, Object> map = new ValueProviderMap(r, valueProvider, entity);
return (E) Helenus.map(entityClass, map);
});
}
public <E> SelectOperation<Row> selectAll(E pojo) {
Objects.requireNonNull(
pojo, "supplied object must be a dsl for a registered entity but cannot be null");
HelenusEntity entity = Helenus.resolve(pojo);
return new SelectOperation<Row>(this, entity);
return new SelectOperation<Row>(this, Helenus.entity(entityClass));
}
public <E> SelectOperation<E> selectAll(Class<E> entityClass, Function<Row, E> rowMapper) {
@ -411,8 +220,7 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
Objects.requireNonNull(getter1, "field 1 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
return new SelectOperation<Tuple1<V1>>(
this, new Mappers.Mapper1<V1>(getValueProvider(), p1), p1);
return new SelectOperation<Tuple1<V1>>(this, new Mappers.Mapper1<V1>(getValueProvider(), p1), p1);
}
public <V1, V2> SelectOperation<Tuple2<V1, V2>> select(Getter<V1> getter1, Getter<V2> getter2) {
@ -421,12 +229,12 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
return new SelectOperation<Fun.Tuple2<V1, V2>>(
this, new Mappers.Mapper2<V1, V2>(getValueProvider(), p1, p2), p1, p2);
return new SelectOperation<Fun.Tuple2<V1, V2>>(this, new Mappers.Mapper2<V1, V2>(getValueProvider(), p1, p2),
p1, p2);
}
public <V1, V2, V3> SelectOperation<Fun.Tuple3<V1, V2, V3>> select(
Getter<V1> getter1, Getter<V2> getter2, Getter<V3> getter3) {
public <V1, V2, V3> SelectOperation<Fun.Tuple3<V1, V2, V3>> select(Getter<V1> getter1, Getter<V2> getter2,
Getter<V3> getter3) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
@ -434,12 +242,12 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
return new SelectOperation<Fun.Tuple3<V1, V2, V3>>(
this, new Mappers.Mapper3<V1, V2, V3>(getValueProvider(), p1, p2, p3), p1, p2, p3);
return new SelectOperation<Fun.Tuple3<V1, V2, V3>>(this,
new Mappers.Mapper3<V1, V2, V3>(getValueProvider(), p1, p2, p3), p1, p2, p3);
}
public <V1, V2, V3, V4> SelectOperation<Fun.Tuple4<V1, V2, V3, V4>> select(
Getter<V1> getter1, Getter<V2> getter2, Getter<V3> getter3, Getter<V4> getter4) {
public <V1, V2, V3, V4> SelectOperation<Fun.Tuple4<V1, V2, V3, V4>> select(Getter<V1> getter1, Getter<V2> getter2,
Getter<V3> getter3, Getter<V4> getter4) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
@ -449,21 +257,12 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
HelenusPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
return new SelectOperation<Fun.Tuple4<V1, V2, V3, V4>>(
this,
new Mappers.Mapper4<V1, V2, V3, V4>(getValueProvider(), p1, p2, p3, p4),
p1,
p2,
p3,
p4);
return new SelectOperation<Fun.Tuple4<V1, V2, V3, V4>>(this,
new Mappers.Mapper4<V1, V2, V3, V4>(getValueProvider(), p1, p2, p3, p4), p1, p2, p3, p4);
}
public <V1, V2, V3, V4, V5> SelectOperation<Fun.Tuple5<V1, V2, V3, V4, V5>> select(
Getter<V1> getter1,
Getter<V2> getter2,
Getter<V3> getter3,
Getter<V4> getter4,
Getter<V5> getter5) {
public <V1, V2, V3, V4, V5> SelectOperation<Fun.Tuple5<V1, V2, V3, V4, V5>> select(Getter<V1> getter1,
Getter<V2> getter2, Getter<V3> getter3, Getter<V4> getter4, Getter<V5> getter5) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
@ -475,23 +274,12 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
HelenusPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
HelenusPropertyNode p5 = MappingUtil.resolveMappingProperty(getter5);
return new SelectOperation<Fun.Tuple5<V1, V2, V3, V4, V5>>(
this,
new Mappers.Mapper5<V1, V2, V3, V4, V5>(getValueProvider(), p1, p2, p3, p4, p5),
p1,
p2,
p3,
p4,
p5);
return new SelectOperation<Fun.Tuple5<V1, V2, V3, V4, V5>>(this,
new Mappers.Mapper5<V1, V2, V3, V4, V5>(getValueProvider(), p1, p2, p3, p4, p5), p1, p2, p3, p4, p5);
}
public <V1, V2, V3, V4, V5, V6> SelectOperation<Fun.Tuple6<V1, V2, V3, V4, V5, V6>> select(
Getter<V1> getter1,
Getter<V2> getter2,
Getter<V3> getter3,
Getter<V4> getter4,
Getter<V5> getter5,
Getter<V6> getter6) {
public <V1, V2, V3, V4, V5, V6> SelectOperation<Fun.Tuple6<V1, V2, V3, V4, V5, V6>> select(Getter<V1> getter1,
Getter<V2> getter2, Getter<V3> getter3, Getter<V4> getter4, Getter<V5> getter5, Getter<V6> getter6) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
@ -505,26 +293,14 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
HelenusPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
HelenusPropertyNode p5 = MappingUtil.resolveMappingProperty(getter5);
HelenusPropertyNode p6 = MappingUtil.resolveMappingProperty(getter6);
return new SelectOperation<Tuple6<V1, V2, V3, V4, V5, V6>>(
this,
new Mappers.Mapper6<V1, V2, V3, V4, V5, V6>(getValueProvider(), p1, p2, p3, p4, p5, p6),
p1,
p2,
p3,
p4,
p5,
p6);
return new SelectOperation<Tuple6<V1, V2, V3, V4, V5, V6>>(this,
new Mappers.Mapper6<V1, V2, V3, V4, V5, V6>(getValueProvider(), p1, p2, p3, p4, p5, p6), p1, p2, p3, p4,
p5, p6);
}
public <V1, V2, V3, V4, V5, V6, V7>
SelectOperation<Fun.Tuple7<V1, V2, V3, V4, V5, V6, V7>> select(
Getter<V1> getter1,
Getter<V2> getter2,
Getter<V3> getter3,
Getter<V4> getter4,
Getter<V5> getter5,
Getter<V6> getter6,
Getter<V7> getter7) {
public <V1, V2, V3, V4, V5, V6, V7> SelectOperation<Fun.Tuple7<V1, V2, V3, V4, V5, V6, V7>> select(
Getter<V1> getter1, Getter<V2> getter2, Getter<V3> getter3, Getter<V4> getter4, Getter<V5> getter5,
Getter<V6> getter6, Getter<V7> getter7) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
@ -540,17 +316,9 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
HelenusPropertyNode p5 = MappingUtil.resolveMappingProperty(getter5);
HelenusPropertyNode p6 = MappingUtil.resolveMappingProperty(getter6);
HelenusPropertyNode p7 = MappingUtil.resolveMappingProperty(getter7);
return new SelectOperation<Fun.Tuple7<V1, V2, V3, V4, V5, V6, V7>>(
this,
new Mappers.Mapper7<V1, V2, V3, V4, V5, V6, V7>(
getValueProvider(), p1, p2, p3, p4, p5, p6, p7),
p1,
p2,
p3,
p4,
p5,
p6,
p7);
return new SelectOperation<Fun.Tuple7<V1, V2, V3, V4, V5, V6, V7>>(this,
new Mappers.Mapper7<V1, V2, V3, V4, V5, V6, V7>(getValueProvider(), p1, p2, p3, p4, p5, p6, p7), p1, p2,
p3, p4, p5, p6, p7);
}
public CountOperation count() {
@ -562,162 +330,43 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
return new CountOperation(this, Helenus.resolve(dsl));
}
public UpdateOperation<ResultSet> update() {
return new UpdateOperation<ResultSet>(this);
public <V> UpdateOperation update() {
return new UpdateOperation(this);
}
public <E> UpdateOperation<E> update(Object pojo) {
if (pojo instanceof MapExportable == false) {
throw new HelenusMappingException(
"update of objects that don't implement MapExportable is not yet supported");
}
return new UpdateOperation<E>(this, pojo);
}
public <E> UpdateOperation<E> update(Drafted<E> drafted) {
if (drafted instanceof AbstractEntityDraft == false) {
throw new HelenusMappingException(
"update of draft objects that don't inherit from AbstractEntityDraft is not yet supported");
}
AbstractEntityDraft<E> draft = (AbstractEntityDraft<E>) drafted;
UpdateOperation update = new UpdateOperation<E>(this, draft);
Map<String, Object> map = draft.toMap();
Set<String> mutatedProperties = draft.mutated();
HelenusEntity entity = Helenus.entity(draft.getEntityClass());
// Add all the mutated values contained in the draft.
entity
.getOrderedProperties()
.forEach(
property -> {
switch (property.getColumnType()) {
case PARTITION_KEY:
case CLUSTERING_COLUMN:
break;
default:
String propertyName = property.getPropertyName();
if (mutatedProperties.contains(propertyName)) {
Object value = map.get(propertyName);
Getter<Object> getter =
new Getter<Object>() {
@Override
public Object get() {
throw new DslPropertyException(
new HelenusPropertyNode(property, Optional.empty()));
}
};
update.set(getter, value);
}
}
});
// Add the partition and clustering keys if they were in the draft (normally the
// case).
entity
.getOrderedProperties()
.forEach(
property -> {
switch (property.getColumnType()) {
case PARTITION_KEY:
case CLUSTERING_COLUMN:
String propertyName = property.getPropertyName();
Object value = map.get(propertyName);
Getter<Object> getter =
new Getter<Object>() {
@Override
public Object get() {
throw new DslPropertyException(
new HelenusPropertyNode(property, Optional.empty()));
}
};
update.where(getter, eq(value));
}
});
return update;
}
public <V> UpdateOperation<ResultSet> update(Getter<V> getter, V v) {
public <V> UpdateOperation update(Getter<V> getter, V v) {
Objects.requireNonNull(getter, "field is empty");
Objects.requireNonNull(v, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter);
return new UpdateOperation<ResultSet>(this, p, v);
return new UpdateOperation(this, p, v);
}
public InsertOperation<ResultSet> insert() {
return new InsertOperation<ResultSet>(this, true);
public InsertOperation insert() {
return new InsertOperation(this, true);
}
public <T> InsertOperation<T> insert(Class<?> resultType) {
return new InsertOperation<T>(this, resultType, true);
}
public <T> InsertOperation<T> insert(T pojo) {
Objects.requireNonNull(
pojo,
"supplied object must be either an instance of the entity class or a dsl for it, but cannot be null");
HelenusEntity entity = null;
try {
entity = Helenus.resolve(pojo);
} catch (HelenusMappingException e) {
}
if (entity != null) {
return new InsertOperation<T>(this, entity, entity.getMappingInterface(), true);
} else {
return this.<T>insert(pojo, null, null);
}
}
public <T> InsertOperation<T> insert(Drafted draft) {
return insert(draft.build(), draft.mutated(), draft.read());
}
private <T> InsertOperation<T> insert(T pojo, Set<String> mutations, Set<String> read) {
public InsertOperation insert(Object pojo) {
Objects.requireNonNull(pojo, "pojo is empty");
Class<?> iface = MappingUtil.getMappingInterface(pojo);
HelenusEntity entity = Helenus.entity(iface);
return new InsertOperation<T>(this, entity, pojo, mutations, read, true);
return new InsertOperation(this, entity, pojo, true);
}
public InsertOperation<ResultSet> upsert() {
return new InsertOperation<ResultSet>(this, false);
public InsertOperation upsert() {
return new InsertOperation(this, false);
}
public <T> InsertOperation<T> upsert(Class<?> resultType) {
return new InsertOperation<T>(this, resultType, false);
}
public <T> InsertOperation<T> upsert(Drafted draft) {
return this.<T>upsert((T) draft.build(), draft.mutated(), draft.read());
}
public <T> InsertOperation<T> upsert(T pojo) {
Objects.requireNonNull(
pojo,
"supplied object must be either an instance of the entity class or a dsl for it, but cannot be null");
HelenusEntity entity = null;
try {
entity = Helenus.resolve(pojo);
} catch (HelenusMappingException e) {
}
if (entity != null) {
return new InsertOperation<T>(this, entity, entity.getMappingInterface(), false);
} else {
return this.<T>upsert(pojo, null, null);
}
}
private <T> InsertOperation<T> upsert(T pojo, Set<String> mutations, Set<String> read) {
public InsertOperation upsert(Object pojo) {
Objects.requireNonNull(pojo, "pojo is empty");
Class<?> iface = MappingUtil.getMappingInterface(pojo);
HelenusEntity entity = Helenus.entity(iface);
return new InsertOperation<T>(this, entity, pojo, mutations, read, false);
return new InsertOperation(this, entity, pojo, false);
}
public DeleteOperation delete() {
@ -733,14 +382,7 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
return session;
}
public <E> E dsl(Class<E> iface) {
return Helenus.dsl(iface, getMetadata());
}
public void close() {
if (session == null) {
return;
}
if (session.isClosed()) {
return;
@ -765,21 +407,23 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
private void dropSchema() {
sessionRepository.entities().forEach(e -> dropEntity(e));
}
private void dropEntity(HelenusEntity entity) {
switch (entity.getType()) {
case TABLE :
execute(SchemaUtil.dropTable(entity));
execute(SchemaUtil.dropTable(entity), true);
break;
case UDT :
execute(SchemaUtil.dropUserType(entity));
execute(SchemaUtil.dropUserType(entity), true);
break;
default:
throw new HelenusException("Unknown entity type.");
}
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -17,12 +16,15 @@
package net.helenus.core;
import java.lang.annotation.Annotation;
import javax.validation.ConstraintValidator;
import net.helenus.mapping.HelenusProperty;
import net.helenus.support.HelenusException;
import net.helenus.support.HelenusMappingException;
public enum HelenusValidator implements PropertyValueValidator {
INSTANCE;
public void validate(HelenusProperty prop, Object value) {
@ -36,13 +38,14 @@ public enum HelenusValidator implements PropertyValueValidator {
try {
valid = typeless.isValid(value, null);
} catch (ClassCastException e) {
throw new HelenusMappingException(
"validator was used for wrong type '" + value + "' in " + prop, e);
throw new HelenusMappingException("validator was used for wrong type '" + value + "' in " + prop, e);
}
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -21,4 +20,5 @@ import java.util.Map;
public interface MapperInstantiator {
<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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,8 +15,10 @@
*/
package net.helenus.core;
import com.datastax.driver.core.Row;
import java.util.function.Function;
import com.datastax.driver.core.Row;
import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.value.ColumnValueProvider;
@ -25,9 +26,10 @@ import net.helenus.support.Fun;
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 HelenusProperty p1;
@ -43,7 +45,7 @@ public final class Mappers {
}
}
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 HelenusProperty p1;
@ -57,22 +59,18 @@ public final class Mappers {
@Override
public Fun.Tuple2<A, B> apply(Row row) {
return new Fun.Tuple2<A, B>(
provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2));
return new Fun.Tuple2<A, B>(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 HelenusProperty p1;
private final HelenusProperty p2;
private final HelenusProperty p3;
public Mapper3(
ColumnValueProvider provider,
HelenusPropertyNode p1,
HelenusPropertyNode p2,
public Mapper3(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
HelenusPropertyNode p3) {
this.provider = provider;
this.p1 = p1.getProperty();
@ -82,14 +80,12 @@ public final class Mappers {
@Override
public Fun.Tuple3<A, B, C> apply(Row row) {
return new Fun.Tuple3<A, B, C>(
provider.getColumnValue(row, 0, p1),
provider.getColumnValue(row, 1, p2),
return new Fun.Tuple3<A, B, C>(provider.getColumnValue(row, 0, p1), 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 HelenusProperty p1;
@ -97,12 +93,8 @@ public final class Mappers {
private final HelenusProperty p3;
private final HelenusProperty p4;
public Mapper4(
ColumnValueProvider provider,
HelenusPropertyNode p1,
HelenusPropertyNode p2,
HelenusPropertyNode p3,
HelenusPropertyNode p4) {
public Mapper4(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
HelenusPropertyNode p3, HelenusPropertyNode p4) {
this.provider = provider;
this.p1 = p1.getProperty();
this.p2 = p2.getProperty();
@ -112,27 +104,18 @@ public final class Mappers {
@Override
public Fun.Tuple4<A, B, C, D> apply(Row row) {
return new Fun.Tuple4<A, B, C, D>(
provider.getColumnValue(row, 0, p1),
provider.getColumnValue(row, 1, p2),
provider.getColumnValue(row, 2, p3),
provider.getColumnValue(row, 3, p4));
return new Fun.Tuple4<A, B, C, D>(provider.getColumnValue(row, 0, p1), 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>
implements Function<Row, Fun.Tuple5<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>> {
private final ColumnValueProvider provider;
private final HelenusProperty p1, p2, p3, p4, p5;
public Mapper5(
ColumnValueProvider provider,
HelenusPropertyNode p1,
HelenusPropertyNode p2,
HelenusPropertyNode p3,
HelenusPropertyNode p4,
HelenusPropertyNode p5) {
public Mapper5(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5) {
this.provider = provider;
this.p1 = p1.getProperty();
this.p2 = p2.getProperty();
@ -143,29 +126,19 @@ public final class Mappers {
@Override
public Fun.Tuple5<A, B, C, D, E> apply(Row row) {
return new Fun.Tuple5<A, B, C, D, E>(
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));
return new Fun.Tuple5<A, B, C, D, E>(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));
}
}
public static final class Mapper6<A, B, C, D, E, F>
implements Function<Row, Fun.Tuple6<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>> {
private final ColumnValueProvider provider;
private final HelenusProperty p1, p2, p3, p4, p5, p6;
public Mapper6(
ColumnValueProvider provider,
HelenusPropertyNode p1,
HelenusPropertyNode p2,
HelenusPropertyNode p3,
HelenusPropertyNode p4,
HelenusPropertyNode p5,
HelenusPropertyNode p6) {
public Mapper6(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5, HelenusPropertyNode p6) {
this.provider = provider;
this.p1 = p1.getProperty();
this.p2 = p2.getProperty();
@ -177,30 +150,20 @@ public final class Mappers {
@Override
public Fun.Tuple6<A, B, C, D, E, F> apply(Row row) {
return new Fun.Tuple6<A, B, C, D, E, F>(
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),
return new Fun.Tuple6<A, B, C, D, E, F>(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));
}
}
public static final class Mapper7<A, B, C, D, E, F, G>
implements Function<Row, Fun.Tuple7<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>> {
private final ColumnValueProvider provider;
private final HelenusProperty p1, p2, p3, p4, p5, p6, p7;
public Mapper7(
ColumnValueProvider provider,
HelenusPropertyNode p1,
HelenusPropertyNode p2,
HelenusPropertyNode p3,
HelenusPropertyNode p4,
HelenusPropertyNode p5,
HelenusPropertyNode p6,
public Mapper7(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5, HelenusPropertyNode p6,
HelenusPropertyNode p7) {
this.provider = provider;
this.p1 = p1.getProperty();
@ -214,14 +177,11 @@ public final class Mappers {
@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));
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -20,6 +19,7 @@ import java.util.HashMap;
import java.util.Map;
public enum Operator {
EQ("=="),
IN("in"),
@ -32,7 +32,9 @@ public enum Operator {
LTE("<=");
private static final Map<String, Operator> indexByName = new HashMap<String, Operator>();
private final String name;
private final static Map<String, Operator> indexByName = new HashMap<String, Operator>();
static {
for (Operator fo : Operator.values()) {
@ -40,17 +42,16 @@ public enum Operator {
}
}
private final String name;
private Operator(String 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;
import java.util.Objects;
import com.datastax.driver.core.querybuilder.Ordering;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import java.util.Objects;
import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.ColumnType;
import net.helenus.mapping.MappingUtil;
@ -32,13 +34,16 @@ public final class Ordered {
}
switch (direction) {
case ASC :
return QueryBuilder.asc(propNode.getColumnName());
case DESC :
return QueryBuilder.desc(propNode.getColumnName());
}
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -18,6 +17,7 @@ package net.helenus.core;
import com.datastax.driver.core.querybuilder.Clause;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.value.ColumnValuePreparer;
import net.helenus.support.HelenusMappingException;
@ -39,9 +39,10 @@ public final class Postulate<V> {
public Clause getClause(HelenusPropertyNode node, ColumnValuePreparer valuePreparer) {
switch (operator) {
case EQ :
return QueryBuilder.eq(
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
return QueryBuilder.eq(node.getColumnName(),
valuePreparer.prepareColumnValue(values[0], node.getProperty()));
case IN :
Object[] preparedValues = new Object[values.length];
@ -51,28 +52,25 @@ public final class Postulate<V> {
return QueryBuilder.in(node.getColumnName(), preparedValues);
case LT :
return QueryBuilder.lt(
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
return QueryBuilder.lt(node.getColumnName(),
valuePreparer.prepareColumnValue(values[0], node.getProperty()));
case LTE :
return QueryBuilder.lte(
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
return QueryBuilder.lte(node.getColumnName(),
valuePreparer.prepareColumnValue(values[0], node.getProperty()));
case GT :
return QueryBuilder.gt(
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
return QueryBuilder.gt(node.getColumnName(),
valuePreparer.prepareColumnValue(values[0], node.getProperty()));
case GTE :
return QueryBuilder.gte(
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
return QueryBuilder.gte(node.getColumnName(),
valuePreparer.prepareColumnValue(values[0], node.getProperty()));
default :
throw new HelenusMappingException("unknown filter operation " + operator);
}
}
public V[] values() {
return values;
}
@Override
@ -94,8 +92,11 @@ public final class Postulate<V> {
b.append(String.valueOf(values[i]));
}
return b.append(')').toString();
}
return operator.getName() + values[0];
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -21,4 +20,5 @@ import net.helenus.mapping.HelenusProperty;
public interface PropertyValueValidator {
void validate(HelenusProperty prop, Object value);
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,17 +15,24 @@
*/
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.Map;
import java.util.Objects;
import com.datastax.driver.core.querybuilder.BindMarker;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import net.helenus.mapping.OrderingDirection;
/** Sugar methods for the queries */
/**
* Sugar methods for the queries
*
*/
public final class Query {
private Query() {}
private Query() {
}
public static BindMarker marker() {
return QueryBuilder.bindMarker();
@ -77,6 +83,7 @@ public final class Query {
public V get() {
return listGetter.get().get(index);
}
};
}
@ -90,6 +97,8 @@ public final class Query {
public V get() {
return mapGetter.get().get(k);
}
};
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,25 +15,24 @@
*/
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.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.ColumnType;
import net.helenus.mapping.annotation.ClusteringColumn;
import net.helenus.mapping.type.OptionalColumnMetadata;
import net.helenus.support.CqlUtil;
import net.helenus.support.HelenusMappingException;
public final class SchemaUtil {
private SchemaUtil() {}
private SchemaUtil() {
}
public static RegularStatement use(String keyspace, boolean forceQuote) {
if (forceQuote) {
@ -57,31 +55,23 @@ public final class SchemaUtil {
ColumnType columnType = prop.getColumnType();
if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
throw new HelenusMappingException(
"primary key columns are not supported in UserDefinedType for "
+ prop.getPropertyName()
+ " in entity "
+ entity);
throw new HelenusMappingException("primary key columns are not supported in UserDefinedType for "
+ prop.getPropertyName() + " in entity " + entity);
}
try {
prop.getDataType().addColumn(create, prop.getColumnName());
} catch (IllegalArgumentException e) {
throw new HelenusMappingException(
"invalid column name '"
+ prop.getColumnName()
+ "' in entity '"
+ entity.getName().getName()
+ "'",
e);
throw new HelenusMappingException("invalid column name '" + prop.getColumnName() + "' in entity '"
+ entity.getName().getName() + "'", e);
}
}
return create;
}
public static List<SchemaStatement> alterUserType(
UserType userType, HelenusEntity entity, boolean dropUnusedColumns) {
public static List<SchemaStatement> alterUserType(UserType userType, HelenusEntity entity,
boolean dropUnusedColumns) {
if (entity.getType() != HelenusEntityType.UDT) {
throw new HelenusMappingException("expected UDT entity " + entity);
@ -90,13 +80,13 @@ public final class SchemaUtil {
List<SchemaStatement> result = new ArrayList<SchemaStatement>();
/**
* TODO: In future replace SchemaBuilder.alterTable by SchemaBuilder.alterType when it will
* exist
* TODO: In future replace SchemaBuilder.alterTable by SchemaBuilder.alterType
* when it will exist
*/
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
final Set<String> visitedColumns =
dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
final Set<String> visitedColumns = dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
for (HelenusProperty prop : entity.getOrderedProperties()) {
@ -113,13 +103,13 @@ public final class SchemaUtil {
}
DataType dataType = userType.getFieldType(columnName);
SchemaStatement stmt =
prop.getDataType()
.alterColumn(alter, prop.getColumnName(), optional(columnName, dataType));
SchemaStatement stmt = prop.getDataType().alterColumn(alter, prop.getColumnName(),
optional(columnName, dataType));
if (stmt != null) {
result.add(stmt);
}
}
if (dropUnusedColumns) {
@ -127,11 +117,13 @@ public final class SchemaUtil {
if (!visitedColumns.contains(field)) {
result.add(alter.dropColumn(field));
}
}
}
return result;
}
public static SchemaStatement dropUserType(HelenusEntity entity) {
@ -141,6 +133,7 @@ public final class SchemaUtil {
}
return SchemaBuilder.dropType(entity.getName().toCql()).ifExists();
}
public static SchemaStatement dropUserType(UserType type) {
@ -148,100 +141,6 @@ public final class SchemaUtil {
return SchemaBuilder.dropType(type.getTypeName()).ifExists();
}
public static String createPrimaryKeyPhrase(Collection<HelenusProperty> properties) {
List<String> p = new ArrayList<String>(properties.size());
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) {
@ -267,19 +166,20 @@ public final class SchemaUtil {
}
prop.getDataType().addColumn(create, prop.getColumnName());
}
if (!clusteringColumns.isEmpty()) {
Options options = create.withOptions();
clusteringColumns.forEach(
p -> options.clusteringOrder(p.getColumnName().toCql(), mapDirection(p.getOrdering())));
clusteringColumns
.forEach(p -> options.clusteringOrder(p.getColumnName().toCql(), mapDirection(p.getOrdering())));
}
return create;
}
public static List<SchemaStatement> alterTable(
TableMetadata tmd, HelenusEntity entity, boolean dropUnusedColumns) {
public static List<SchemaStatement> alterTable(TableMetadata tmd, HelenusEntity entity, boolean dropUnusedColumns) {
if (entity.getType() != HelenusEntityType.TABLE) {
throw new HelenusMappingException("expected table entity " + entity);
@ -289,8 +189,7 @@ public final class SchemaUtil {
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
final Set<String> visitedColumns =
dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
final Set<String> visitedColumns = dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
for (HelenusProperty prop : entity.getOrderedProperties()) {
@ -307,12 +206,13 @@ public final class SchemaUtil {
}
ColumnMetadata columnMetadata = tmd.getColumn(columnName);
SchemaStatement stmt =
prop.getDataType().alterColumn(alter, prop.getColumnName(), optional(columnMetadata));
SchemaStatement stmt = prop.getDataType().alterColumn(alter, prop.getColumnName(),
optional(columnMetadata));
if (stmt != null) {
result.add(stmt);
}
}
if (dropUnusedColumns) {
@ -320,6 +220,7 @@ public final class SchemaUtil {
if (!visitedColumns.contains(cm.getName())) {
result.add(alter.dropColumn(cm.getName()));
}
}
}
@ -334,11 +235,12 @@ public final class SchemaUtil {
}
return SchemaBuilder.dropTable(entity.getName().toCql()).ifExists();
}
public static SchemaStatement createIndex(HelenusProperty prop) {
if (prop.caseSensitiveIndex()) {
return SchemaBuilder.createIndex(indexName(prop))
return SchemaBuilder.createIndex(prop.getIndexName().get().toCql())
.ifNotExists()
.onTable(prop.getEntity().getName().toCql())
.andColumn(prop.getColumnName().toCql());
@ -352,28 +254,20 @@ public final class SchemaUtil {
public static List<SchemaStatement> createIndexes(HelenusEntity entity) {
return entity
.getOrderedProperties()
.stream()
.filter(p -> p.getIndexName().isPresent())
.map(p -> SchemaUtil.createIndex(p))
.collect(Collectors.toList());
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) {
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();
final Set<String> visitedColumns = dropUnusedIndexes ? new HashSet<String>() : Collections.<String>emptySet();
entity.getOrderedProperties().stream().filter(p -> p.getIndexName().isPresent()).forEach(p -> {
entity
.getOrderedProperties()
.stream()
.filter(p -> p.getIndexName().isPresent())
.forEach(
p -> {
String columnName = p.getColumnName().getName();
if (dropUnusedIndexes) {
@ -390,24 +284,25 @@ public final class SchemaUtil {
} else {
list.add(createIndex(p));
}
});
if (dropUnusedIndexes) {
tmd.getColumns()
.stream()
.filter(c -> tmd.getIndex(c.getName()) != null && !visitedColumns.contains(c.getName()))
.forEach(
c -> {
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();
return SchemaBuilder.dropIndex(prop.getIndexName().get().toCql()).ifExists();
}
private static SchemaBuilder.Direction mapDirection(OrderingDirection o) {
@ -424,11 +319,9 @@ public final class SchemaUtil {
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.getPropertyName() + "' type is '" + prop.getJavaType() + "' in the entity "
+ prop.getEntity());
}
private static OptionalColumnMetadata optional(final ColumnMetadata columnMetadata) {
@ -444,6 +337,7 @@ public final class SchemaUtil {
public DataType getType() {
return columnMetadata.getType();
}
};
}
return null;
@ -462,13 +356,10 @@ public final class SchemaUtil {
public DataType getType() {
return dataType;
}
};
}
return null;
}
private static String indexName(HelenusProperty prop) {
return prop.getEntity().getName().toCql() + "_" + prop.getIndexName().get().toCql();
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -19,50 +18,39 @@ package net.helenus.core;
import com.codahale.metrics.MetricRegistry;
import com.datastax.driver.core.*;
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.PrintStream;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
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 {
private final Session session;
private final List<Either<Object, Class<?>>> initList = new ArrayList<Either<Object, Class<?>>>();
private CodecRegistry registry;
private MetricRegistry metricRegistry;
private String usingKeyspace;
private boolean showCql = false;
private boolean showValues = true;
private ConsistencyLevel consistencyLevel;
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) {
this.session = session;
this.usingKeyspace = keyspace;
if (session != null) {
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");
@ -70,6 +58,9 @@ public final class SessionInitializer extends AbstractSessionOperations {
this.sessionRepository = new SessionRepositoryBuilder(session);
}
@Override
public void cache(String key, Object value) { }
@Override
public Session currentSession() {
return session;
@ -110,53 +101,6 @@ public final class SessionInitializer extends AbstractSessionOperations {
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;
@ -173,6 +117,12 @@ public final class SessionInitializer extends AbstractSessionOperations {
return this;
}
public SessionInitializer withMetricsRegistry(MetricRegistry metricRegistry) {
Objects.requireNonNull(metricRegistry, "empty registry");
this.metricRegistry = metricRegistry;
return this;
}
public SessionInitializer withCachingExecutor() {
this.executor = Executors.newCachedThreadPool();
return this;
@ -200,13 +150,8 @@ public final class SessionInitializer extends AbstractSessionOperations {
public SessionInitializer addPackage(String packageName) {
try {
PackageUtil.getClasses(packageName)
.stream()
.filter(c -> c.isInterface() && !c.isAnnotation())
.forEach(
clazz -> {
initList.add(Either.right(clazz));
});
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);
}
@ -218,7 +163,7 @@ public final class SessionInitializer extends AbstractSessionOperations {
int len = dsls.length;
for (int i = 0; i != len; ++i) {
Object obj = Objects.requireNonNull(dsls[i], "element " + i + " is empty");
initList.add(Either.left(obj));
initList.add(obj);
}
return this;
}
@ -249,10 +194,8 @@ public final class SessionInitializer extends AbstractSessionOperations {
}
public SessionInitializer use(String keyspace) {
if (session != null) {
session.execute(SchemaUtil.use(keyspace, false));
this.usingKeyspace = keyspace;
}
return this;
}
@ -263,128 +206,62 @@ public final class SessionInitializer extends AbstractSessionOperations {
}
public void singleton() {
Helenus.setSession(get());
}
public synchronized HelenusSession get() {
initialize();
return new HelenusSession(
session,
usingKeyspace,
registry,
showCql,
showValues,
printStream,
sessionRepository,
executor,
autoDdl == AutoDdl.CREATE_DROP,
consistencyLevel,
idempotent,
cacheManager,
metricRegistry);
return new HelenusSession(session, usingKeyspace, registry, showCql, printStream, sessionRepository, executor,
autoDdl == AutoDdl.CREATE_DROP, metricRegistry);
}
private void initialize() {
Objects.requireNonNull(usingKeyspace, "please define keyspace by 'use' operator");
initList.forEach(
(either) -> {
Class<?> iface = null;
if (either.isLeft()) {
iface = MappingUtil.getMappingInterface(either.getLeft());
} else {
iface = either.getRight();
}
DslExportable dsl = (DslExportable) Helenus.dsl(iface);
if (session != null) {
dsl.setCassandraMetadataForHelenusSession(session.getCluster().getMetadata());
}
if (sessionRepository != null) {
sessionRepository.add(dsl);
}
});
if (session == null) return;
initList.forEach(dsl -> sessionRepository.add(dsl));
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)
// 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!)
// 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)
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)
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)
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();
@ -392,43 +269,42 @@ public final class SessionInitializer extends AbstractSessionOperations {
for (UserType userType : km.getUserTypes()) {
sessionRepository.addUserType(userType.getTypeName(), userType);
}
}
private void eachUserTypeInOrder(
UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) {
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 -> {
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) {
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);
deque.stream().forEach(e -> {action.accept(e); });
/*
Set<HelenusEntity> processedSet = new HashSet<HelenusEntity>();
Set<HelenusEntity> stack = new HashSet<HelenusEntity>();
sessionRepository.entities().stream()
.filter(e -> e.getType() == HelenusEntityType.UDT)
.collect(Collectors.toCollection(ArrayDeque::new))
.descendingIterator()
.forEachRemaining(e -> {
stack.clear();
eachUserTypeInRecursion(e, processedSet, stack, userTypeOps, action);
});
*/
}
private void eachUserTypeInRecursion(
HelenusEntity e,
Set<HelenusEntity> processedSet,
Set<HelenusEntity> stack,
UserTypeOperations userTypeOps,
Consumer<? super HelenusEntity> action) {
private void eachUserTypeInRecursion(HelenusEntity e, Set<HelenusEntity> processedSet, Set<HelenusEntity> stack,
UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) {
stack.add(e);
@ -445,18 +321,19 @@ public final class SessionInitializer extends AbstractSessionOperations {
action.accept(e);
processedSet.add(e);
}
}
private KeyspaceMetadata getKeyspaceMetadata() {
if (keyspaceMetadata == null) {
keyspaceMetadata =
session.getCluster().getMetadata().getKeyspace(usingKeyspace.toLowerCase());
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) {

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,9 +15,11 @@
*/
package net.helenus.core;
import java.util.Collection;
import com.datastax.driver.core.UserType;
import com.google.common.collect.ImmutableMap;
import java.util.Collection;
import net.helenus.mapping.HelenusEntity;
public final class SessionRepository {
@ -31,8 +32,7 @@ public final class SessionRepository {
userTypeMap = ImmutableMap.<String, UserType>builder().putAll(builder.getUserTypeMap()).build();
entityMap =
ImmutableMap.<Class<?>, HelenusEntity>builder().putAll(builder.getEntityMap()).build();
entityMap = ImmutableMap.<Class<?>, HelenusEntity>builder().putAll(builder.getEntityMap()).build();
}
public UserType findUserType(String name) {
@ -42,4 +42,5 @@ public final class SessionRepository {
public Collection<HelenusEntity> entities() {
return entityMap.values();
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,15 +15,17 @@
*/
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.UDTValue;
import com.datastax.driver.core.UserType;
import com.google.common.collect.HashMultimap;
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.HelenusEntityType;
import net.helenus.mapping.HelenusProperty;
@ -34,8 +35,7 @@ import net.helenus.support.HelenusMappingException;
public final class SessionRepositoryBuilder {
private static final Optional<HelenusEntityType> OPTIONAL_UDT =
Optional.of(HelenusEntityType.UDT);
private static final Optional<HelenusEntityType> OPTIONAL_UDT = Optional.of(HelenusEntityType.UDT);
private final Map<Class<?>, HelenusEntity> entityMap = new HashMap<Class<?>, HelenusEntity>();
@ -45,6 +45,7 @@ public final class SessionRepositoryBuilder {
private final Session session;
SessionRepositoryBuilder(Session session) {
this.session = session;
}
@ -84,6 +85,7 @@ public final class SessionRepositoryBuilder {
if (concurrentEntity == null) {
addUserDefinedTypes(entity.getOrderedProperties());
}
}
public HelenusEntity add(Object dsl, Optional<HelenusEntityType> type) {
@ -99,8 +101,7 @@ public final class SessionRepositoryBuilder {
entity = helenusEntity;
if (type.isPresent() && entity.getType() != type.get()) {
throw new HelenusMappingException(
"unexpected entity type " + entity.getType() + " for " + entity);
throw new HelenusMappingException("unexpected entity type " + entity.getType() + " for " + entity);
}
HelenusEntity concurrentEntity = entityMap.putIfAbsent(iface, entity);
@ -110,6 +111,7 @@ public final class SessionRepositoryBuilder {
} else {
entity = concurrentEntity;
}
}
return entity;
@ -138,8 +140,13 @@ public final class SessionRepositoryBuilder {
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,9 +15,11 @@
*/
package net.helenus.core;
import java.util.List;
import com.datastax.driver.core.TableMetadata;
import com.datastax.driver.core.schemabuilder.SchemaStatement;
import java.util.List;
import net.helenus.mapping.HelenusEntity;
import net.helenus.support.HelenusException;
@ -28,30 +29,31 @@ public final class TableOperations {
private final boolean dropUnusedColumns;
private final boolean dropUnusedIndexes;
public TableOperations(
AbstractSessionOperations sessionOps, boolean dropUnusedColumns, boolean dropUnusedIndexes) {
public TableOperations(AbstractSessionOperations sessionOps, boolean dropUnusedColumns, boolean dropUnusedIndexes) {
this.sessionOps = sessionOps;
this.dropUnusedColumns = dropUnusedColumns;
this.dropUnusedIndexes = dropUnusedIndexes;
}
public void createTable(HelenusEntity entity) {
sessionOps.execute(SchemaUtil.createTable(entity));
sessionOps.execute(SchemaUtil.createTable(entity), true);
executeBatch(SchemaUtil.createIndexes(entity));
}
public void dropTable(HelenusEntity entity) {
sessionOps.execute(SchemaUtil.dropTable(entity));
sessionOps.execute(SchemaUtil.dropTable(entity), true);
}
public void validateTable(TableMetadata tmd, HelenusEntity entity) {
if (tmd == null) {
throw new HelenusException(
"table does not exists "
+ entity.getName()
+ "for entity "
+ entity.getMappingInterface());
"table not exists " + entity.getName() + "for entity " + entity.getMappingInterface());
}
List<SchemaStatement> list = SchemaUtil.alterTable(tmd, entity, dropUnusedColumns);
@ -60,37 +62,12 @@ public final class TableOperations {
if (!list.isEmpty()) {
throw new HelenusException(
"schema changed for entity "
+ entity.getMappingInterface()
+ ", apply this command: "
+ list);
"schema changed for entity " + entity.getMappingInterface() + ", apply this command: " + list);
}
}
public void updateTable(TableMetadata tmd, HelenusEntity entity) {
if (tmd == null) {
createTable(entity);
return;
}
executeBatch(SchemaUtil.alterTable(tmd, entity, dropUnusedColumns));
executeBatch(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
}
public void createView(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) {
sessionOps.execute(
SchemaUtil.dropMaterializedView(
sessionOps.usingKeyspace(), entity.getName().toCql(), entity));
}
public void updateView(TableMetadata tmd, HelenusEntity entity) {
if (tmd == null) {
createTable(entity);
return;
@ -102,6 +79,10 @@ public final class TableOperations {
private void executeBatch(List<SchemaStatement> list) {
list.forEach(s -> sessionOps.execute(s));
list.forEach(s -> {
sessionOps.execute(s, true);
});
}
}

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;
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.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;
import net.helenus.core.cache.MapCache;
import net.helenus.core.operation.AbstractOperation;
import net.helenus.core.operation.BatchOperation;
import net.helenus.mapping.MappingUtil;
import net.helenus.support.CheckedRunnable;
import net.helenus.support.Either;
import net.helenus.support.HelenusException;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Encapsulates the concept of a "transaction" as a unit-of-work.
*/
public class UnitOfWork {
/** 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);
private final HelenusSession session;
private ArrayList<UnitOfWork> nested;
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);
}
UnitOfWork(HelenusSession session) {
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);
}
// log.record(txn::start)
}
/**
* Marks the beginning of a transactional section of work. Will write a
* recordCacheAndDatabaseOperationCount to the shared write-ahead log.
* 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 synchronized UnitOfWork begin() {
elapsedTime.start();
// log.record(txn::start)
return this;
public UnitOfWork begin() {
if (nested == null) {
nested = new ArrayList<UnitOfWork>();
}
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();
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.
* 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.
* @throws ConflictingUnitOfWorkException
* 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);
}
}
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 abort the work within this unit of work. Any nested aborted unit of work will
* trigger the entire unit of work to commit.
* Explicitly discard the work and mark it as as such in the log.
*/
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...
public void abort() {
// 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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,9 +15,11 @@
*/
package net.helenus.core;
import java.util.List;
import com.datastax.driver.core.UserType;
import com.datastax.driver.core.schemabuilder.SchemaStatement;
import java.util.List;
import net.helenus.mapping.HelenusEntity;
import net.helenus.support.HelenusException;
@ -34,12 +35,14 @@ public final class UserTypeOperations {
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));
sessionOps.execute(SchemaUtil.dropUserType(entity), true);
}
public void validateUserType(UserType userType, HelenusEntity entity) {
@ -53,11 +56,9 @@ public final class UserTypeOperations {
if (!list.isEmpty()) {
throw new HelenusException(
"schema changed for entity "
+ entity.getMappingInterface()
+ ", apply this command: "
+ list);
"schema changed for entity " + entity.getMappingInterface() + ", apply this command: " + list);
}
}
public void updateUserType(UserType userType, HelenusEntity entity) {
@ -68,10 +69,15 @@ public final class UserTypeOperations {
}
executeBatch(SchemaUtil.alterUserType(userType, entity, dropUnusedColumns));
}
private void executeBatch(List<SchemaStatement> list) {
list.forEach(s -> sessionOps.execute(s));
list.forEach(s -> {
sessionOps.execute(s, true);
});
}
}

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;
import java.lang.annotation.ElementType;
@ -23,4 +7,5 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@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;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeoutException;
import net.helenus.core.ConflictingUnitOfWorkException;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Retry {
Class<? extends Exception>[] on() default {
ConflictingUnitOfWorkException.class, TimeoutException.class
};
Class<? extends Exception>[] on() default ConflictingUnitOfWorkException.class;
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.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;
@ -13,6 +13,8 @@ import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import net.helenus.core.annotation.Retry;
@Aspect
public class RetryConcurrentUnitOfWorkAspect {
@ -37,8 +39,8 @@ public class RetryConcurrentUnitOfWorkAspect {
return tryProceeding(pjp, times, retryOn);
}
private Object tryProceeding(
ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn) throws Throwable {
private Object tryProceeding(ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn)
throws Throwable {
try {
return proceed(pjp);
} catch (Throwable throwable) {

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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,15 +15,14 @@
*/
package net.helenus.core.operation;
import java.util.*;
import java.util.LinkedList;
import java.util.List;
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>>
extends AbstractOperation<E, O> {
extends
AbstractOperation<E, O> {
protected List<Filter<?>> filters = null;
protected List<Filter<?>> ifFilters = null;
@ -110,59 +108,4 @@ public abstract class AbstractFilterOperation<E, O extends AbstractFilterOperati
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,18 +15,16 @@
*/
package net.helenus.core.operation;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import net.helenus.core.*;
import net.helenus.mapping.HelenusProperty;
public abstract class AbstractFilterOptionalOperation<
E, O extends AbstractFilterOptionalOperation<E, O>>
extends AbstractOptionalOperation<E, O> {
public abstract class AbstractFilterOptionalOperation<E, O extends AbstractFilterOptionalOperation<E, O>>
extends
AbstractOptionalOperation<E, O> {
protected Map<HelenusProperty, Filter<?>> filters = null;
protected List<Filter<?>> filters = null;
protected List<Filter<?>> ifFilters = null;
public AbstractFilterOptionalOperation(AbstractSessionOperations sessionOperations) {
@ -99,9 +96,9 @@ public abstract class AbstractFilterOptionalOperation<
private void addFilter(Filter<?> filter) {
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) {
@ -110,4 +107,5 @@ public abstract class AbstractFilterOptionalOperation<
}
ifFilters.add(filter);
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,18 +15,15 @@
*/
package net.helenus.core.operation;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import net.helenus.core.*;
import net.helenus.mapping.HelenusProperty;
public abstract class AbstractFilterStreamOperation<
E, O extends AbstractFilterStreamOperation<E, O>>
import net.helenus.core.*;
public abstract class AbstractFilterStreamOperation<E, O extends AbstractFilterStreamOperation<E, O>>
extends AbstractStreamOperation<E, O> {
protected Map<HelenusProperty, Filter<?>> filters = null;
protected List<Filter<?>> filters = null;
protected List<Filter<?>> ifFilters = null;
public AbstractFilterStreamOperation(AbstractSessionOperations sessionOperations) {
@ -43,7 +39,7 @@ public abstract class AbstractFilterStreamOperation<
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;
}
@ -64,7 +60,7 @@ public abstract class AbstractFilterStreamOperation<
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;
}
@ -85,7 +81,7 @@ public abstract class AbstractFilterStreamOperation<
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;
}
@ -99,9 +95,9 @@ public abstract class AbstractFilterStreamOperation<
private void addFilter(Filter<?> filter) {
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) {
@ -110,4 +106,5 @@ public abstract class AbstractFilterStreamOperation<
}
ifFilters.add(filter);
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,76 +15,106 @@
*/
package net.helenus.core.operation;
import com.codahale.metrics.Timer;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ResultSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeoutException;
import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.UnitOfWork;
import com.datastax.driver.core.ResultSetFuture;
import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>>
extends AbstractStatementOperation<E, O> {
import net.helenus.core.AbstractSessionOperations;
import net.helenus.support.Fun;
import net.helenus.support.Scala;
import scala.concurrent.Future;
public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>> extends AbstractStatementOperation<E, O> {
public abstract E transform(ResultSet resultSet);
public boolean cacheable() {
return false;
}
public String getCacheKey() {
return "";
}
public AbstractOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations);
}
public abstract E transform(ResultSet resultSet);
public PreparedOperation<E> prepare() {
return new PreparedOperation<E>(prepareStatement(), this);
}
public E sync() throws TimeoutException {
final Timer.Context context = requestLatency.time();
try {
ResultSet resultSet =
this.execute(
sessionOps, null, queryExecutionTimeout, queryTimeoutUnits, showValues, false);
return transform(resultSet);
} finally {
context.stop();
}
public ListenableFuture<PreparedOperation<E>> prepareAsync() {
final O _this = (O) this;
return Futures.transform(prepareStatementAsync(), new Function<PreparedStatement, PreparedOperation<E>>() {
@Override
public PreparedOperation<E> apply(PreparedStatement preparedStatement) {
return new PreparedOperation<E>(preparedStatement, _this);
}
public E sync(UnitOfWork uow) throws TimeoutException {
if (uow == null) return sync();
});
final Timer.Context context = requestLatency.time();
try {
ResultSet resultSet =
execute(sessionOps, uow, queryExecutionTimeout, queryTimeoutUnits, showValues, true);
}
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;
} finally {
context.stop();
}
}
public CompletableFuture<E> async() {
return CompletableFuture.<E>supplyAsync(
() -> {
try {
return sync();
} catch (TimeoutException ex) {
throw new CompletionException(ex);
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);
}
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);
}, sessionOps.getExecutor());
return future;
}
});
uow.addFuture(f);
return f;
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);
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,32 +15,25 @@
*/
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.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
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.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.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 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>>
extends AbstractStatementOperation<E, O> {
extends
AbstractStatementOperation<E, O> {
public AbstractOptionalOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations);
@ -54,202 +46,87 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
}
public ListenableFuture<PreparedOptionalOperation<E>> prepareAsync() {
final O _this = (O) this;
return Futures.transform(
prepareStatementAsync(),
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 Timer.Context context = requestLatency.time();
try {
Optional<E> result = Optional.empty();
E cacheResult = null;
boolean updateCache = isSessionCacheable() && !ignoreCache();
public Future<PreparedOptionalOperation<E>> prepareFuture() {
return Scala.asFuture(prepareAsync());
}
if (updateCache) {
List<Facet> facets = bindFacetValues();
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();
public Optional<E> sync() {
ResultSet resultSet = sessionOps.executeAsync(options(buildStatement()), showValues).getUninterruptibly();
return transform(resultSet);
}
public ListenableFuture<Optional<E>> async() {
ResultSetFuture resultSetFuture = sessionOps.executeAsync(options(buildStatement()), showValues);
ListenableFuture<Optional<E>> future = Futures.transform(resultSetFuture,
new Function<ResultSet, Optional<E>>() {
@Override
public Optional<E> apply(ResultSet resultSet) {
return transform(resultSet);
}
}, sessionOps.getExecutor());
return future;
}
public ListenableFuture<Option<E>> asyncForScala() {
ResultSetFuture resultSetFuture = sessionOps.executeAsync(options(buildStatement()), showValues);
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 {
sessionCacheMiss.mark();
cacheMiss.mark();
}
}
} else {
//TODO(gburd): look in statement cache for results
return Option.empty();
}
}
if (!result.isPresent()) {
// Formulate the query and execute it against the Cassandra cluster.
ResultSet resultSet =
this.execute(
sessionOps,
null,
queryExecutionTimeout,
queryTimeoutUnits,
showValues,
isSessionCacheable());
}, sessionOps.getExecutor());
// Transform the query result set into the desired shape.
result = transform(resultSet);
return future;
}
public Future<Option<E>> future() {
return Scala.asFuture(asyncForScala());
}
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 <A> Future<Fun.Tuple2<Option<E>, A>> future(A a) {
return Scala.asFuture(asyncForScala(), a);
}
public Optional<E> sync(UnitOfWork uow) throws TimeoutException {
if (uow == null) return sync();
final Timer.Context context = requestLatency.time();
try {
Optional<E> result = Optional.empty();
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;
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;
public <A, B> Future<Fun.Tuple3<Option<E>, A, B>> future(A a, B b) {
return Scala.asFuture(asyncForScala(), a, b);
}
// Check to see if we fetched the object from the cache
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.
ResultSet resultSet =
execute(sessionOps, uow, queryExecutionTimeout, queryTimeoutUnits, showValues, true);
// Transform the query result set into the desired shape.
result = transform(resultSet);
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);
}
// If we have a result, it wasn't from the UOW cache, and we're caching things
// then we need to put this result into the cache for future requests to find.
if (updateCache && result.isPresent()) {
E r = result.get();
if (!(r instanceof Fun) && r != deleted) {
cacheUpdate(uow, r, getFacets());
}
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);
}
return result;
} finally {
context.stop();
}
}
public CompletableFuture<Optional<E>> async() {
return CompletableFuture.<Optional<E>>supplyAsync(
() -> {
try {
return sync();
} catch (TimeoutException ex) {
throw new CompletionException(ex);
}
});
}
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,6 +15,9 @@
*/
package net.helenus.core.operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.RegularStatement;
@ -26,47 +28,30 @@ import com.datastax.driver.core.policies.FallthroughRetryPolicy;
import com.datastax.driver.core.policies.RetryPolicy;
import com.datastax.driver.core.querybuilder.BuiltStatement;
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.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;
public abstract class AbstractStatementOperation<E, O extends AbstractStatementOperation<E, O>>
extends Operation<E> {
private boolean ignoreCache = false;
import net.helenus.core.AbstractSessionOperations;
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;
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;
this.sessionOps = sessionOperations;
}
public O showValues(boolean enabled) {
@ -90,16 +75,6 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
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;
@ -135,21 +110,6 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
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;
@ -175,16 +135,6 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
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;
@ -206,19 +156,7 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
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) {
protected Statement options(Statement statement) {
if (defaultTimestamp != null) {
statement.setDefaultTimestamp(defaultTimestamp[0]);
@ -246,24 +184,15 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
statement.setFetchSize(fetchSize[0]);
}
if (isIdempotentOperation()) {
statement.setIdempotent(true);
}
return statement;
}
@Override
protected boolean isIdempotentOperation() {
return idempotent;
}
public Statement statement() {
return buildStatement(false);
return buildStatement();
}
public String cql() {
Statement statement = buildStatement(false);
Statement statement = buildStatement();
if (statement == null) return "";
if (statement instanceof BuiltStatement) {
BuiltStatement buildStatement = (BuiltStatement) statement;
@ -275,7 +204,7 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
public PreparedStatement prepareStatement() {
Statement statement = buildStatement(true);
Statement statement = buildStatement();
if (statement instanceof RegularStatement) {
@ -289,68 +218,21 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
public ListenableFuture<PreparedStatement> prepareStatementAsync() {
Statement statement = buildStatement(true);
Statement statement = buildStatement();
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;
public Future<PreparedStatement> prepareStatementFuture() {
return Scala.asFuture(prepareStatementAsync());
}
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,33 +15,24 @@
*/
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.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
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.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.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 org.apache.commons.lang3.SerializationUtils;
import net.helenus.support.Scala;
import scala.concurrent.Future;
public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperation<E, O>>
extends AbstractStatementOperation<E, O> {
extends
AbstractStatementOperation<E, O> {
public AbstractStreamOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations);
@ -55,207 +45,93 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
}
public ListenableFuture<PreparedStreamOperation<E>> prepareAsync() {
final O _this = (O) this;
return Futures.transform(
prepareStatementAsync(),
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 Timer.Context context = requestLatency.time();
try {
Stream<E> resultStream = null;
E cacheResult = null;
boolean updateCache = isSessionCacheable();
if (!ignoreCache() && isSessionCacheable()) {
List<Facet> facets = bindFacetValues();
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) {
resultStream = Stream.of(cacheResult);
updateCache = false;
sessionCacheHits.mark();
cacheHits.mark();
} else {
sessionCacheMiss.mark();
cacheMiss.mark();
}
} else {
//TODO(gburd): look in statement cache for results
}
}
public Future<PreparedStreamOperation<E>> prepareFuture() {
return Scala.asFuture(prepareAsync());
}
if (resultStream == null) {
// Formulate the query and execute it against the Cassandra cluster.
ResultSet resultSet =
this.execute(
sessionOps,
null,
queryExecutionTimeout,
queryTimeoutUnits,
showValues,
isSessionCacheable());
// Transform the query result set into the desired shape.
resultStream = transform(resultSet);
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
}
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);
@Override
public void onFailure(Throwable throwable) {
log.error("Exception in task", throwable);
}
});
}
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);
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);
}
});
uow.addFuture(f);
return f;
}, 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);
}
}

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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -37,12 +36,8 @@ public final class BoundOperation<E> extends AbstractOperation<E, BoundOperation
}
@Override
public Statement buildStatement(boolean cached) {
public Statement buildStatement() {
return boundStatement;
}
@Override
public boolean isSessionCacheable() {
return delegate.isSessionCacheable();
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,19 +15,18 @@
*/
package net.helenus.core.operation;
import java.util.Optional;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Statement;
import java.util.Optional;
public final class BoundOptionalOperation<E>
extends AbstractOptionalOperation<E, BoundOptionalOperation<E>> {
public final class BoundOptionalOperation<E> extends AbstractOptionalOperation<E, BoundOptionalOperation<E>> {
private final BoundStatement boundStatement;
private final AbstractOptionalOperation<E, ?> delegate;
public BoundOptionalOperation(
BoundStatement boundStatement, AbstractOptionalOperation<E, ?> operation) {
public BoundOptionalOperation(BoundStatement boundStatement, AbstractOptionalOperation<E, ?> operation) {
super(operation.sessionOps);
this.boundStatement = boundStatement;
this.delegate = operation;
@ -40,12 +38,8 @@ public final class BoundOptionalOperation<E>
}
@Override
public Statement buildStatement(boolean cached) {
public Statement buildStatement() {
return boundStatement;
}
@Override
public boolean isSessionCacheable() {
return delegate.isSessionCacheable();
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,43 +15,31 @@
*/
package net.helenus.core.operation;
import java.util.stream.Stream;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.ResultSet;
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>
extends AbstractStreamOperation<E, BoundStreamOperation<E>> {
public final class BoundStreamOperation<E> extends AbstractStreamOperation<E, BoundStreamOperation<E>> {
private final BoundStatement boundStatement;
private final AbstractStreamOperation<E, ?> delegate;
public BoundStreamOperation(
BoundStatement boundStatement, AbstractStreamOperation<E, ?> operation) {
public BoundStreamOperation(BoundStatement boundStatement, AbstractStreamOperation<E, ?> operation) {
super(operation.sessionOps);
this.boundStatement = boundStatement;
this.delegate = operation;
}
@Override
public List<Facet> bindFacetValues() {
return delegate.bindFacetValues();
}
@Override
public Stream<E> transform(ResultSet resultSet) {
return delegate.transform(resultSet);
}
@Override
public Statement buildStatement(boolean cached) {
public Statement buildStatement() {
return boundStatement;
}
@Override
public boolean isSessionCacheable() {
return delegate.isSessionCacheable();
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -21,6 +20,7 @@ import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Select.Where;
import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Filter;
import net.helenus.core.reflect.HelenusPropertyNode;
@ -38,11 +38,10 @@ public final class CountOperation extends AbstractFilterOperation<Long, CountOpe
public CountOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
super(sessionOperations);
this.entity = entity;
//TODO(gburd): cache SELECT COUNT results within the scope of a UOW
}
@Override
public BuiltStatement buildStatement(boolean cached) {
public BuiltStatement buildStatement() {
if (filters != null && !filters.isEmpty()) {
filters.forEach(f -> addPropertyNode(f.getNode()));
@ -75,11 +74,9 @@ public final class CountOperation extends AbstractFilterOperation<Long, CountOpe
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());
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -21,15 +20,11 @@ import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.Delete;
import com.datastax.driver.core.querybuilder.Delete.Where;
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.Filter;
import net.helenus.core.UnitOfWork;
import net.helenus.core.cache.Facet;
import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.HelenusEntity;
import net.helenus.support.HelenusException;
import net.helenus.support.HelenusMappingException;
public final class DeleteOperation extends AbstractFilterOperation<ResultSet, DeleteOperation> {
@ -52,7 +47,7 @@ public final class DeleteOperation extends AbstractFilterOperation<ResultSet, De
}
@Override
public BuiltStatement buildStatement(boolean cached) {
public BuiltStatement buildStatement() {
if (filters != null && !filters.isEmpty()) {
filters.forEach(f -> addPropertyNode(f.getNode()));
@ -123,53 +118,8 @@ public final class DeleteOperation extends AbstractFilterOperation<ResultSet, De
if (entity == null) {
entity = p.getEntity();
} else if (entity != p.getEntity()) {
throw new HelenusMappingException(
"you can delete rows only in single entity "
+ entity.getMappingInterface()
+ " or "
+ p.getEntity().getMappingInterface());
throw new HelenusMappingException("you can delete rows only in single entity "
+ 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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,110 +15,59 @@
*/
package net.helenus.core.operation;
import java.util.*;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.Insert;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import java.util.*;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.helenus.core.AbstractSessionOperations;
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.MapExportable;
import net.helenus.mapping.ColumnType;
import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.value.BeanColumnValueProvider;
import net.helenus.support.Fun;
import net.helenus.support.HelenusException;
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 =
new ArrayList<Fun.Tuple2<HelenusPropertyNode, Object>>();
private final T pojo;
private final Class<?> resultType;
private final Set<String> readSet;
private HelenusEntity entity;
private final List<Fun.Tuple2<HelenusPropertyNode, Object>> values = new ArrayList<Fun.Tuple2<HelenusPropertyNode, Object>>();
private boolean ifNotExists;
private int[] ttl;
private long[] timestamp;
private long writeTime = 0L;
public InsertOperation(AbstractSessionOperations sessionOperations, boolean ifNotExists) {
super(sessionOperations);
this.pojo = null;
this.readSet = null;
this.ifNotExists = ifNotExists;
this.resultType = ResultSet.class;
}
public InsertOperation(
AbstractSessionOperations sessionOperations,
HelenusEntity entity,
Class<?> resultType,
public InsertOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity, Object pojo,
boolean ifNotExists) {
super(sessionOperations);
this.pojo = null;
this.readSet = null;
this.ifNotExists = ifNotExists;
this.resultType = resultType;
this.entity = entity;
}
public InsertOperation(
AbstractSessionOperations sessionOperations, Class<?> resultType, boolean ifNotExists) {
super(sessionOperations);
this.pojo = null;
this.readSet = null;
this.ifNotExists = ifNotExists;
this.resultType = resultType;
}
public InsertOperation(
AbstractSessionOperations sessionOperations,
HelenusEntity entity,
T pojo,
Set<String> mutations,
Set<String> read,
boolean ifNotExists) {
super(sessionOperations);
this.pojo = pojo;
this.readSet = read;
this.entity = entity;
this.ifNotExists = ifNotExists;
this.resultType = entity.getMappingInterface();
Set<String> keys = (pojo instanceof MapExportable) ? ((MapExportable)pojo).toMap().keySet() : null;
Collection<HelenusProperty> properties = entity.getOrderedProperties();
Set<String> keys = (mutations == null) ? null : mutations;
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()));
}
// Skip properties that are not in the map of the pojo we're storing. This creates a path
// for entity instances to be {in,up}serted without including all columns in the INSERT statement.
if (keys == null || keys.contains(prop.getPropertyName())) {
if (addProp) {
Object value = BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop);
value = sessionOps.getValuePreparer().prepareColumnValue(value, prop);
@ -127,21 +75,24 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
HelenusPropertyNode node = new HelenusPropertyNode(prop, Optional.empty());
values.add(Fun.Tuple2.of(node, value));
}
}
}
}
public InsertOperation<T> ifNotExists() {
}
}
public InsertOperation ifNotExists() {
this.ifNotExists = true;
return this;
}
public InsertOperation<T> ifNotExists(boolean enable) {
public InsertOperation ifNotExists(boolean enable) {
this.ifNotExists = enable;
return this;
}
public <V> InsertOperation<T> value(Getter<V> getter, V val) {
public <V> InsertOperation value(Getter<V> getter, V val) {
Objects.requireNonNull(getter, "getter is empty");
@ -158,35 +109,12 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
}
@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;
}
public BuiltStatement buildStatement() {
if (values.isEmpty()) return null;
values.forEach(t -> addPropertyNode(t._1));
if (values.isEmpty())
return null;
if (entity == null) {
throw new HelenusMappingException("unknown entity");
@ -198,13 +126,10 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
insert.ifNotExists();
}
values.forEach(
t -> {
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]));
}
@ -215,210 +140,29 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
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");
public ResultSet transform(ResultSet resultSet) {
return resultSet;
}
Class<?> iface = entity.getMappingInterface();
if (resultType == iface) {
T o = newInstance(iface);
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 usingTtl(int ttl) {
this.ttl = new int[1];
this.ttl[0] = ttl;
return this;
}
public InsertOperation<T> usingTimestamp(long timestamp) {
public InsertOperation usingTimestamp(long timestamp) {
this.timestamp = new long[1];
this.timestamp[0] = timestamp;
return this;
}
protected void adjustTtlAndWriteTime(MapExportable pojo) {
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 (ttl != null) {
columnNames.forEach(name -> pojo.put(CacheUtil.ttlKey(name), ttl));
}
if (writeTime != 0L) {
columnNames.forEach(name -> pojo.put(CacheUtil.writeTimeKey(name), writeTime));
}
}
}
}
@Override
protected boolean isIdempotentOperation() {
return values.stream().map(v -> v._1.getProperty()).allMatch(prop -> prop.isIdempotent())
|| super.isIdempotentOperation();
}
@Override
public T sync() throws TimeoutException {
T result = super.sync();
if (entity.isCacheable() && result != null) {
adjustTtlAndWriteTime((MapExportable) result);
sessionOps.updateCache(result, bindFacetValues());
}
return result;
}
@Override
public T sync(UnitOfWork uow) throws TimeoutException {
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 {
if (uow == null) {
throw new HelenusException("UnitOfWork cannot be null when batching operations.");
}
if (this.entity != null) {
Class<?> iface = this.entity.getMappingInterface();
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);
}
@Override
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 (facet instanceof UnboundFacet) {
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
public List<Facet> getFacets() {
if (entity != null) {
return entity.getFacets();
} else {
return new ArrayList<Facet>();
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -44,4 +43,5 @@ public final class PreparedOperation<E> {
public String toString() {
return preparedStatement.getQueryString();
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -24,8 +23,7 @@ public final class PreparedOptionalOperation<E> {
private final PreparedStatement preparedStatement;
private final AbstractOptionalOperation<E, ?> operation;
public PreparedOptionalOperation(
PreparedStatement statement, AbstractOptionalOperation<E, ?> operation) {
public PreparedOptionalOperation(PreparedStatement statement, AbstractOptionalOperation<E, ?> operation) {
this.preparedStatement = statement;
this.operation = operation;
}
@ -45,4 +43,5 @@ public final class PreparedOptionalOperation<E> {
public String toString() {
return preparedStatement.getQueryString();
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -24,8 +23,7 @@ public final class PreparedStreamOperation<E> {
private final PreparedStatement preparedStatement;
private final AbstractStreamOperation<E, ?> operation;
public PreparedStreamOperation(
PreparedStatement statement, AbstractStreamOperation<E, ?> operation) {
public PreparedStreamOperation(PreparedStatement statement, AbstractStreamOperation<E, ?> operation) {
this.preparedStatement = statement;
this.operation = operation;
}
@ -35,7 +33,9 @@ public final class PreparedStreamOperation<E> {
}
public BoundStreamOperation<E> bind(Object... params) {
BoundStatement boundStatement = preparedStatement.bind(params);
return new BoundStreamOperation<E>(boundStatement, operation);
}
@ -43,4 +43,5 @@ public final class PreparedStreamOperation<E> {
public String toString() {
return preparedStatement.getQueryString();
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,57 +15,36 @@
*/
package net.helenus.core.operation;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import net.helenus.core.cache.Facet;
public final class SelectFirstOperation<E>
extends AbstractFilterOptionalOperation<E, SelectFirstOperation<E>> {
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
private final SelectOperation<E> delegate;
public final class SelectFirstOperation<E> extends AbstractFilterOptionalOperation<E, SelectFirstOperation<E>> {
public SelectFirstOperation(SelectOperation<E> delegate) {
super(delegate.sessionOps);
private final SelectOperation<E> src;
this.delegate = delegate;
this.filters = delegate.filters;
this.ifFilters = delegate.ifFilters;
public SelectFirstOperation(SelectOperation<E> src) {
super(src.sessionOps);
this.src = src;
this.filters = src.filters;
this.ifFilters = src.ifFilters;
}
public <R> SelectFirstTransformingOperation<R, E> map(Function<E, R> fn) {
return new SelectFirstTransformingOperation<R, E>(delegate, fn);
return new SelectFirstTransformingOperation<R, E>(src, fn);
}
@Override
public BuiltStatement buildStatement(boolean cached) {
return delegate.buildStatement(cached);
}
@Override
public List<Facet> getFacets() {
return delegate.getFacets();
}
@Override
public List<Facet> bindFacetValues() {
return delegate.bindFacetValues();
public BuiltStatement buildStatement() {
return src.buildStatement();
}
@Override
public Optional<E> transform(ResultSet resultSet) {
return delegate.transform(resultSet).findFirst();
return src.transform(resultSet).findFirst();
}
@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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,50 +15,36 @@
*/
package net.helenus.core.operation;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import net.helenus.core.cache.Facet;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
public final class SelectFirstTransformingOperation<R, E>
extends AbstractFilterOptionalOperation<R, SelectFirstTransformingOperation<R, E>> {
extends
AbstractFilterOptionalOperation<R, SelectFirstTransformingOperation<R, E>> {
private final SelectOperation<E> delegate;
private final SelectOperation<E> src;
private final Function<E, R> fn;
public SelectFirstTransformingOperation(SelectOperation<E> delegate, Function<E, R> fn) {
super(delegate.sessionOps);
public SelectFirstTransformingOperation(SelectOperation<E> src, Function<E, R> fn) {
super(src.sessionOps);
this.delegate = delegate;
this.src = src;
this.fn = fn;
this.filters = delegate.filters;
this.ifFilters = delegate.ifFilters;
this.filters = src.filters;
this.ifFilters = src.ifFilters;
}
@Override
public List<Facet> bindFacetValues() {
return delegate.bindFacetValues();
}
@Override
public BuiltStatement buildStatement(boolean cached) {
return delegate.buildStatement(cached);
public BuiltStatement buildStatement() {
return src.buildStatement();
}
@Override
public Optional<R> transform(ResultSet resultSet) {
return delegate.transform(resultSet).findFirst().map(fn);
return src.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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,6 +15,11 @@
*/
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.Row;
import com.datastax.driver.core.querybuilder.BuiltStatement;
@ -24,47 +28,30 @@ import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Select.Selection;
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.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.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.OrderingDirection;
import net.helenus.mapping.value.ColumnValueProvider;
import net.helenus.mapping.value.ValueProviderMap;
import net.helenus.support.Fun;
import net.helenus.support.HelenusMappingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, SelectOperation<E>> {
private static final Logger LOG = LoggerFactory.getLogger(SelectOperation.class);
protected final List<HelenusPropertyNode> props = new ArrayList<HelenusPropertyNode>();
protected Function<Row, E> rowMapper = null;
protected final List<HelenusPropertyNode> props = new ArrayList<HelenusPropertyNode>();
protected List<Ordering> ordering = null;
protected Integer limit = null;
protected boolean allowFiltering = false;
protected String alternateTableName = null;
protected boolean isCacheable = false;
protected boolean implementsEntityType = false;
@SuppressWarnings("unchecked")
public SelectOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations);
this.rowMapper =
new Function<Row, E>() {
this.rowMapper = new Function<Row, E>() {
@Override
public E apply(Row source) {
@ -80,6 +67,7 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
return (E) Fun.ArrayTuple.of(arr);
}
};
}
@ -87,47 +75,28 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
super(sessionOperations);
entity
.getOrderedProperties()
.stream()
.map(p -> new HelenusPropertyNode(p, Optional.empty()))
entity.getOrderedProperties().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(
AbstractSessionOperations sessionOperations,
HelenusEntity entity,
public SelectOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity,
Function<Row, E> rowMapper) {
super(sessionOperations);
this.rowMapper = rowMapper;
entity
.getOrderedProperties()
.stream()
.map(p -> new HelenusPropertyNode(p, Optional.empty()))
entity.getOrderedProperties().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(
AbstractSessionOperations sessionOperations,
Function<Row, E> rowMapper,
public SelectOperation(AbstractSessionOperations sessionOperations, Function<Row, E> rowMapper,
HelenusPropertyNode... props) {
super(sessionOperations);
this.rowMapper = rowMapper;
Collections.addAll(this.props, props);
HelenusEntity entity = props[0].getEntity();
this.isCacheable = entity.isCacheable();
this.implementsEntityType = Entity.class.isAssignableFrom(entity.getMappingInterface());
}
public CountOperation count() {
@ -138,30 +107,14 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
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());
throw new HelenusMappingException("you can count records only from a single entity "
+ entity.getMappingInterface() + " or " + prop.getEntity().getMappingInterface());
}
}
return new CountOperation(sessionOps, entity);
}
public <V extends E> SelectOperation<E> from(Class<V> materializedViewClass) {
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() {
limit(1);
return new SelectFirstOperation<E>(this);
@ -175,11 +128,11 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
this.rowMapper = null;
return new SelectTransformingOperation<R, E>(
this,
(r) -> {
return new SelectTransformingOperation<R, E>(this, (r) -> {
Map<String, Object> map = new ValueProviderMap(r, sessionOps.getValueProvider(), entity);
return (R) Helenus.map(entityClass, map);
});
}
@ -214,81 +167,23 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
}
@Override
public boolean isSessionCacheable() {
return isCacheable;
}
@Override
public List<Facet> getFacets() {
HelenusEntity entity = props.get(0).getEntity();
return entity.getFacets();
}
@Override
public List<Facet> bindFacetValues() {
HelenusEntity entity = props.get(0).getEntity();
List<Facet> boundFacets = new ArrayList<>();
for (Facet facet : entity.getFacets()) {
if (facet instanceof UnboundFacet) {
UnboundFacet unboundFacet = (UnboundFacet) facet;
UnboundFacet.Binder binder = unboundFacet.binder();
for (HelenusProperty prop : unboundFacet.getProperties()) {
if (filters != null) {
Filter filter = filters.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;
}
@Override
public BuiltStatement buildStatement(boolean cached) {
public BuiltStatement buildStatement() {
HelenusEntity entity = null;
Selection selection = QueryBuilder.select();
for (HelenusPropertyNode prop : props) {
String columnName = prop.getColumnName();
selection = selection.column(columnName);
selection = selection.column(prop.getColumnName());
if (prop.getProperty().caseSensitiveIndex()) {
allowFiltering = true;
}
if (entity == null) {
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) {
switch (prop.getProperty().getColumnType()) {
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;
}
throw new HelenusMappingException("you can select columns only from a single entity "
+ entity.getMappingInterface() + " or " + prop.getEntity().getMappingInterface());
}
}
@ -296,8 +191,7 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
throw new HelenusMappingException("no entity or table to select data");
}
String tableName = alternateTableName == null ? entity.getName().toCql() : alternateTableName;
Select select = selection.from(tableName);
Select select = selection.from(entity.getName().toCql());
if (ordering != null && !ordering.isEmpty()) {
select.orderBy(ordering.toArray(new Ordering[ordering.size()]));
@ -311,40 +205,13 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
Where where = select.where();
boolean isFirstIndex = true;
for (Filter<?> filter : filters.values()) {
for (Filter<?> filter : filters) {
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);
logger.error("onlyIf conditions " + ifFilters + " would be ignored in the statement " + select);
}
if (allowFiltering) {
@ -354,18 +221,30 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
return select;
}
@Override
public Optional<E> sync() {
if (true) {
} else {
return super.sync();
}
}
@SuppressWarnings("unchecked")
@Override
public Stream<E> transform(ResultSet resultSet) {
if (rowMapper != null) {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(resultSet.iterator(), Spliterator.ORDERED), false)
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);
}
else {
return (Stream<E>) StreamSupport
.stream(Spliterators.spliteratorUnknownSize(resultSet.iterator(), Spliterator.ORDERED), false);
}
}
@ -375,4 +254,5 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
}
return ordering;
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,55 +15,36 @@
*/
package net.helenus.core.operation;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;
import net.helenus.core.cache.Facet;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
public final class SelectTransformingOperation<R, E>
extends AbstractFilterStreamOperation<R, SelectTransformingOperation<R, E>> {
extends
AbstractFilterStreamOperation<R, SelectTransformingOperation<R, E>> {
private final SelectOperation<E> delegate;
private final SelectOperation<E> src;
private final Function<E, R> fn;
public SelectTransformingOperation(SelectOperation<E> delegate, Function<E, R> fn) {
super(delegate.sessionOps);
public SelectTransformingOperation(SelectOperation<E> src, Function<E, R> fn) {
super(src.sessionOps);
this.delegate = delegate;
this.src = src;
this.fn = fn;
this.filters = delegate.filters;
this.ifFilters = delegate.ifFilters;
this.filters = src.filters;
this.ifFilters = src.ifFilters;
}
@Override
public List<Facet> bindFacetValues() {
return delegate.bindFacetValues();
}
@Override
public List<Facet> getFacets() {
return delegate.getFacets();
}
@Override
public BuiltStatement buildStatement(boolean cached) {
return delegate.buildStatement(cached);
public BuiltStatement buildStatement() {
return src.buildStatement();
}
@Override
public Stream<R> transform(ResultSet resultSet) {
return delegate.transform(resultSet).map(fn);
return src.transform(resultSet).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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,109 +15,54 @@
*/
package net.helenus.core.operation;
import java.util.*;
import java.util.function.Function;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.Assignment;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Update;
import java.util.*;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.stream.Collectors;
import net.helenus.core.*;
import net.helenus.core.cache.BoundFacet;
import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet;
import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Filter;
import net.helenus.core.Getter;
import net.helenus.core.reflect.HelenusPropertyNode;
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;
import net.helenus.support.HelenusException;
import net.helenus.support.HelenusMappingException;
import net.helenus.support.Immutables;
public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateOperation<E>> {
public final class UpdateOperation extends AbstractFilterOperation<ResultSet, UpdateOperation> {
private final Map<Assignment, BoundFacet> assignments = new HashMap<>();
private final AbstractEntityDraft<E> draft;
private final Map<String, Object> draftMap;
private final Set<String> readSet;
private HelenusEntity entity = null;
private Object pojo;
private final List<Assignment> assignments = new ArrayList<Assignment>();
private int[] ttl;
private long[] timestamp;
private long writeTime = 0L;
public UpdateOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations);
this.draft = null;
this.draftMap = null;
this.readSet = null;
}
public UpdateOperation(
AbstractSessionOperations sessionOperations, AbstractEntityDraft<E> draft) {
public UpdateOperation(AbstractSessionOperations sessionOperations, HelenusPropertyNode p, Object v) {
super(sessionOperations);
this.draft = draft;
this.draftMap = draft.toMap();
this.readSet = draft.read();
}
public UpdateOperation(AbstractSessionOperations sessionOperations, Object pojo) {
super(sessionOperations);
this.draft = null;
this.draftMap = null;
if (pojo != null) {
this.entity = Helenus.resolve(MappingUtil.getMappingInterface(pojo));
if (this.entity != null && entity.isCacheable() && pojo instanceof MapExportable) {
this.pojo = pojo;
this.readSet = ((MapExportable) pojo).toReadSet();
} else {
this.readSet = null;
}
} else {
this.readSet = null;
}
}
public UpdateOperation(
AbstractSessionOperations sessionOperations, HelenusPropertyNode p, Object v) {
super(sessionOperations);
this.draft = null;
this.draftMap = null;
this.readSet = null;
Object value = sessionOps.getValuePreparer().prepareColumnValue(v, p.getProperty());
assignments.put(QueryBuilder.set(p.getColumnName(), value), new BoundFacet(p.getProperty(), v));
assignments.add(QueryBuilder.set(p.getColumnName(), value));
addPropertyNode(p);
}
public <V> UpdateOperation<E> set(Getter<V> getter, V v) {
public <V> UpdateOperation set(Getter<V> getter, V v) {
Objects.requireNonNull(getter, "getter is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter);
HelenusProperty prop = p.getProperty();
Object value = sessionOps.getValuePreparer().prepareColumnValue(v, prop);
assignments.put(QueryBuilder.set(p.getColumnName(), value), new BoundFacet(prop, value));
if (draft != null) {
String key = prop.getPropertyName();
if (draft.get(key, value.getClass()) != v) {
draft.set(key, v);
}
}
if (pojo != null) {
if (!BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop).equals(v)) {
String key = prop.getPropertyName();
((MapExportable) pojo).put(key, v);
}
}
Object value = sessionOps.getValuePreparer().prepareColumnValue(v, p.getProperty());
assignments.add(QueryBuilder.set(p.getColumnName(), value));
addPropertyNode(p);
@ -133,60 +77,38 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
*
*/
public <V> UpdateOperation<E> increment(Getter<V> counterGetter) {
public <V> UpdateOperation increment(Getter<V> counterGetter) {
return increment(counterGetter, 1L);
}
public <V> UpdateOperation<E> increment(Getter<V> counterGetter, long delta) {
public <V> UpdateOperation increment(Getter<V> counterGetter, long delta) {
Objects.requireNonNull(counterGetter, "counterGetter is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(counterGetter);
BoundFacet facet = null;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
Long value = (Long) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop);
facet = new BoundFacet(prop, value + delta);
} else if (draft != null) {
String key = prop.getPropertyName();
draftMap.put(key, (Long) draftMap.get(key) + delta);
facet = new BoundFacet(prop, draftMap.get(key));
}
assignments.put(QueryBuilder.incr(p.getColumnName(), delta), facet);
assignments.add(QueryBuilder.incr(p.getColumnName(), delta));
addPropertyNode(p);
return this;
}
public <V> UpdateOperation<E> decrement(Getter<V> counterGetter) {
public <V> UpdateOperation decrement(Getter<V> counterGetter) {
return decrement(counterGetter, 1L);
}
public <V> UpdateOperation<E> decrement(Getter<V> counterGetter, long delta) {
public <V> UpdateOperation decrement(Getter<V> counterGetter, long delta) {
Objects.requireNonNull(counterGetter, "counterGetter is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(counterGetter);
BoundFacet facet = null;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
Long value = (Long) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop);
facet = new BoundFacet(prop, value - delta);
} else if (draft != null) {
String key = prop.getPropertyName();
draftMap.put(key, (Long) draftMap.get(key) - delta);
facet = new BoundFacet(prop, draftMap.get(key));
}
assignments.put(QueryBuilder.decr(p.getColumnName(), delta), facet);
assignments.add(QueryBuilder.decr(p.getColumnName(), delta));
addPropertyNode(p);
return this;
}
/*
@ -196,7 +118,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
*
*/
public <V> UpdateOperation<E> prepend(Getter<List<V>> listGetter, V value) {
public <V> UpdateOperation prepend(Getter<List<V>> listGetter, V value) {
Objects.requireNonNull(listGetter, "listGetter is empty");
Objects.requireNonNull(value, "value is empty");
@ -204,31 +126,13 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
Object valueObj = prepareSingleListValue(p, value);
final List<V> list;
final BoundFacet facet;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
list = (List<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
list.add(0, value);
facet = new BoundFacet(prop, list);
} else if (draft != null) {
String key = prop.getPropertyName();
list = (List<V>) draftMap.get(key);
list.add(0, value);
facet = new BoundFacet(prop, list);
} else {
list = null;
facet = null;
}
assignments.put(QueryBuilder.prepend(p.getColumnName(), valueObj), facet);
assignments.add(QueryBuilder.prepend(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
public <V> UpdateOperation<E> prependAll(Getter<List<V>> listGetter, List<V> value) {
public <V> UpdateOperation prependAll(Getter<List<V>> listGetter, List<V> value) {
Objects.requireNonNull(listGetter, "listGetter is empty");
Objects.requireNonNull(value, "value is empty");
@ -236,31 +140,13 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
List valueObj = prepareListValue(p, value);
final List<V> list;
final BoundFacet facet;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
list = (List<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
list.addAll(0, value);
facet = new BoundFacet(prop, list);
} else if (draft != null && value.size() > 0) {
String key = p.getProperty().getPropertyName();
list = (List<V>) draftMap.get(key);
list.addAll(0, value);
facet = new BoundFacet(prop, list);
} else {
list = null;
facet = null;
}
assignments.put(QueryBuilder.prependAll(p.getColumnName(), valueObj), facet);
assignments.add(QueryBuilder.prependAll(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
public <V> UpdateOperation<E> setIdx(Getter<List<V>> listGetter, int idx, V value) {
public <V> UpdateOperation setIdx(Getter<List<V>> listGetter, int idx, V value) {
Objects.requireNonNull(listGetter, "listGetter is empty");
Objects.requireNonNull(value, "value is empty");
@ -268,37 +154,13 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
Object valueObj = prepareSingleListValue(p, value);
final BoundFacet facet;
HelenusProperty prop = p.getProperty();
if (pojo != null || draft != null) {
final List<V> list;
if (pojo != null) {
list = (List<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
} else {
String key = prop.getPropertyName();
list = (List<V>) draftMap.get(key);
}
if (idx < 0) {
list.add(0, value);
} else if (idx > list.size()) {
list.add(list.size(), value);
} else {
list.add(idx, value);
}
list.add(0, value);
facet = new BoundFacet(prop, list);
} else {
facet = null;
}
assignments.put(QueryBuilder.setIdx(p.getColumnName(), idx, valueObj), facet);
assignments.add(QueryBuilder.setIdx(p.getColumnName(), idx, valueObj));
addPropertyNode(p);
return this;
}
public <V> UpdateOperation<E> append(Getter<List<V>> listGetter, V value) {
public <V> UpdateOperation append(Getter<List<V>> listGetter, V value) {
Objects.requireNonNull(listGetter, "listGetter is empty");
Objects.requireNonNull(value, "value is empty");
@ -306,30 +168,13 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
Object valueObj = prepareSingleListValue(p, value);
final List<V> list;
final BoundFacet facet;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
list = (List<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
list.add(value);
facet = new BoundFacet(prop, list);
} else if (draft != null) {
String key = prop.getPropertyName();
list = (List<V>) draftMap.get(key);
list.add(value);
facet = new BoundFacet(prop, list);
} else {
list = null;
facet = null;
}
assignments.put(QueryBuilder.append(p.getColumnName(), valueObj), facet);
assignments.add(QueryBuilder.append(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
public <V> UpdateOperation<E> appendAll(Getter<List<V>> listGetter, List<V> value) {
public <V> UpdateOperation appendAll(Getter<List<V>> listGetter, List<V> value) {
Objects.requireNonNull(listGetter, "listGetter is empty");
Objects.requireNonNull(value, "value is empty");
@ -337,30 +182,13 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
List valueObj = prepareListValue(p, value);
final List<V> list;
final BoundFacet facet;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
list = (List<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
list.addAll(value);
facet = new BoundFacet(prop, list);
} else if (draft != null && value.size() > 0) {
String key = prop.getPropertyName();
list = (List<V>) draftMap.get(key);
list.addAll(value);
facet = new BoundFacet(prop, list);
} else {
list = null;
facet = null;
}
assignments.put(QueryBuilder.appendAll(p.getColumnName(), valueObj), facet);
assignments.add(QueryBuilder.appendAll(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
public <V> UpdateOperation<E> discard(Getter<List<V>> listGetter, V value) {
public <V> UpdateOperation discard(Getter<List<V>> listGetter, V value) {
Objects.requireNonNull(listGetter, "listGetter is empty");
Objects.requireNonNull(value, "value is empty");
@ -368,30 +196,13 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
Object valueObj = prepareSingleListValue(p, value);
final List<V> list;
final BoundFacet facet;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
list = (List<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
list.remove(value);
facet = new BoundFacet(prop, list);
} else if (draft != null) {
String key = prop.getPropertyName();
list = (List<V>) draftMap.get(key);
list.remove(value);
facet = new BoundFacet(prop, list);
} else {
list = null;
facet = null;
}
assignments.put(QueryBuilder.discard(p.getColumnName(), valueObj), facet);
assignments.add(QueryBuilder.discard(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
public <V> UpdateOperation<E> discardAll(Getter<List<V>> listGetter, List<V> value) {
public <V> UpdateOperation discardAll(Getter<List<V>> listGetter, List<V> value) {
Objects.requireNonNull(listGetter, "listGetter is empty");
Objects.requireNonNull(value, "value is empty");
@ -399,26 +210,9 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
List valueObj = prepareListValue(p, value);
final List<V> list;
final BoundFacet facet;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
list = (List<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
list.removeAll(value);
facet = new BoundFacet(prop, list);
} else if (draft != null) {
String key = prop.getPropertyName();
list = (List<V>) draftMap.get(key);
list.removeAll(value);
facet = new BoundFacet(prop, list);
} else {
list = null;
facet = null;
}
assignments.put(QueryBuilder.discardAll(p.getColumnName(), valueObj), facet);
assignments.add(QueryBuilder.discardAll(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
@ -427,8 +221,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
Object valueObj = value;
Optional<Function<Object, Object>> converter =
prop.getWriteConverter(sessionOps.getSessionRepository());
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
List convertedList = (List) converter.get().apply(Immutables.listOf(value));
valueObj = convertedList.get(0);
@ -443,8 +236,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
List valueObj = value;
Optional<Function<Object, Object>> converter =
prop.getWriteConverter(sessionOps.getSessionRepository());
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
valueObj = (List) converter.get().apply(value);
}
@ -460,7 +252,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
*
*/
public <V> UpdateOperation<E> add(Getter<Set<V>> setGetter, V value) {
public <V> UpdateOperation add(Getter<Set<V>> setGetter, V value) {
Objects.requireNonNull(setGetter, "setGetter is empty");
Objects.requireNonNull(value, "value is empty");
@ -468,30 +260,13 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
Object valueObj = prepareSingleSetValue(p, value);
final Set<V> set;
final BoundFacet facet;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
set = (Set<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
set.add(value);
facet = new BoundFacet(prop, set);
} else if (draft != null) {
String key = prop.getPropertyName();
set = (Set<V>) draftMap.get(key);
set.add(value);
facet = new BoundFacet(prop, set);
} else {
set = null;
facet = null;
}
assignments.put(QueryBuilder.add(p.getColumnName(), valueObj), facet);
assignments.add(QueryBuilder.add(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
public <V> UpdateOperation<E> addAll(Getter<Set<V>> setGetter, Set<V> value) {
public <V> UpdateOperation addAll(Getter<Set<V>> setGetter, Set<V> value) {
Objects.requireNonNull(setGetter, "setGetter is empty");
Objects.requireNonNull(value, "value is empty");
@ -499,30 +274,13 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
Set valueObj = prepareSetValue(p, value);
final Set<V> set;
final BoundFacet facet;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
set = (Set<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
set.addAll(value);
facet = new BoundFacet(prop, set);
} else if (draft != null) {
String key = prop.getPropertyName();
set = (Set<V>) draftMap.get(key);
set.addAll(value);
facet = new BoundFacet(prop, set);
} else {
set = null;
facet = null;
}
assignments.put(QueryBuilder.addAll(p.getColumnName(), valueObj), facet);
assignments.add(QueryBuilder.addAll(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
public <V> UpdateOperation<E> remove(Getter<Set<V>> setGetter, V value) {
public <V> UpdateOperation remove(Getter<Set<V>> setGetter, V value) {
Objects.requireNonNull(setGetter, "setGetter is empty");
Objects.requireNonNull(value, "value is empty");
@ -530,30 +288,13 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
Object valueObj = prepareSingleSetValue(p, value);
final Set<V> set;
final BoundFacet facet;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
set = (Set<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
set.remove(value);
facet = new BoundFacet(prop, set);
} else if (draft != null) {
String key = prop.getPropertyName();
set = (Set<V>) draftMap.get(key);
set.remove(value);
facet = new BoundFacet(prop, set);
} else {
set = null;
facet = null;
}
assignments.put(QueryBuilder.remove(p.getColumnName(), valueObj), facet);
assignments.add(QueryBuilder.remove(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
public <V> UpdateOperation<E> removeAll(Getter<Set<V>> setGetter, Set<V> value) {
public <V> UpdateOperation removeAll(Getter<Set<V>> setGetter, Set<V> value) {
Objects.requireNonNull(setGetter, "setGetter is empty");
Objects.requireNonNull(value, "value is empty");
@ -561,26 +302,9 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
Set valueObj = prepareSetValue(p, value);
final Set<V> set;
final BoundFacet facet;
HelenusProperty prop = p.getProperty();
if (pojo != null) {
set = (Set<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
set.removeAll(value);
facet = new BoundFacet(prop, set);
} else if (draft != null) {
String key = prop.getPropertyName();
set = (Set<V>) draftMap.get(key);
set.removeAll(value);
facet = new BoundFacet(prop, set);
} else {
set = null;
facet = null;
}
assignments.put(QueryBuilder.removeAll(p.getColumnName(), valueObj), facet);
assignments.add(QueryBuilder.removeAll(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
@ -589,8 +313,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusProperty prop = p.getProperty();
Object valueObj = value;
Optional<Function<Object, Object>> converter =
prop.getWriteConverter(sessionOps.getSessionRepository());
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
Set convertedSet = (Set) converter.get().apply(Immutables.setOf(value));
valueObj = convertedSet.iterator().next();
@ -604,8 +327,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusProperty prop = p.getProperty();
Set valueObj = value;
Optional<Function<Object, Object>> converter =
prop.getWriteConverter(sessionOps.getSessionRepository());
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
valueObj = (Set) converter.get().apply(value);
}
@ -621,7 +343,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
*
*/
public <K, V> UpdateOperation<E> put(Getter<Map<K, V>> mapGetter, K key, V value) {
public <K, V> UpdateOperation put(Getter<Map<K, V>> mapGetter, K key, V value) {
Objects.requireNonNull(mapGetter, "mapGetter is empty");
Objects.requireNonNull(key, "key is empty");
@ -629,39 +351,22 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(mapGetter);
HelenusProperty prop = p.getProperty();
final Map<K, V> map;
final BoundFacet facet;
if (pojo != null) {
map = (Map<K, V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
map.put(key, value);
facet = new BoundFacet(prop, map);
} else if (draft != null) {
map = (Map<K, V>) draftMap.get(prop.getPropertyName());
map.put(key, value);
facet = new BoundFacet(prop, map);
} else {
map = null;
facet = null;
}
Optional<Function<Object, Object>> converter =
prop.getWriteConverter(sessionOps.getSessionRepository());
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
Map<Object, Object> convertedMap =
(Map<Object, Object>) converter.get().apply(Immutables.mapOf(key, value));
Map<Object, Object> convertedMap = (Map<Object, Object>) converter.get()
.apply(Immutables.mapOf(key, value));
for (Map.Entry<Object, Object> e : convertedMap.entrySet()) {
assignments.put(QueryBuilder.put(p.getColumnName(), e.getKey(), e.getValue()), facet);
assignments.add(QueryBuilder.put(p.getColumnName(), e.getKey(), e.getValue()));
}
} else {
assignments.put(QueryBuilder.put(p.getColumnName(), key, value), facet);
assignments.add(QueryBuilder.put(p.getColumnName(), key, value));
}
addPropertyNode(p);
return this;
}
public <K, V> UpdateOperation<E> putAll(Getter<Map<K, V>> mapGetter, Map<K, V> map) {
public <K, V> UpdateOperation putAll(Getter<Map<K, V>> mapGetter, Map<K, V> map) {
Objects.requireNonNull(mapGetter, "mapGetter is empty");
Objects.requireNonNull(map, "map is empty");
@ -669,37 +374,20 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(mapGetter);
HelenusProperty prop = p.getProperty();
final Map<K, V> newMap;
final BoundFacet facet;
if (pojo != null) {
newMap = (Map<K, V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
newMap.putAll(map);
facet = new BoundFacet(prop, newMap);
} else if (draft != null) {
newMap = (Map<K, V>) draftMap.get(prop.getPropertyName());
newMap.putAll(map);
facet = new BoundFacet(prop, newMap);
} else {
newMap = null;
facet = null;
}
Optional<Function<Object, Object>> converter =
prop.getWriteConverter(sessionOps.getSessionRepository());
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
Map convertedMap = (Map) converter.get().apply(map);
assignments.put(QueryBuilder.putAll(p.getColumnName(), convertedMap), facet);
assignments.add(QueryBuilder.putAll(p.getColumnName(), convertedMap));
} else {
assignments.put(QueryBuilder.putAll(p.getColumnName(), map), facet);
assignments.add(QueryBuilder.putAll(p.getColumnName(), map));
}
addPropertyNode(p);
return this;
}
@Override
public BuiltStatement buildStatement(boolean cached) {
public BuiltStatement buildStatement() {
if (entity == null) {
throw new HelenusMappingException("empty update operation");
@ -707,7 +395,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
Update update = QueryBuilder.update(entity.getName().toCql());
for (Assignment assignment : assignments.keySet()) {
for (Assignment assignment : assignments) {
update.with(assignment);
}
@ -728,7 +416,6 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
if (this.ttl != null) {
update.using(QueryBuilder.ttl(this.ttl[0]));
}
if (this.timestamp != null) {
update.using(QueryBuilder.timestamp(this.timestamp[0]));
}
@ -737,25 +424,17 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
}
@Override
public E transform(ResultSet resultSet) {
if ((ifFilters != null && !ifFilters.isEmpty()) && (resultSet.wasApplied() == false)) {
throw new HelenusException("Statement was not applied due to consistency constraints");
public ResultSet transform(ResultSet resultSet) {
return resultSet;
}
if (draft != null) {
return Helenus.map(draft.getEntityClass(), draft.toMap(draftMap));
} else {
return (E) resultSet;
}
}
public UpdateOperation<E> usingTtl(int ttl) {
public UpdateOperation usingTtl(int ttl) {
this.ttl = new int[1];
this.ttl[0] = ttl;
return this;
}
public UpdateOperation<E> usingTimestamp(long timestamp) {
public UpdateOperation usingTimestamp(long timestamp) {
this.timestamp = new long[1];
this.timestamp[0] = timestamp;
return this;
@ -765,140 +444,8 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
if (entity == null) {
entity = p.getEntity();
} else if (entity != p.getEntity()) {
throw new HelenusMappingException(
"you can update columns only in single entity "
+ entity.getMappingInterface()
+ " or "
+ p.getEntity().getMappingInterface());
}
}
private void adjustTtlAndWriteTime(MapExportable pojo) {
if (ttl != null || writeTime != 0L) {
List<String> names = new ArrayList<String>(assignments.size());
for (BoundFacet facet : assignments.values()) {
for (HelenusProperty prop : facet.getProperties()) {
names.add(prop.getColumnName().toCql(false));
}
}
if (names.size() > 0) {
if (ttl != null) {
names.forEach(name -> pojo.put(CacheUtil.ttlKey(name), ttl));
}
if (writeTime != 0L) {
names.forEach(name -> pojo.put(CacheUtil.writeTimeKey(name), writeTime));
}
}
}
}
@Override
protected boolean isIdempotentOperation() {
return assignments
.values()
.stream()
.allMatch(
facet -> {
if (facet != null) {
Set<HelenusProperty> props = facet.getProperties();
if (props != null && props.size() > 0) {
return props.stream().allMatch(prop -> prop.isIdempotent());
} else {
return true;
}
} else {
// In this case our UPDATE statement made mutations via the List, Set, Map methods only.
return false;
}
})
|| super.isIdempotentOperation();
}
@Override
public E sync() throws TimeoutException {
E result = super.sync();
if (result != null && entity.isCacheable()) {
if (draft != null) {
adjustTtlAndWriteTime(draft);
adjustTtlAndWriteTime((MapExportable) result);
sessionOps.updateCache(result, bindFacetValues());
} else if (pojo != null) {
adjustTtlAndWriteTime((MapExportable) pojo);
sessionOps.updateCache(pojo, bindFacetValues());
} else {
sessionOps.cacheEvict(bindFacetValues());
}
}
return result;
}
@Override
public E sync(UnitOfWork uow) throws TimeoutException {
if (uow == null) {
return sync();
}
E result = super.sync(uow);
if (result != null) {
if (draft != null) {
adjustTtlAndWriteTime(draft);
}
if (entity != null && MapExportable.class.isAssignableFrom(entity.getMappingInterface())) {
adjustTtlAndWriteTime((MapExportable) result);
cacheUpdate(uow, result, bindFacetValues());
} else if (pojo != null) {
adjustTtlAndWriteTime((MapExportable) pojo);
cacheUpdate(uow, (E) pojo, bindFacetValues());
return (E) pojo;
}
}
return result;
}
public E batch(UnitOfWork uow) throws TimeoutException {
if (uow == null) {
throw new HelenusException("UnitOfWork cannot be null when batching operations.");
}
final E result;
if (draft != null) {
result = draft.build();
adjustTtlAndWriteTime(draft);
} else if (pojo != null) {
result = (E) pojo;
adjustTtlAndWriteTime((MapExportable) pojo);
} else {
result = null;
}
if (result != null) {
cacheUpdate(uow, result, bindFacetValues());
uow.batch(this);
return result;
}
return sync(uow);
}
@Override
public List<Facet> bindFacetValues() {
List<Facet> facets = bindFacetValues(entity.getFacets());
facets.addAll(
assignments
.values()
.stream()
.distinct()
.filter(o -> o != null)
.collect(Collectors.toList()));
return facets;
}
@Override
public List<Facet> getFacets() {
if (entity != null) {
return entity.getFacets();
} else {
return new ArrayList<Facet>();
throw new HelenusMappingException("you can update 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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -20,17 +19,14 @@ import java.util.HashMap;
import java.util.Map;
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 =
new HashMap<Class<?>, 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 final Class<?> primitiveClass;
private final Object defaultValue;
private final static Map<Class<?>, DefaultPrimitiveTypes> map = new HashMap<Class<?>, DefaultPrimitiveTypes>();
static {
for (DefaultPrimitiveTypes type : DefaultPrimitiveTypes.values()) {
@ -38,9 +34,6 @@ public enum DefaultPrimitiveTypes {
}
}
private final Class<?> primitiveClass;
private final Object defaultValue;
private DefaultPrimitiveTypes(Class<?> primitiveClass, Object defaultValue) {
this.primitiveClass = primitiveClass;
this.defaultValue = defaultValue;
@ -57,4 +50,5 @@ public enum DefaultPrimitiveTypes {
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,18 +15,15 @@
*/
package net.helenus.core.reflect;
import com.datastax.driver.core.Metadata;
import net.helenus.mapping.HelenusEntity;
public interface DslExportable {
String GET_ENTITY_METHOD = "getHelenusMappingEntity";
String GET_PARENT_METHOD = "getParentDslHelenusPropertyNode";
String SET_METADATA_METHOD = "setCassandraMetadataForHelenusSession";
public static final String GET_ENTITY_METHOD = "getHelenusMappingEntity";
public static final String GET_PARENT_METHOD = "getParentDslHelenusPropertyNode";
HelenusEntity getHelenusMappingEntity();
HelenusPropertyNode getParentDslHelenusPropertyNode();
void setCassandraMetadataForHelenusSession(Metadata metadata);
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,14 +15,18 @@
*/
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.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import com.datastax.driver.core.*;
import net.helenus.core.Helenus;
import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusMappingEntity;
@ -36,39 +39,21 @@ import net.helenus.support.HelenusException;
public class DslInvocationHandler<E> implements InvocationHandler {
private final Class<E> iface;
private final ClassLoader classLoader;
private final HelenusEntity entity;
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(
Class<E> iface,
ClassLoader classLoader,
Optional<HelenusPropertyNode> parent,
Metadata metadata) {
public DslInvocationHandler(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent, Metadata metadata) {
this.metadata = metadata;
this.entity = new HelenusMappingEntity(iface, metadata);
this.parent = parent;
this.iface = iface;
this.classLoader = classLoader;
}
public void setCassandraMetadataForHelenusSession(Metadata metadata) {
if (metadata != null) {
this.metadata = metadata;
entity = init(metadata);
}
}
private HelenusEntity init(Metadata metadata) {
HelenusEntity entity = new HelenusMappingEntity(iface, metadata);
Collection<HelenusProperty> properties = entity.getOrderedProperties();
if (properties != null) {
for (HelenusProperty prop : properties) {
if (this.entity != null) {
for (HelenusProperty prop : entity.getOrderedProperties()) {
map.put(prop.getGetterMethod(), prop);
@ -77,12 +62,8 @@ public class DslInvocationHandler<E> implements InvocationHandler {
if (type instanceof UDTDataType && !UDTValue.class.isAssignableFrom(javaType)) {
Object childDsl =
Helenus.dsl(
javaType,
classLoader,
Optional.of(new HelenusPropertyNode(prop, parent)),
metadata);
Object childDsl = Helenus.dsl(javaType, classLoader,
Optional.of(new HelenusPropertyNode(prop, parent)), metadata);
udtMap.put(prop.getGetterMethod(), childDsl);
}
@ -90,29 +71,23 @@ public class DslInvocationHandler<E> implements InvocationHandler {
if (type instanceof DTDataType) {
DTDataType dataType = (DTDataType) type;
if (dataType.getDataType() instanceof TupleType
&& !TupleValue.class.isAssignableFrom(javaType)) {
if (dataType.getDataType() instanceof TupleType && !TupleValue.class.isAssignableFrom(javaType)) {
Object childDsl =
Helenus.dsl(
javaType,
classLoader,
Optional.of(new HelenusPropertyNode(prop, parent)),
metadata);
Object childDsl = Helenus.dsl(javaType, classLoader,
Optional.of(new HelenusPropertyNode(prop, parent)), metadata);
tupleMap.put(prop.getGetterMethod(), childDsl);
}
}
}
}
return entity;
}
}
}
@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) {
@ -126,15 +101,6 @@ public class DslInvocationHandler<E> implements InvocationHandler {
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);
}
@ -143,14 +109,6 @@ public class DslInvocationHandler<E> implements InvocationHandler {
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();
}
@ -159,6 +117,11 @@ public class DslInvocationHandler<E> implements InvocationHandler {
return entity;
}
if (DslExportable.GET_PARENT_METHOD.equals(methodName)) {
return parent.get();
}
HelenusProperty prop = map.get(method);
if (prop == null) {
prop = entity.getProperty(methodName);
@ -175,6 +138,7 @@ public class DslInvocationHandler<E> implements InvocationHandler {
if (childDsl != null) {
return childDsl;
}
}
if (type instanceof DTDataType) {
@ -182,7 +146,9 @@ public class DslInvocationHandler<E> implements InvocationHandler {
DataType dt = dataType.getDataType();
switch (dt.getName()) {
case TUPLE :
Object childDsl = tupleMap.get(method);
if (childDsl != null) {
@ -202,7 +168,9 @@ public class DslInvocationHandler<E> implements InvocationHandler {
default :
break;
}
}
throw new DslPropertyException(new HelenusPropertyNode(prop, parent));
@ -210,4 +178,5 @@ public class DslInvocationHandler<E> implements InvocationHandler {
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -20,7 +19,9 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.function.Function;
import javax.validation.ConstraintValidator;
import net.helenus.core.SessionRepository;
import net.helenus.mapping.*;
import net.helenus.mapping.type.AbstractDataType;
@ -60,14 +61,7 @@ public final class HelenusNamedProperty implements HelenusProperty {
}
@Override
public boolean caseSensitiveIndex() {
return false;
}
@Override
public boolean isIdempotent() {
return false;
}
public boolean caseSensitiveIndex() { return false; }
@Override
public Class<?> getJavaType() {

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -18,6 +17,7 @@ package net.helenus.core.reflect;
import java.util.*;
import java.util.stream.Collectors;
import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty;
@ -102,5 +102,7 @@ public final class HelenusPropertyNode implements Iterable<HelenusProperty> {
next = node.next;
return node.prop;
}
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -17,6 +16,7 @@
package net.helenus.core.reflect;
import java.util.*;
import net.helenus.mapping.HelenusProperty;
import net.helenus.support.DslPropertyException;
import net.helenus.support.HelenusMappingException;

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -20,6 +19,7 @@ import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import net.helenus.mapping.HelenusProperty;
import net.helenus.support.DslPropertyException;
import net.helenus.support.HelenusMappingException;
@ -114,4 +114,5 @@ public final class MapDsl<K, V> implements Map<K, V> {
public String toString() {
return "MapDsl";
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -17,25 +16,11 @@
package net.helenus.core.reflect;
import java.util.Map;
import java.util.Set;
import net.helenus.core.Getter;
public interface MapExportable {
String TO_MAP_METHOD = "toMap";
String TO_READ_SET_METHOD = "toReadSet";
String PUT_METHOD = "put";
public static final String TO_MAP_METHOD = "toMap";
Map<String, Object> toMap();
default Map<String, Object> toMap(boolean mutable) {
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,32 +15,20 @@
*/
package net.helenus.core.reflect;
import com.google.common.collect.ImmutableList;
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.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
import net.helenus.core.Getter;
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 java.util.Collections;
import java.util.Map;
import net.helenus.support.HelenusException;
public class MapperInvocationHandler<E> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -7044209982830584984L;
public class MapperInvocationHandler<E> implements InvocationHandler {
private Map<String, Object> src;
private final Set<String> read = new HashSet<String>();
private final Map<String, Object> src;
private final Class<E> iface;
public MapperInvocationHandler(Class<E> iface, Map<String, Object> src) {
@ -49,46 +36,27 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
this.iface = iface;
}
private Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable {
// NOTE: This is reflection magic to invoke (non-recursively) a default method
// implemented on an interface
// that we've proxied (in ReflectionDslInstantiator). I found the answer in this
// article.
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.isDefault()) {
// NOTE: This is reflection magic to invoke (non-recursively) a default method 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.
Constructor<MethodHandles.Lookup> constructor =
MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
constructor.setAccessible(true);
// Now we need to lookup and invoke special the default method on the interface
// class.
// Now we need to lookup and invoke special the default method on the interface class.
final Class<?> declaringClass = method.getDeclaringClass();
Object result =
constructor
.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
Object result = constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
.unreflectSpecial(method, declaringClass)
.bindTo(proxy)
.invokeWithArguments(args);
return result;
}
private Object writeReplace() {
return new SerializationProxy<E>(this);
}
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
throw new InvalidObjectException("Proxy required.");
}
@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) {
@ -97,100 +65,11 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
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 this == Proxy.getInvocationHandler(otherObj);
}
return false;
}
if (MapExportable.PUT_METHOD.equals(methodName) && method.getParameterCount() == 2) {
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) {
final String key;
if (args[0] instanceof String) {
key = CacheUtil.writeTimeKey((String) args[0]);
} else if (args[0] instanceof Getter) {
Getter getter = (Getter) args[0];
key =
CacheUtil.writeTimeKey(
MappingUtil.resolveMappingProperty(getter)
.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) {
Long v = (Long) src.get("");
if (v != null) {
return v;
}
return 0L;
}
if (Entity.TTL_OF_METHOD.equals(methodName) && method.getParameterCount() == 1) {
final String key;
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 (method.getParameterCount() == 1 && args[0] instanceof Boolean) {
if ((boolean) args[0] == true) {
return fromValueProviderMap(src, true);
}
}
return Collections.unmodifiableMap(src);
}
if (MapExportable.TO_READ_SET_METHOD.equals(methodName)) {
return read;
}
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new HelenusException("invalid getter method " + method);
}
@ -203,92 +82,30 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
return iface.getSimpleName() + ": " + src.toString();
}
if ("writeReplace".equals(methodName)) {
return new SerializationProxy(this);
if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
return Collections.unmodifiableMap(src);
}
if ("readObject".equals(methodName)) {
throw new InvalidObjectException("Proxy required.");
}
if ("dsl".equals(methodName)) {
return Helenus.dsl(iface);
}
final Object value = src.get(methodName);
read.add(methodName);
Object value = src.get(methodName);
if (value == null) {
Class<?> returnType = method.getReturnType();
// 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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,25 +15,22 @@
*/
package net.helenus.core.reflect;
import com.datastax.driver.core.Metadata;
import java.lang.reflect.Proxy;
import java.util.Optional;
import com.datastax.driver.core.Metadata;
import net.helenus.core.DslInstantiator;
public enum ReflectionDslInstantiator implements DslInstantiator {
INSTANCE;
@Override
@SuppressWarnings("unchecked")
public <E> E instantiate(
Class<E> iface,
ClassLoader classLoader,
Optional<HelenusPropertyNode> parent,
Metadata metadata) {
DslInvocationHandler<E> handler =
new DslInvocationHandler<E>(iface, classLoader, parent, metadata);
E proxy =
(E) Proxy.newProxyInstance(classLoader, new Class[] {iface, DslExportable.class}, handler);
public <E> E instantiate(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent, Metadata metadata) {
DslInvocationHandler<E> handler = 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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -20,7 +19,8 @@ import net.helenus.support.HelenusMappingException;
public final class ReflectionInstantiator {
private ReflectionInstantiator() {}
private ReflectionInstantiator() {
}
public static <T> T instantiateClass(Class<T> clazz) {
@ -29,5 +29,7 @@ public final class ReflectionInstantiator {
} 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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,12 +15,13 @@
*/
package net.helenus.core.reflect;
import java.io.Serializable;
import java.lang.reflect.Proxy;
import java.util.Map;
import net.helenus.core.MapperInstantiator;
public enum ReflectionMapperInstantiator implements MapperInstantiator {
INSTANCE;
@Override
@ -29,10 +29,9 @@ public enum ReflectionMapperInstantiator implements MapperInstantiator {
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, Serializable.class}, handler);
E proxy = (E) Proxy.newProxyInstance(classLoader, new Class[]{iface, MapExportable.class}, handler);
return proxy;
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -19,6 +18,7 @@ package net.helenus.core.reflect;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import net.helenus.support.HelenusMappingException;
public final class SetDsl<V> implements Set<V> {

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -17,6 +16,7 @@
package net.helenus.mapping;
import java.lang.reflect.Method;
import net.helenus.mapping.annotation.ClusteringColumn;
import net.helenus.mapping.annotation.Column;
import net.helenus.mapping.annotation.PartitionKey;
@ -103,21 +103,15 @@ public final class ColumnInformation {
private void ensureSingleColumnType(ColumnType columnTypeLocal, Method getter) {
if (columnTypeLocal != ColumnType.COLUMN) {
throw new HelenusMappingException(
"property can be annotated only by a single column type " + getter);
throw new HelenusMappingException("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
+ "]";
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-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -17,8 +16,5 @@
package net.helenus.mapping;
public enum ColumnType {
PARTITION_KEY,
CLUSTERING_COLUMN,
STATIC_COLUMN,
COLUMN;
PARTITION_KEY, CLUSTERING_COLUMN, STATIC_COLUMN, COLUMN;
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -17,8 +16,6 @@
package net.helenus.mapping;
import java.util.Collection;
import java.util.List;
import net.helenus.core.cache.Facet;
public interface HelenusEntity {
@ -34,7 +31,4 @@ public interface HelenusEntity {
HelenusProperty getProperty(String name);
List<Facet> getFacets();
boolean isDraftable();
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -17,8 +16,5 @@
package net.helenus.mapping;
public enum HelenusEntityType {
TABLE,
VIEW,
TUPLE,
UDT;
TABLE, TUPLE, UDT;
}

View file

@ -1,7 +1,6 @@
/*
*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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
@ -16,23 +15,20 @@
*/
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.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.core.Helenus;
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.validator.DistinctValidator;
import net.helenus.support.HelenusMappingException;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
public final class HelenusMappingEntity implements HelenusEntity {
@ -40,11 +36,9 @@ public final class HelenusMappingEntity implements HelenusEntity {
private final HelenusEntityType type;
private final IdentityName name;
private final boolean cacheable;
private final boolean draftable;
private final ImmutableMap<String, Method> methods;
private final ImmutableMap<String, HelenusProperty> props;
private final ImmutableList<HelenusProperty> orderedProps;
private final List<Facet> facets;
public HelenusMappingEntity(Class<?> iface, Metadata metadata) {
this(iface, autoDetectType(iface), metadata);
@ -62,33 +56,19 @@ public final class HelenusMappingEntity implements HelenusEntity {
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)) {
if (c.getDeclaredAnnotation(Table.class) != null
|| c.getDeclaredAnnotation(InheritedTable.class) != null) {
for (Method m : c.getDeclaredMethods()) {
Method o = methods.get(m.getName());
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<Method> methods = new ArrayList<Method>();
methods.addAll(Arrays.asList(iface.getDeclaredMethods()));
for (Class<?> c : iface.getInterfaces()) {
methods.addAll(Arrays.asList(c.getDeclaredMethods()));
}
List<HelenusProperty> propsLocal = new ArrayList<HelenusProperty>();
ImmutableMap.Builder<String, HelenusProperty> propsBuilder = ImmutableMap.builder();
ImmutableMap.Builder<String, Method> methodsBuilder = ImmutableMap.builder();
for (Method method : methods.values()) {
for (Method method : methods) {
if (settings.getGetterMethodDetector().apply(method)) {
@ -100,7 +80,9 @@ public final class HelenusMappingEntity implements HelenusEntity {
propsBuilder.put(prop.getPropertyName(), prop);
propsLocal.add(prop);
}
}
}
this.methods = methodsBuilder.build();
@ -111,107 +93,7 @@ public final class HelenusMappingEntity implements HelenusEntity {
validateOrdinals();
// Caching
cacheable = (null != iface.getDeclaredAnnotation(Cacheable.class));
// Draft
Class<?> draft;
try {
draft = Class.forName(iface.getName() + "$Draft");
} catch (Exception ignored) {
draft = null;
}
draftable = (draft != null);
// Materialized view
List<HelenusProperty> primaryKeyProperties = new ArrayList<>();
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) {
switch (type) {
case TABLE:
return MappingUtil.getTableName(iface, true);
case VIEW:
return MappingUtil.getViewName(iface, true);
case TUPLE:
return IdentityName.of(MappingUtil.getDefaultEntityName(iface), false);
case UDT:
return MappingUtil.getUserDefinedTypeName(iface, true);
}
throw new HelenusMappingException("invalid entity type " + type + " in " + type);
}
private static HelenusEntityType autoDetectType(Class<?> iface) {
Objects.requireNonNull(iface, "empty iface");
if (null != iface.getDeclaredAnnotation(Table.class)) {
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(
"entity must be annotated by @Table or @Tuple or @UserDefinedType " + iface);
}
@Override
@ -224,11 +106,6 @@ public final class HelenusMappingEntity implements HelenusEntity {
return cacheable;
}
@Override
public boolean isDraftable() {
return draftable;
}
@Override
public Class<?> getMappingInterface() {
return iface;
@ -249,19 +126,52 @@ public final class HelenusMappingEntity implements HelenusEntity {
return props.get(name);
}
@Override
public List<Facet> getFacets() {
return facets;
}
@Override
public IdentityName getName() {
return name;
}
private static IdentityName resolveName(Class<?> iface, HelenusEntityType type) {
switch (type) {
case TABLE :
return MappingUtil.getTableName(iface, true);
case TUPLE :
return IdentityName.of(MappingUtil.getDefaultEntityName(iface), false);
case UDT :
return MappingUtil.getUserDefinedTypeName(iface, true);
}
throw new HelenusMappingException("invalid entity type " + type + " in " + type);
}
private static HelenusEntityType autoDetectType(Class<?> iface) {
Objects.requireNonNull(iface, "empty iface");
if (null != iface.getDeclaredAnnotation(Table.class)) {
return HelenusEntityType.TABLE;
}
else if (null != iface.getDeclaredAnnotation(Tuple.class)) {
return HelenusEntityType.TUPLE;
}
else if (null != iface.getDeclaredAnnotation(UDT.class)) {
return HelenusEntityType.UDT;
}
throw new HelenusMappingException("entity must be annotated by @Table or @Tuple or @UserDefinedType " + iface);
}
private void validateOrdinals() {
switch (getType()) {
case TABLE :
validateOrdinalsForTable();
break;
@ -273,6 +183,7 @@ public final class HelenusMappingEntity implements HelenusEntity {
default :
break;
}
}
private void validateOrdinalsForTable() {
@ -287,12 +198,11 @@ public final class HelenusMappingEntity implements HelenusEntity {
int ordinal = prop.getOrdinal();
switch (type) {
case PARTITION_KEY :
if (partitionKeys.get(ordinal)) {
throw new HelenusMappingException(
"detected two or more partition key columns with the same ordinal "
+ ordinal
+ " in "
"detected two or more partition key columns with the same ordinal " + ordinal + " in "
+ prop.getEntity());
}
partitionKeys.set(ordinal);
@ -300,11 +210,8 @@ public final class HelenusMappingEntity implements HelenusEntity {
case CLUSTERING_COLUMN :
if (clusteringColumns.get(ordinal)) {
throw new HelenusMappingException(
"detected two or clustering columns with the same ordinal "
+ ordinal
+ " in "
+ prop.getEntity());
throw new HelenusMappingException("detected two or clustering columns with the same ordinal "
+ ordinal + " in " + prop.getEntity());
}
clusteringColumns.set(ordinal);
break;
@ -312,36 +219,30 @@ public final class HelenusMappingEntity implements HelenusEntity {
default :
break;
}
}
}
private void validateOrdinalsInTuple() {
boolean[] ordinals = new boolean[props.size()];
getOrderedProperties()
.forEach(
p -> {
getOrderedProperties().forEach(p -> {
int ordinal = p.getOrdinal();
if (ordinal < 0 || ordinal >= ordinals.length) {
throw new HelenusMappingException(
"invalid ordinal "
+ ordinal
+ " found for property "
+ p.getPropertyName()
+ " in "
+ p.getEntity());
throw new HelenusMappingException("invalid ordinal " + 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());
"detected two or more properties with the same ordinal " + ordinal + " in " + p.getEntity());
}
ordinals[ordinal] = true;
});
for (int i = 0; i != ordinals.length; ++i) {
@ -349,18 +250,15 @@ public final class HelenusMappingEntity implements HelenusEntity {
throw new HelenusMappingException("detected absent ordinal " + i + " in " + this);
}
}
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
str.append(iface.getSimpleName())
.append("(")
.append(name.getName())
.append(") ")
.append(type.name().toLowerCase())
.append(":\n");
str.append(iface.getSimpleName()).append("(").append(name.getName()).append(") ")
.append(type.name().toLowerCase()).append(":\n");
for (HelenusProperty prop : getOrderedProperties()) {
str.append(prop.toString());
@ -368,4 +266,5 @@ public final class HelenusMappingEntity implements HelenusEntity {
}
return str.toString();
}
}

View file

@ -1,6 +1,5 @@
/*
* Copyright (C) 2015 The Casser Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Copyright (C) 2015 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.
@ -16,13 +15,15 @@
*/
package net.helenus.mapping;
import com.datastax.driver.core.Metadata;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Optional;
import java.util.function.Function;
import javax.validation.ConstraintValidator;
import com.datastax.driver.core.Metadata;
import net.helenus.core.SessionRepository;
import net.helenus.mapping.javatype.AbstractJavaType;
import net.helenus.mapping.javatype.MappingJavaTypes;
@ -36,7 +37,6 @@ public final class HelenusMappingProperty implements HelenusProperty {
private final String propertyName;
private final Optional<IdentityName> indexName;
private final boolean caseSensitiveIndex;
private final boolean idempotent;
private final ColumnInformation columnInfo;
@ -44,10 +44,12 @@ public final class HelenusMappingProperty implements HelenusProperty {
private final Class<?> javaType;
private final AbstractJavaType abstractJavaType;
private final AbstractDataType dataType;
private final ConstraintValidator<? extends Annotation, ?>[] validators;
private volatile Optional<Function<Object, Object>> readConverter = null;
private volatile Optional<Function<Object, Object>> writeConverter = null;
private final ConstraintValidator<? extends Annotation, ?>[] validators;
public HelenusMappingProperty(HelenusMappingEntity entity, Method getter, Metadata metadata) {
this.entity = entity;
this.getter = getter;
@ -58,22 +60,12 @@ public final class HelenusMappingProperty implements HelenusProperty {
this.columnInfo = new ColumnInformation(getter);
switch (this.columnInfo.getColumnType()) {
case PARTITION_KEY:
case CLUSTERING_COLUMN:
this.idempotent = true;
break;
default:
this.idempotent = MappingUtil.idempotent(getter);
}
this.genericJavaType = getter.getGenericReturnType();
this.javaType = getter.getReturnType();
this.abstractJavaType = MappingJavaTypes.resolveJavaType(this.javaType);
this.dataType =
abstractJavaType.resolveDataType(
this.getter, this.genericJavaType, this.columnInfo.getColumnType(), metadata);
this.dataType = abstractJavaType.resolveDataType(this.getter, this.genericJavaType,
this.columnInfo.getColumnType(), metadata);
this.validators = MappingUtil.getValidators(getter);
}
@ -123,11 +115,6 @@ public final class HelenusMappingProperty implements HelenusProperty {
return caseSensitiveIndex;
}
@Override
public boolean isIdempotent() {
return idempotent;
}
@Override
public String getPropertyName() {
return propertyName;
@ -182,6 +169,7 @@ public final class HelenusMappingProperty implements HelenusProperty {
ColumnType type = this.getColumnType();
switch (type) {
case PARTITION_KEY :
str.append("partition_key[");
str.append(this.getOrdinal());
@ -204,6 +192,7 @@ public final class HelenusMappingProperty implements HelenusProperty {
case COLUMN :
break;
}
Optional<IdentityName> idx = this.getIndexName();
@ -213,4 +202,5 @@ public final class HelenusMappingProperty implements HelenusProperty {
return str.toString();
}
}

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