From e11468ab4abe58eda877a5785399356830ca2baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per-=C3=85ke=20Minborg?= Date: Sat, 1 Oct 2016 10:40:20 -0700 Subject: [PATCH] First step in refactor of manager --- .../entity/GeneratedEntityTranslator.java | 57 +++++----- .../config/identifier/ColumnIdentifier.java | 8 +- .../config/identifier/TableIdentifier.java | 15 ++- .../identifier/TableIdentifierImpl.java | 14 +-- .../identifier/TableIdentifierTest.java | 32 ++++++ .../component/SqlStreamSupplierComponent.java | 24 +++++ .../component/StreamSupplierComponent.java | 40 +++---- .../core/internal/AbstractSpeedment.java | 7 +- .../NativeStreamSupplierComponentImpl.java | 48 --------- .../SqlStreamSupplierComponentImpl.java | 51 +++++++++ ...SqlStreamSupplierComponentImplSupport.java | 21 ++++ .../db/AsynchronousQueryResultImpl.java | 2 +- .../manager/JdbcManagerSupportImpl.java | 2 +- .../core/internal/stream/StreamUtil.java | 2 +- .../runtime/core/manager/AbstractManager.java | 14 ++- .../runtime/core/manager/Manager.java | 100 +++++++++++++++++- .../runtime/core/stream/StreamDecorator.java | 85 ++++++++++----- .../stream/parallel/ParallelStrategy.java | 51 +++++++-- .../ComputeIntensityParallelStrategyTest.java | 8 +- 19 files changed, 416 insertions(+), 165 deletions(-) create mode 100644 runtime-parent/runtime-config/src/test/java/com/speedment/runtime/config/identifier/TableIdentifierTest.java create mode 100644 runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/component/SqlStreamSupplierComponent.java delete mode 100644 runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/NativeStreamSupplierComponentImpl.java create mode 100644 runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/SqlStreamSupplierComponentImpl.java create mode 100644 runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/SqlStreamSupplierComponentImplSupport.java diff --git a/generator-parent/generator-core/src/main/java/com/speedment/generator/core/internal/translator/entity/GeneratedEntityTranslator.java b/generator-parent/generator-core/src/main/java/com/speedment/generator/core/internal/translator/entity/GeneratedEntityTranslator.java index 84640ced3e..19ff460b27 100644 --- a/generator-parent/generator-core/src/main/java/com/speedment/generator/core/internal/translator/entity/GeneratedEntityTranslator.java +++ b/generator-parent/generator-core/src/main/java/com/speedment/generator/core/internal/translator/entity/GeneratedEntityTranslator.java @@ -61,6 +61,7 @@ import com.speedment.runtime.config.util.DocumentDbUtil; import static com.speedment.runtime.config.util.DocumentUtil.Name.DATABASE_NAME; import com.speedment.runtime.config.identifier.ColumnIdentifier; +import com.speedment.runtime.config.identifier.TableIdentifier; import static com.speedment.runtime.config.util.DocumentUtil.relativeName; /** @@ -69,9 +70,9 @@ * @author Per-Åke Minborg */ public final class GeneratedEntityTranslator extends AbstractEntityAndManagerTranslator { - + public final static String IDENTIFIER_NAME = "Identifier"; - + private @Inject Injector injector; private @Inject TypeMapperComponent typeMappers; @@ -82,12 +83,16 @@ public GeneratedEntityTranslator(Table table) { @Override protected Interface makeCodeGenModel(File file) { + final Type tableIdentifierType = SimpleParameterizedType.create(TableIdentifier.class, getSupport().entityType()); + final Enum identifierEnum = Enum.of(IDENTIFIER_NAME) .add(Field.of("columnName", String.class).private_().final_()) + .add(Field.of("tableIdentifier", tableIdentifierType).private_().final_()) .add(SimpleParameterizedType.create(ColumnIdentifier.class, getSupport().entityType())) .add(Constructor.of() .add(Field.of("columnName", String.class)) .add("this.columnName = columnName;") + .add("this.tableIdentifier = TableIdentifier.of(getDbmsName(), getSchemaName(), getTableName());") ) .add(Method.of("getDbmsName", String.class).public_() .add(OVERRIDE) @@ -104,6 +109,10 @@ protected Interface makeCodeGenModel(File file) { .add(Method.of("getColumnName", String.class).public_() .add(OVERRIDE) .add("return this.columnName;") + ) + .add(Method.of("asTableIdentifier", tableIdentifierType).public_() + .add(OVERRIDE) + .add("return this.tableIdentifier;") ); return newBuilder(file, getSupport().generatedEntityName()) @@ -111,7 +120,6 @@ protected Interface makeCodeGenModel(File file) { * General */ .forEveryTable((intrf, col) -> intrf.public_().add(identifierEnum)) - /** * Getters */ @@ -132,7 +140,6 @@ protected Interface makeCodeGenModel(File file) { ) ); }) - /** * Setters */ @@ -150,7 +157,6 @@ protected Interface makeCodeGenModel(File file) { .add(RETURN.setText("this " + getSupport().entityName() + " instance"))) ); }) - /** * Finders */ @@ -164,16 +170,16 @@ protected Interface makeCodeGenModel(File file) { file.add(Import.of(fuSupport.entityType())); intrf.add(Method.of(FINDER_METHOD_PREFIX + getSupport().typeName(col), - col.isNullable() - ? DefaultType.optional(fuSupport.entityType()) - : fuSupport.entityType() - ) + col.isNullable() + ? DefaultType.optional(fuSupport.entityType()) + : fuSupport.entityType() + ) .set(Javadoc.of( - "Queries the specified manager for the referenced " + - fuSupport.entityName() + ". If no such " + - fuSupport.entityName() + - " exists, an {@code NullPointerException} will be thrown." - ).add(DefaultJavadocTag.PARAM.setValue("foreignManager").setText("the manager to query for the entity")) + "Queries the specified manager for the referenced " + + fuSupport.entityName() + ". If no such " + + fuSupport.entityName() + + " exists, an {@code NullPointerException} will be thrown." + ).add(DefaultJavadocTag.PARAM.setValue("foreignManager").setText("the manager to query for the entity")) .add(DefaultJavadocTag.RETURN.setText("the foreign entity referenced")) ) .add(Field.of("foreignManager", SimpleParameterizedType.create( @@ -182,18 +188,17 @@ protected Interface makeCodeGenModel(File file) { ); }); }) - /** * Fields */ .forEveryColumn((intrf, col) -> { - final EntityTranslatorSupport.ReferenceFieldType ref = - EntityTranslatorSupport.getReferenceFieldType( + final EntityTranslatorSupport.ReferenceFieldType ref + = EntityTranslatorSupport.getReferenceFieldType( file, getSupport().tableOrThrow(), col, getSupport().entityType(), injector ); - final Type entityType = getSupport().entityType(); + final Type entityType = getSupport().entityType(); final String shortEntityName = getSupport().entityName(); file.add(Import.of(entityType)); @@ -210,9 +215,9 @@ file, getSupport().tableOrThrow(), col, getSupport().entityType(), injector .map(fkc -> { final FkHolder fu = new FkHolder(injector, fkc.getParentOrThrow()); final TranslatorSupport fuSupport = fu.getForeignEmt().getSupport(); - - return ", " + fuSupport.entityName() + "." + - fuSupport.namer().javaStaticFieldName( + + return ", " + fuSupport.entityName() + "." + + fuSupport.namer().javaStaticFieldName( fu.getForeignColumn().getJavaName() ); }).orElse(""); @@ -265,10 +270,10 @@ file, getSupport().tableOrThrow(), col, getSupport().entityType(), injector @Override protected String getJavadocRepresentText() { - return "The generated base for the {@link " + - getSupport().entityType().getTypeName() + - "}-interface representing entities of the {@code " + - getDocument().getName() + "}-table in the database."; + return "The generated base for the {@link " + + getSupport().entityType().getTypeName() + + "}-interface representing entities of the {@code " + + getDocument().getName() + "}-table in the database."; } @Override @@ -296,7 +301,7 @@ static Type getterReturnType(TypeMapperComponent typeMappers, Column col) { retType = OptionalBoolean.class; } else { retType = SimpleParameterizedType.create(Optional.class, type); - } + } } else { retType = type; } diff --git a/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/identifier/ColumnIdentifier.java b/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/identifier/ColumnIdentifier.java index 33582711b8..ef7d64464c 100644 --- a/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/identifier/ColumnIdentifier.java +++ b/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/identifier/ColumnIdentifier.java @@ -46,4 +46,10 @@ public interface ColumnIdentifier extends HasDbmsName, HasSchemaName, HasTableName, - HasColumnName {} + HasColumnName { + + default TableIdentifier asTableIdentifier() { + return TableIdentifier.of(getDbmsName(), getSchemaName(), getTableName()); + } + +} diff --git a/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/identifier/TableIdentifier.java b/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/identifier/TableIdentifier.java index fc9db11fee..397fa393b4 100644 --- a/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/identifier/TableIdentifier.java +++ b/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/identifier/TableIdentifier.java @@ -21,6 +21,9 @@ import com.speedment.runtime.config.identifier.trait.HasTableName; import com.speedment.runtime.config.internal.identifier.TableIdentifierImpl; import com.speedment.runtime.config.util.DocumentDbUtil; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; /** * Identifies a particular Table. The identifier is an immutable non-complex @@ -30,7 +33,7 @@ * To find the actual documents referred to by the identifier, the following * utility methods can be used: *
    - + * *
  • DocumentDbUtil#referencedTable(Project, Project, TableIdentifier) *
  • DocumentDbUtil#referencedSchema(Project, Project, TableIdentifier) *
  • DocumentDbUtil#referencedDbms(Project, TableIdentifier) @@ -47,8 +50,16 @@ public interface TableIdentifier extends HasSchemaName, HasTableName { + static class Hidden { + + private static final Map INTERNED = new ConcurrentHashMap<>(); + + } + static TableIdentifier of(String dbmsName, String schemaName, String tableName) { - return new TableIdentifierImpl<>(dbmsName, schemaName, tableName); + final TableIdentifier newTableIdentity = new TableIdentifierImpl<>(dbmsName, schemaName, tableName); + Hidden.INTERNED.putIfAbsent(newTableIdentity, newTableIdentity); + return Hidden.INTERNED.get(newTableIdentity); } } diff --git a/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/internal/identifier/TableIdentifierImpl.java b/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/internal/identifier/TableIdentifierImpl.java index 253c257b6b..84d931f988 100644 --- a/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/internal/identifier/TableIdentifierImpl.java +++ b/runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/internal/identifier/TableIdentifierImpl.java @@ -66,18 +66,18 @@ public boolean equals(Object obj) { if (getClass() != obj.getClass()) { return false; } - if (this.hashCode != obj.hashCode()) { + if (hashCode != obj.hashCode()) { return false; } final TableIdentifierImpl other = (TableIdentifierImpl) obj; - if (!Objects.equals(this.dbmsName, other.dbmsName)) { + if (!Objects.equals(dbmsName, other.dbmsName)) { return false; } - if (!Objects.equals(this.schemaName, other.schemaName)) { + if (!Objects.equals(schemaName, other.schemaName)) { return false; } - if (!Objects.equals(this.tableName, other.tableName)) { + if (!Objects.equals(tableName, other.tableName)) { return false; } return true; @@ -85,9 +85,9 @@ public boolean equals(Object obj) { private int privateHashCode() { int hash = 5; - hash = 53 * hash + Objects.hashCode(this.dbmsName); - hash = 53 * hash + Objects.hashCode(this.schemaName); - hash = 53 * hash + Objects.hashCode(this.tableName); + hash = 53 * hash + Objects.hashCode(dbmsName); + hash = 53 * hash + Objects.hashCode(schemaName); + hash = 53 * hash + Objects.hashCode(tableName); return hash; } diff --git a/runtime-parent/runtime-config/src/test/java/com/speedment/runtime/config/identifier/TableIdentifierTest.java b/runtime-parent/runtime-config/src/test/java/com/speedment/runtime/config/identifier/TableIdentifierTest.java new file mode 100644 index 0000000000..af12750e37 --- /dev/null +++ b/runtime-parent/runtime-config/src/test/java/com/speedment/runtime/config/identifier/TableIdentifierTest.java @@ -0,0 +1,32 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.speedment.runtime.config.identifier; + +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author Per Minborg + */ +public class TableIdentifierTest { + + @Test + public void testOf() { + final String db = "db"; + final String sc = "sc"; + final String ta = "ta"; + + TableIdentifier ti0 = TableIdentifier.of(db, sc, ta); + TableIdentifier ti1 = TableIdentifier.of(db, sc, ta); + TableIdentifier ti2 = TableIdentifier.of(db, sc, "Arne"); + + assertTrue(ti0 == ti1); // Make sure that the interface interns duplicates + assertFalse(ti0 == ti2); + + } + +} diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/component/SqlStreamSupplierComponent.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/component/SqlStreamSupplierComponent.java new file mode 100644 index 0000000000..e4438e7b69 --- /dev/null +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/component/SqlStreamSupplierComponent.java @@ -0,0 +1,24 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.speedment.runtime.core.component; + +import java.sql.ResultSet; + +/** + * + * @author Per Minborg + */ +public interface SqlStreamSupplierComponent extends StreamSupplierComponent { + + public interface Support { + + String getSql(); + + ENTITY from(ResultSet rs); + + } + +} diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/component/StreamSupplierComponent.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/component/StreamSupplierComponent.java index 44bc9c92bd..d46bf7aa95 100644 --- a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/component/StreamSupplierComponent.java +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/component/StreamSupplierComponent.java @@ -17,6 +17,7 @@ package com.speedment.runtime.core.component; import com.speedment.common.injector.annotation.InjectKey; +import com.speedment.runtime.config.identifier.TableIdentifier; import com.speedment.runtime.core.field.trait.HasComparableOperators; import com.speedment.runtime.core.stream.StreamDecorator; @@ -32,48 +33,35 @@ @InjectKey(StreamSupplierComponent.class) public interface StreamSupplierComponent { - /** - * Does all the preparations required to start serving streams - * before returning. The component must never be called before - * this method has returned. - */ - void start(); - - /** - * Stops the component, releasing any resources. When this method - * returns, the component must never be called again. - */ - void stop(); - /** * Basic stream over all entities. * - * @param entity type - * @param entityClass the entity class - * @param decorator decorates the stream before building it - * @return a stream for the given entity class + * @param entity type + * @param tableIdentifier the identifier to use + * @param decorator decorates the stream before building it + * @return a stream for the given entity class */ - Stream stream(Class entityClass, StreamDecorator decorator); + Stream stream(TableIdentifier tableIdentifier, StreamDecorator decorator); /** * Finds a particular entity in the source where the specified field has * the specified value. This is a form of key-value lookup than can * potentially be more efficient with for an example foreign key references. * - * @param the entity type - * @param the java type of the column - * @param entityClass the entity interface .class - * @param field the field to select on - * @param value the value of that field for the entity to return - * @return entity found or empty if none existed with that value + * @param the entity type + * @param the java type of the column + * @param tableIdentifier the identifier to use + * @param field the field to select on + * @param value the value of that field for the entity to return + * @return entity found or empty if none existed with that value */ default > Optional findAny( - Class entityClass, + TableIdentifier tableIdentifier, HasComparableOperators field, V value) { - return stream(entityClass, StreamDecorator.IDENTITY) + return stream(tableIdentifier, StreamDecorator.identity()) .filter(field.equal(value)) .findAny(); } diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/AbstractSpeedment.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/AbstractSpeedment.java index 4cef0c6c36..34aa45ec15 100644 --- a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/AbstractSpeedment.java +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/AbstractSpeedment.java @@ -27,7 +27,7 @@ import com.speedment.runtime.core.internal.component.EntityManagerImpl; import com.speedment.runtime.core.internal.component.InfoComponentImpl; import com.speedment.runtime.core.internal.component.ManagerComponentImpl; -import com.speedment.runtime.core.internal.component.NativeStreamSupplierComponentImpl; +import com.speedment.runtime.core.internal.component.SqlStreamSupplierComponentImpl; import com.speedment.runtime.core.internal.component.PasswordComponentImpl; import com.speedment.runtime.core.internal.component.PrimaryKeyFactoryComponentImpl; import com.speedment.runtime.core.internal.component.ProjectComponentImpl; @@ -47,13 +47,12 @@ public abstract class AbstractSpeedment implements Speedment { public static InjectBundle include() { - return InjectBundle.of( - InfoComponentImpl.class, + return InjectBundle.of(InfoComponentImpl.class, ConnectionPoolComponentImpl.class, DbmsHandlerComponentImpl.class, EntityManagerImpl.class, ManagerComponentImpl.class, - NativeStreamSupplierComponentImpl.class, + SqlStreamSupplierComponentImpl.class, PasswordComponentImpl.class, PrimaryKeyFactoryComponentImpl.class, ProjectComponentImpl.class, diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/NativeStreamSupplierComponentImpl.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/NativeStreamSupplierComponentImpl.java deleted file mode 100644 index a7e46287c5..0000000000 --- a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/NativeStreamSupplierComponentImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * - * Copyright (c) 2006-2016, Speedment, Inc. 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 com.speedment.runtime.core.internal.component; - -import com.speedment.common.injector.annotation.Inject; -import com.speedment.runtime.core.component.ManagerComponent; -import com.speedment.runtime.core.component.StreamSupplierComponent; -import com.speedment.runtime.core.stream.StreamDecorator; - -import java.util.stream.Stream; - -/** - * - * @author Per Minborg - */ -public class NativeStreamSupplierComponentImpl implements StreamSupplierComponent { - - private @Inject ManagerComponent managerComponent; - - @Override - public Stream stream(Class entityClass, StreamDecorator decorator) { - return managerComponent.managerOf(entityClass).stream(); // TODO use decorator - } - - @Override - public void start() { - // Do nothing. - } - - @Override - public void stop() { - // Do nothing. - } -} \ No newline at end of file diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/SqlStreamSupplierComponentImpl.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/SqlStreamSupplierComponentImpl.java new file mode 100644 index 0000000000..7f1a4e5f4e --- /dev/null +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/SqlStreamSupplierComponentImpl.java @@ -0,0 +1,51 @@ +/** + * + * Copyright (c) 2006-2016, Speedment, Inc. 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 com.speedment.runtime.core.internal.component; + +import com.speedment.runtime.config.identifier.TableIdentifier; +import com.speedment.runtime.core.component.SqlStreamSupplierComponent; +import com.speedment.runtime.core.stream.StreamDecorator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import java.util.stream.Stream; + +/** + * + * @author Per Minborg + */ +public class SqlStreamSupplierComponentImpl implements SqlStreamSupplierComponent { + + private final Map supportMap; + + public SqlStreamSupplierComponentImpl() { + this.supportMap = new ConcurrentHashMap<>(); + } + + @Override + public Stream stream(TableIdentifier tableIdentifier, StreamDecorator decorator) { + final SqlStreamSupplierComponent.Support support = supportMap.computeIfAbsent(tableIdentifier, this::makeSupport); + + return Stream.empty(); // Todo: Generate stream. + } + + private SqlStreamSupplierComponent.Support makeSupport(TableIdentifier tableIdentifier) { + // Calculate stuff from the TableIdentifier and some other components... + return null; + } + +} diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/SqlStreamSupplierComponentImplSupport.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/SqlStreamSupplierComponentImplSupport.java new file mode 100644 index 0000000000..c28ec562c4 --- /dev/null +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/component/SqlStreamSupplierComponentImplSupport.java @@ -0,0 +1,21 @@ +package com.speedment.runtime.core.internal.component; + +import com.speedment.runtime.core.component.SqlStreamSupplierComponent; + +/** + * + * @author Per Minborg + */ +public class SqlStreamSupplierComponentImplSupport { + + private final SqlStreamSupplierComponent.Support support; + + public SqlStreamSupplierComponentImplSupport(SqlStreamSupplierComponent.Support support) { + this.support = support; + } + + public String getSql() { + return null; + } + +} diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/db/AsynchronousQueryResultImpl.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/db/AsynchronousQueryResultImpl.java index 984d17dfa4..05769ee9d6 100644 --- a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/db/AsynchronousQueryResultImpl.java +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/db/AsynchronousQueryResultImpl.java @@ -69,7 +69,7 @@ public AsynchronousQueryResultImpl( setValues(values); // requireNonNull in setter setRsMapper(rsMapper); // requireNonNull in setter this.connectionSupplier = requireNonNull(connectionSupplier); - parallelStrategy = ParallelStrategy.DEFAULT; + parallelStrategy = ParallelStrategy.computeIntensityDefault(); setState(State.INIT); } diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/manager/JdbcManagerSupportImpl.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/manager/JdbcManagerSupportImpl.java index 0731e25afe..5510d443f0 100644 --- a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/manager/JdbcManagerSupportImpl.java +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/manager/JdbcManagerSupportImpl.java @@ -149,7 +149,7 @@ public String fullColumnName(Field field) { @Override public Stream stream() { - return nativeStream(StreamDecorator.IDENTITY); + return nativeStream(StreamDecorator.identity()); } @Override diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/stream/StreamUtil.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/stream/StreamUtil.java index 647893fcab..049375baa7 100644 --- a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/stream/StreamUtil.java +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/stream/StreamUtil.java @@ -71,7 +71,7 @@ public static Stream asStream(ResultSet resultSet, SqlFunction iterator = new ResultSetIterator<>(resultSet, mapper); // return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.IMMUTABLE + Spliterator.NONNULL), false); - return asStream(resultSet, mapper, ParallelStrategy.DEFAULT); + return asStream(resultSet, mapper, ParallelStrategy.computeIntensityDefault()); } public static Stream asStream(ResultSet resultSet, SqlFunction mapper, ParallelStrategy parallelStrategy) { diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/manager/AbstractManager.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/manager/AbstractManager.java index d86ac45871..dd91cb0cec 100644 --- a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/manager/AbstractManager.java +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/manager/AbstractManager.java @@ -30,6 +30,8 @@ import static com.speedment.common.injector.State.INITIALIZED; import static com.speedment.common.injector.State.RESOLVED; import static com.speedment.common.invariant.NullUtil.requireNonNulls; +import com.speedment.runtime.core.component.StreamSupplierComponent; +import com.speedment.runtime.core.stream.StreamDecorator; import static java.util.Objects.requireNonNull; /** @@ -41,7 +43,9 @@ */ public abstract class AbstractManager implements Manager { - private ManagerSupport support; + private StreamSupplierComponent streamSupplierComponent; + + private ManagerSupport support; // Move to SqlStreamSupplierComponent and CudComponent // Hold these fields internally so that exposing methods may be compared by equality private final EntityCreator entityCreator = this::entityCreate; private final EntityCopier entityCopier = this::entityCopy; @@ -56,6 +60,7 @@ protected AbstractManager() { final void createSupport( Injector injector, @WithState(INITIALIZED) ProjectComponent projectComponent, + @WithState(INITIALIZED) StreamSupplierComponent streamSupplierComponent, @WithState(INITIALIZED) ResultSetMapperComponent resultSetComponent, @WithState(INITIALIZED) DbmsHandlerComponent dbmsHandlerComponent) { @@ -65,6 +70,7 @@ final void createSupport( persister = support::persist; updater = support::update; remover = support::remove; + this.streamSupplierComponent = streamSupplierComponent; } @ExecuteBefore(RESOLVED) @@ -72,7 +78,7 @@ final void install( @WithState(INITIALIZED) ManagerComponent managerComponent, @WithState(INITIALIZED) ProjectComponent projectComponent) { - requireNonNull(projectComponent); // Must be initialized first. + requireNonNull(projectComponent); // Must be initialized first. // Not really now...!! managerComponent.put(this); } @@ -89,8 +95,8 @@ public EntityCopier entityCopier() { } @Override - public final Stream stream() { - return support.stream(); + public Stream stream(StreamDecorator decorator) { + return streamSupplierComponent.stream(getTableIdentifier(), StreamDecorator.identity()); } @Override diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/manager/Manager.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/manager/Manager.java index 5932145cdb..68628e7cf1 100644 --- a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/manager/Manager.java +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/manager/Manager.java @@ -19,6 +19,7 @@ import com.speedment.runtime.config.identifier.TableIdentifier; import com.speedment.runtime.core.exception.SpeedmentException; import com.speedment.runtime.core.field.Field; +import com.speedment.runtime.core.stream.StreamDecorator; import java.util.stream.Stream; @@ -194,7 +195,104 @@ public interface Manager { * @see java.util.stream * @see Stream */ - Stream stream(); + default Stream stream() { + return stream(StreamDecorator.identity()); + } + + + /** + * Creates and returns a new {@link Stream} over all entities in the + * underlying database. This is the main query API for Speedment. + *

    + * This is an inexpensive O(1) operation that will complete in + * constant time regardless of the number of entities in the underlying + * database. + *

    + * The returned stream is aware of its own pipeline and will optimize + * its own pipeline whenever it encounters a Terminal + * Operation so that it will only iterate over a minimum set of + * matching entities. + *

    + * When a Terminal Operation is eventually called on the {@link Stream}, + * that execution time of the Terminal Operation will depend on the + * optimized pipeline and the entities in the underlying database. + *

    + * The Stream will be automatically + * {@link Stream#onClose(java.lang.Runnable) closed} after the Terminal + * Operation is completed or if an Exception is thrown during the Terminal + * Operation. + *

    + * Some of the Terminal Operations are: + *

      + *
    • {@link Stream#forEach(java.util.function.Consumer) forEach(Consumer)} + *
    • {@link Stream#forEachOrdered(java.util.function.Consumer) forEachOrdered(Consumer)} + *
    • {@link Stream#toArray() toArray()} + *
    • {@link Stream#toArray(java.util.function.IntFunction) toArray(IntFunction)} + *
    • {@link Stream#reduce(java.util.function.BinaryOperator) reduce(BinaryOperation} + *
    • {@link Stream#reduce(java.lang.Object, java.util.function.BinaryOperator) reduce(Object, BinaryOperator)} + *
    • {@link Stream#reduce(java.lang.Object, java.util.function.BiFunction, java.util.function.BinaryOperator) reduce(Object, BiFunction, BinaryOperator)} + *
    • {@link Stream#collect(java.util.stream.Collector) collect(Collector)} + *
    • {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer) collect(Supplier, BiConsumer, BiConsumer)} + *
    • {@link Stream#min(java.util.Comparator) min(Comparator)} + *
    • {@link Stream#max(java.util.Comparator) min(Comparator)} + *
    • {@link Stream#count() count()} + *
    • {@link Stream#anyMatch(java.util.function.Predicate) anyMatch(Predicate)} + *
    • {@link Stream#noneMatch(java.util.function.Predicate) noneMatch(Predicate)} + *
    • {@link Stream#findFirst() findFirst()} + *
    • {@link Stream#findAny() findAny()} + *
    • {@link Stream#iterator() iterator()} + *
    + *

    + * Any Terminating Operation may throw a {@link SpeedmentException} if the + * underlying database throws an Exception (e.g. an SqlException) + *

    + * Because the Stream may short-circuit operations in the Stream pipeline, + * methods having side-effects (like + * {@link Stream#peek(java.util.function.Consumer) peek(Consumer)} will + * potentially be affected by the optimization. + *

    + * Here are some examples of how the stream optimization might work: + *

      + *
    • + *
      {@code stream
      +     *   .filter(Hare.NAME.equal("Henry")
      +     *   .collect(toList());}
      + *
      {@code -> select * from hares where name='Henry'}
      + *
    • + *
    • + *
      {@code stream.count();}
      + *
      {@code -> select count(*) from hares}
      + *
    • + *
    • + *
      {@code stream
      +     *   .filter(Hare.NAME.equal("Henry")
      +     *   .count();}
      + *
      {@code -> select count(*) from hares where
      +     *   name='Henry'}
      + *

      + *

    • + *
    • + *
      {@code stream
      +     *   .filter(Hare.NAME.equal("Henry")
      +     *   .filter(Hare.AGE.greaterThan(5)
      +     *   .count();}
      + *
      {@code -> select count(*) from hares where
      +     *          name ='Henry'
      +     *        and
      +     *          age > 5}
      + *
    • + *
    + * + * + * @param decorator the implementation for decorating this stream + * @return a new stream over all entities in this table + * @throws SpeedmentException if an error occurs during a Terminal Operation + * (e.g. an SqlException is thrown by the underlying database) + * @see java.util.stream + * @see Stream + */ + Stream stream(StreamDecorator decorator); + /** * Persists the provided entity to the underlying database and returns a diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/stream/StreamDecorator.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/stream/StreamDecorator.java index 633caaa876..6fd2adcaf3 100644 --- a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/stream/StreamDecorator.java +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/stream/StreamDecorator.java @@ -29,18 +29,19 @@ * Speedment before execution. This can for an example be used to perform * optimizations. * - * @author Emil Forslund - * @since 2.2.0 + * @author Emil Forslund + * @since 2.2.0 */ public interface StreamDecorator { - final static StreamDecorator IDENTITY = new StreamDecorator() { - @Override - public StreamDecorator and(StreamDecorator other) { - return other; - } - - }; + /** + * Returns a StreamDecorator which does not alter the Stream in any way. + * + * @return a StreamDecorator which does not alter the Stream in any way + */ + static StreamDecorator identity() { + return Hidden.IDENTITY; + } default StreamDecorator and(StreamDecorator other) { if (this instanceof ComposedStreamDecorator) { @@ -49,14 +50,14 @@ default StreamDecorator and(StreamDecorator other) { return new ComposedStreamDecorator(this, other); } - /** + /** * Method to be used to modify or configure the final stream before it is * returned to the application. * - * @param the entity type - * @param the stream type - * @param stream final stream before it is returned to the application - * @return the modified or configured final stream + * @param the entity type + * @param the stream type + * @param stream final stream before it is returned to the application + * @return the modified or configured final stream */ default > S applyOnFinal(S stream) { return stream; @@ -74,10 +75,10 @@ default

    P apply(P pipeline) { * Method to be used to modify or configure the initial stream from the data * source. * - * @param the entity type - * @param the stream type - * @param stream from the data source - * @return the modified or configured stream + * @param the entity type + * @param the stream type + * @param stream from the data source + * @return the modified or configured stream */ default > S applyOnInitial(S stream) { return stream; @@ -88,10 +89,10 @@ default > S applyOnInitial(S stream) { * {@link ParallelStrategy} defines how parallel streams are divided amongst * the available execution threads. * - * @param type of strategy receiver - * @param hasParallelStrategy to apply the strategy on - * @return the object {@link HasParallelStrategy} to use - * for this {@link Stream} + * @param type of strategy receiver + * @param hasParallelStrategy to apply the strategy on + * @return the object {@link HasParallelStrategy} to use for this + * {@link Stream} */ default H apply(H hasParallelStrategy) { return hasParallelStrategy; @@ -102,27 +103,36 @@ default H apply(H hasParallelStrategy) { * {@link ParallelStrategy#COMPUTE_INTENSITY_MEDIUM COMPUTE_INTENSITY_MEDIUM} * parallel strategy. * + * @return a StreamDecorator * @see ParallelStrategy#COMPUTE_INTENSITY_MEDIUM COMPUTE_INTENSITY_MEDIUM */ - final static StreamDecorator COMPUTE_INTENSITY_MEDIUM = of(ParallelStrategy.COMPUTE_INTENSITY_MEDIUM); - + static StreamDecorator computeIntensityMedium() { + return Hidden.COMPUTE_INTENSITY_MEDIUM; + } + /** * A {@link StreamDecorator} that modifies the stream according to the * {@link ParallelStrategy#COMPUTE_INTENSITY_HIGH COMPUTE_INTENSITY_HIGH} * parallel strategy. * + * @return a StreamDecorator * @see ParallelStrategy#COMPUTE_INTENSITY_HIGH COMPUTE_INTENSITY_HIGH */ - final static StreamDecorator COMPUTE_INTENSITY_HIGH = of(ParallelStrategy.COMPUTE_INTENSITY_HIGH); - + static StreamDecorator computeIntensityHigh() { + return Hidden.COMPUTE_INTENSITY_HIGH; + } + /** * A {@link StreamDecorator} that modifies the stream according to the * {@link ParallelStrategy#COMPUTE_INTENSITY_EXTREME COMPUTE_INTENSITY_EXTREME} * parallel strategy. * + * @return a StreamDecorator * @see ParallelStrategy#COMPUTE_INTENSITY_EXTREME COMPUTE_INTENSITY_EXTREME */ - final static StreamDecorator COMPUTE_INTENSITY_EXTREAM = of(ParallelStrategy.COMPUTE_INTENSITY_EXTREME); + static StreamDecorator computeIntensityExtreme() { + return Hidden.COMPUTE_INTENSITY_EXTREME; + } static StreamDecorator of(final ParallelStrategy parallelStrategy) { return new StreamDecorator() { @@ -134,4 +144,23 @@ public H apply(H hasParallelStrategy) { }; } -} \ No newline at end of file + + static class Hidden { + + final static StreamDecorator IDENTITY = new StreamDecorator() { + @Override + public StreamDecorator and(StreamDecorator other) { + return other; + } + + }; + + final static StreamDecorator COMPUTE_INTENSITY_MEDIUM = of(ParallelStrategy.computeIntensityMedium()); + + final static StreamDecorator COMPUTE_INTENSITY_HIGH = of(ParallelStrategy.computeIntensityHigh()); + + final static StreamDecorator COMPUTE_INTENSITY_EXTREME = of(ParallelStrategy.computeIntensityExtreme()); + + } + +} diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/stream/parallel/ParallelStrategy.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/stream/parallel/ParallelStrategy.java index 58dc1eff2b..cdbacfad33 100644 --- a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/stream/parallel/ParallelStrategy.java +++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/stream/parallel/ParallelStrategy.java @@ -16,7 +16,6 @@ */ package com.speedment.runtime.core.stream.parallel; - import com.speedment.runtime.core.internal.stream.parallel.ComputeIntensityExtremeParallelStrategy; import com.speedment.runtime.core.internal.stream.parallel.ComputeIntensityHighParallelStrategy; import com.speedment.runtime.core.internal.stream.parallel.ComputeIntensityMediumParallelStrategy; @@ -27,7 +26,7 @@ /** * - * @author Per Minborg + * @author Per Minborg */ @FunctionalInterface @@ -37,28 +36,47 @@ public interface ParallelStrategy { * A Parallel Strategy that is Java's default Iterator to * Spliterator converter. It favors relatively large sets (in * the ten thousands or more) with low computational overhead. + * + * @return a ParallelStrategy */ - ParallelStrategy DEFAULT = Spliterators::spliteratorUnknownSize; + static ParallelStrategy computeIntensityDefault() { + return Hidden.COMPUTE_INTENSITY_DEFAULT; + } + /** * A Parallel Strategy that favors relatively small to medium sets with * medium computational overhead. + * + * @return a ParallelStrategy */ - ParallelStrategy COMPUTE_INTENSITY_MEDIUM = new ComputeIntensityMediumParallelStrategy(); + static ParallelStrategy computeIntensityMedium() { + return Hidden.COMPUTE_INTENSITY_MEDIUM; + } + /** * A Parallel Strategy that favors relatively small to medium sets with high * computational overhead. + * + * @return a ParallelStrategy */ - ParallelStrategy COMPUTE_INTENSITY_HIGH = new ComputeIntensityHighParallelStrategy(); + static ParallelStrategy computeIntensityHigh() { + return Hidden.COMPUTE_INTENSITY_HIGH; + } + /** - * A Parallel Strategy that favors small sets with extremely high computational - * overhead. The set will be split up in solitary elements that are executed - * separately in their own thread. + * A Parallel Strategy that favors small sets with extremely high + * computational overhead. The set will be split up in solitary elements + * that are executed separately in their own thread. + * + * @return a ParallelStrategy */ - ParallelStrategy COMPUTE_INTENSITY_EXTREME = new ComputeIntensityExtremeParallelStrategy(); + static ParallelStrategy computeIntensityExtreme() { + return Hidden.COMPUTE_INTENSITY_EXTREME; + } Spliterator spliteratorUnknownSize(Iterator iterator, int characteristics); - static ParallelStrategy of(final int... batchSizes) { + static ParallelStrategy of(final int... batchSizes) { return new ParallelStrategy() { @Override public Spliterator spliteratorUnknownSize(Iterator iterator, int characteristics) { @@ -66,5 +84,16 @@ public Spliterator spliteratorUnknownSize(Iterator iterator, } }; } - + + static class Hidden { + + private static final ParallelStrategy COMPUTE_INTENSITY_DEFAULT = Spliterators::spliteratorUnknownSize; + + private static final ParallelStrategy COMPUTE_INTENSITY_MEDIUM = new ComputeIntensityMediumParallelStrategy(); + + private static final ParallelStrategy COMPUTE_INTENSITY_HIGH = new ComputeIntensityHighParallelStrategy(); + + private static final ParallelStrategy COMPUTE_INTENSITY_EXTREME = new ComputeIntensityExtremeParallelStrategy(); + } + } diff --git a/runtime-parent/runtime-core/src/test/java/com/speedment/runtime/core/internal/stream/parallel/ComputeIntensityParallelStrategyTest.java b/runtime-parent/runtime-core/src/test/java/com/speedment/runtime/core/internal/stream/parallel/ComputeIntensityParallelStrategyTest.java index ea4f1fa0ae..251c194ea4 100644 --- a/runtime-parent/runtime-core/src/test/java/com/speedment/runtime/core/internal/stream/parallel/ComputeIntensityParallelStrategyTest.java +++ b/runtime-parent/runtime-core/src/test/java/com/speedment/runtime/core/internal/stream/parallel/ComputeIntensityParallelStrategyTest.java @@ -188,10 +188,10 @@ public String toString() { private Stream strategies() { return Stream.of( - ParallelStrategy.DEFAULT, - ParallelStrategy.COMPUTE_INTENSITY_MEDIUM, - ParallelStrategy.COMPUTE_INTENSITY_HIGH, - ParallelStrategy.COMPUTE_INTENSITY_EXTREME + ParallelStrategy.computeIntensityDefault(), + ParallelStrategy.computeIntensityMedium(), + ParallelStrategy.computeIntensityHigh(), + ParallelStrategy.computeIntensityExtreme() ); }