Skip to content

Commit 6db0e02

Browse files
author
Oleksii Tymchenko
authored
Merge pull request #185 from SpineEventEngine/stand-in-memory
Implement read-side API: * Stand * SubscriptionService * Query Service
2 parents f753879 + 0d84014 commit 6db0e02

File tree

105 files changed

+8526
-1027
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+8526
-1027
lines changed

.idea/codeStyleSettings.xml

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ before_install:
66
after_success:
77
# See: https://github.com/codecov/example-java/blob/master/.travis.yml
88
- bash <(curl -s https://codecov.io/bash)
9+
10+
script: ./gradlew check --stacktrace

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ allprojects {
5454
apply plugin: 'idea'
5555

5656
group = 'org.spine3'
57-
version = '0.5.19-SNAPSHOT'
57+
version = '0.6.0-SNAPSHOT'
5858
}
5959

6060
ext {

client/src/main/java/org/spine3/base/Commands.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
import static org.spine3.base.CommandContext.newBuilder;
4848
import static org.spine3.base.Identifiers.idToString;
4949
import static org.spine3.protobuf.Timestamps.getCurrentTime;
50-
import static org.spine3.validate.Validate.checkIsPositive;
50+
import static org.spine3.validate.Validate.checkPositive;
5151
import static org.spine3.validate.Validate.checkNotEmptyOrBlank;
5252
import static org.spine3.validate.Validate.isNotDefault;
5353

@@ -287,7 +287,7 @@ public static Command setSchedulingTime(Command command, Timestamp schedulingTim
287287
*/
288288
@Internal
289289
public static Command setSchedule(Command command, Duration delay, Timestamp schedulingTime) {
290-
checkIsPositive(schedulingTime, "command scheduling time");
290+
checkPositive(schedulingTime, "command scheduling time");
291291
final CommandContext context = command.getContext();
292292
final CommandContext.Schedule scheduleUpdated = context.getSchedule()
293293
.toBuilder()
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
/*
2+
* Copyright 2016, TeamDev Ltd. All rights reserved.
3+
*
4+
* Redistribution and use in source and/or binary forms, with or without
5+
* modification, must retain the above copyright notice and the following
6+
* disclaimer.
7+
*
8+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
9+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
11+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
12+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
13+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
14+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
15+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
16+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19+
*/
20+
package org.spine3.base;
21+
22+
import com.google.protobuf.Any;
23+
import com.google.protobuf.FieldMask;
24+
import com.google.protobuf.Message;
25+
import org.spine3.client.EntityFilters;
26+
import org.spine3.client.EntityId;
27+
import org.spine3.client.EntityIdFilter;
28+
import org.spine3.client.Query;
29+
import org.spine3.client.Target;
30+
import org.spine3.protobuf.AnyPacker;
31+
import org.spine3.protobuf.KnownTypes;
32+
import org.spine3.protobuf.TypeUrl;
33+
34+
import javax.annotation.Nullable;
35+
import java.util.Arrays;
36+
import java.util.Set;
37+
38+
import static org.spine3.base.Queries.Targets.allOf;
39+
import static org.spine3.base.Queries.Targets.someOf;
40+
41+
/**
42+
* Client-side utilities for working with queries.
43+
*
44+
* @author Alex Tymchenko
45+
* @author Dmytro Dashenkov
46+
*/
47+
public class Queries {
48+
49+
private Queries() {
50+
}
51+
52+
/**
53+
* Create a {@link Query} to read certain entity states by IDs with the {@link FieldMask}
54+
* applied to each of the results.
55+
*
56+
* <p>Allows to specify a set of identifiers to be used during the {@code Query} processing. The processing
57+
* results will contain only the entities, which IDs are present among the {@code ids}.
58+
*
59+
* <p>Allows to set property paths for a {@link FieldMask}, applied to each of the query results.
60+
* This processing is performed according to the
61+
* <a href="https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.FieldMask>FieldMask specs</a>.
62+
*
63+
* <p>In case the {@code paths} array contains entries inapplicable to the resulting entity
64+
* (e.g. a {@code path} references a missing field), such invalid paths are silently ignored.
65+
*
66+
* @param entityClass the class of a target entity
67+
* @param ids the entity IDs of interest
68+
* @param paths the property paths for the {@code FieldMask} applied to each of results
69+
* @return an instance of {@code Query} formed according to the passed parameters
70+
*/
71+
public static Query readByIds(Class<? extends Message> entityClass, Set<? extends Message> ids, String... paths) {
72+
final FieldMask fieldMask = FieldMask.newBuilder()
73+
.addAllPaths(Arrays.asList(paths))
74+
.build();
75+
final Query result = composeQuery(entityClass, ids, fieldMask);
76+
return result;
77+
}
78+
79+
/**
80+
* Create a {@link Query} to read all entity states with the {@link FieldMask}
81+
* applied to each of the results.
82+
*
83+
* <p>Allows to set property paths for a {@link FieldMask}, applied to each of the query results.
84+
* This processing is performed according to the
85+
* <a href="https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.FieldMask>FieldMask specs</a>.
86+
*
87+
* <p>In case the {@code paths} array contains entries inapplicable to the resulting entity
88+
* (e.g. a {@code path} references a missing field), such invalid paths are silently ignored.
89+
*
90+
* @param entityClass the class of a target entity
91+
* @param paths the property paths for the {@code FieldMask} applied to each of results
92+
* @return an instance of {@code Query} formed according to the passed parameters
93+
*/
94+
public static Query readAll(Class<? extends Message> entityClass, String... paths) {
95+
final FieldMask fieldMask = FieldMask.newBuilder()
96+
.addAllPaths(Arrays.asList(paths))
97+
.build();
98+
final Query result = composeQuery(entityClass, null, fieldMask);
99+
return result;
100+
}
101+
102+
/**
103+
* Create a {@link Query} to read certain entity states by IDs.
104+
*
105+
* <p>Allows to specify a set of identifiers to be used during the {@code Query} processing. The processing
106+
* results will contain only the entities, which IDs are present among the {@code ids}.
107+
*
108+
* <p>Unlike {@link Queries#readByIds(Class, Set, String...)}, the {@code Query} processing will not change
109+
* the resulting entities.
110+
*
111+
* @param entityClass the class of a target entity
112+
* @param ids the entity IDs of interest
113+
* @return an instance of {@code Query} formed according to the passed parameters
114+
*/
115+
public static Query readByIds(Class<? extends Message> entityClass, Set<? extends Message> ids) {
116+
return composeQuery(entityClass, ids, null);
117+
}
118+
119+
/**
120+
* Create a {@link Query} to read all states of a certain entity.
121+
*
122+
* <p>Unlike {@link Queries#readAll(Class, String...)}, the {@code Query} processing will not change
123+
* the resulting entities.
124+
*
125+
* @param entityClass the class of a target entity
126+
* @return an instance of {@code Query} formed according to the passed parameters
127+
*/
128+
public static Query readAll(Class<? extends Message> entityClass) {
129+
return composeQuery(entityClass, null, null);
130+
}
131+
132+
private static Query composeQuery(Class<? extends Message> entityClass, @Nullable Set<? extends Message> ids, @Nullable FieldMask fieldMask) {
133+
final Target target = ids == null ? allOf(entityClass) : someOf(entityClass, ids);
134+
final Query.Builder queryBuilder = Query.newBuilder()
135+
.setTarget(target);
136+
if (fieldMask != null) {
137+
queryBuilder.setFieldMask(fieldMask);
138+
}
139+
final Query result = queryBuilder
140+
.build();
141+
return result;
142+
}
143+
144+
/**
145+
* Extract the type of {@link Target} for the given {@link Query}.
146+
*
147+
* <p>Returns null if the {@code Target} type is unknown to the application.
148+
*
149+
* @param query the query of interest.
150+
* @return the type of the {@code Query#getTarget()} or null, if the type is unknown.
151+
*/
152+
@Nullable
153+
public static TypeUrl typeOf(Query query) {
154+
final Target target = query.getTarget();
155+
final String typeAsString = target.getType();
156+
final TypeUrl type = KnownTypes.getTypeUrl(typeAsString);
157+
return type;
158+
}
159+
160+
/**
161+
* Client-side utilities for working with {@link Query} and {@link org.spine3.client.Subscription} targets.
162+
*
163+
* @author Alex Tymchenko
164+
* @author Dmytro Dashenkov
165+
*/
166+
public static class Targets {
167+
168+
private Targets() {
169+
}
170+
171+
/**
172+
* Create a {@link Target} for a subset of the entity states by specifying their IDs.
173+
*
174+
* @param entityClass the class of a target entity
175+
* @param ids the IDs of interest
176+
* @return the instance of {@code Target} assembled according to the parameters.
177+
*/
178+
public static Target someOf(Class<? extends Message> entityClass, Set<? extends Message> ids) {
179+
final Target result = composeTarget(entityClass, ids);
180+
return result;
181+
}
182+
183+
/**
184+
* Create a {@link Target} for all of the specified entity states.
185+
*
186+
* @param entityClass the class of a target entity
187+
* @return the instance of {@code Target} assembled according to the parameters.
188+
*/
189+
public static Target allOf(Class<? extends Message> entityClass) {
190+
final Target result = composeTarget(entityClass, null);
191+
return result;
192+
}
193+
194+
/* package */
195+
static Target composeTarget(Class<? extends Message> entityClass, @Nullable Set<? extends Message> ids) {
196+
final TypeUrl type = TypeUrl.of(entityClass);
197+
198+
final boolean includeAll = ids == null;
199+
200+
final EntityIdFilter.Builder idFilterBuilder = EntityIdFilter.newBuilder();
201+
202+
if (!includeAll) {
203+
for (Message rawId : ids) {
204+
final Any packedId = AnyPacker.pack(rawId);
205+
final EntityId entityId = EntityId.newBuilder()
206+
.setId(packedId)
207+
.build();
208+
idFilterBuilder.addIds(entityId);
209+
}
210+
}
211+
final EntityIdFilter idFilter = idFilterBuilder.build();
212+
final EntityFilters filters = EntityFilters.newBuilder()
213+
.setIdFilter(idFilter)
214+
.build();
215+
final Target.Builder builder = Target.newBuilder()
216+
.setType(type.getTypeName());
217+
if (includeAll) {
218+
builder.setIncludeAll(true);
219+
} else {
220+
builder.setFilters(filters);
221+
}
222+
223+
return builder.build();
224+
}
225+
}
226+
}

client/src/main/java/org/spine3/protobuf/KnownTypes.java

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import org.spine3.protobuf.error.UnknownTypeException;
6464
import org.spine3.type.ClassName;
6565

66+
import javax.annotation.Nullable;
6667
import java.util.Map;
6768
import java.util.Properties;
6869
import java.util.Set;
@@ -105,8 +106,8 @@ public class KnownTypes {
105106
*/
106107
private static final ImmutableMap<String, TypeUrl> typeNameToUrlMap = buildTypeToUrlMap(knownTypes);
107108

108-
109-
private KnownTypes() {}
109+
private KnownTypes() {
110+
}
110111

111112
/** Retrieves Protobuf type URLs known to the application. */
112113
public static ImmutableSet<TypeUrl> getTypeUrls() {
@@ -145,14 +146,16 @@ public static ClassName getClassName(TypeUrl typeUrl) throws UnknownTypeExceptio
145146
* @throws IllegalStateException if there is no Protobuf type for the specified class
146147
*/
147148
public static TypeUrl getTypeUrl(ClassName className) {
148-
final TypeUrl result = knownTypes.inverse().get(className);
149+
final TypeUrl result = knownTypes.inverse()
150+
.get(className);
149151
if (result == null) {
150152
throw new IllegalStateException("No Protobuf type URL found for the Java class " + className);
151153
}
152154
return result;
153155
}
154156

155157
/** Returns a Protobuf type URL by Protobuf type name. */
158+
@Nullable
156159
public static TypeUrl getTypeUrl(String typeName) {
157160
final TypeUrl typeUrl = typeNameToUrlMap.get(typeName);
158161
return typeUrl;
@@ -203,7 +206,8 @@ private void putProperties(Properties properties) {
203206
* <p>This method needs to be updated with introduction of new Google Protobuf types
204207
* after they are used in the framework.
205208
*/
206-
@SuppressWarnings("OverlyLongMethod") // OK as there are many types in Protobuf and we want to keep this code in one place.
209+
@SuppressWarnings("OverlyLongMethod")
210+
// OK as there are many types in Protobuf and we want to keep this code in one place.
207211
private Builder addStandardProtobufTypes() {
208212
// Types from `any.proto`.
209213
put(Any.class);
@@ -217,14 +221,14 @@ private Builder addStandardProtobufTypes() {
217221
put(DescriptorProtos.FileDescriptorSet.class);
218222
put(DescriptorProtos.FileDescriptorProto.class);
219223
put(DescriptorProtos.DescriptorProto.class);
220-
// Inner types of `DescriptorProto`
221-
put(DescriptorProtos.DescriptorProto.ExtensionRange.class);
222-
put(DescriptorProtos.DescriptorProto.ReservedRange.class);
224+
// Inner types of `DescriptorProto`
225+
put(DescriptorProtos.DescriptorProto.ExtensionRange.class);
226+
put(DescriptorProtos.DescriptorProto.ReservedRange.class);
223227

224228
put(DescriptorProtos.FieldDescriptorProto.class);
225-
putEnum(DescriptorProtos.FieldDescriptorProto.Type.getDescriptor(),
226-
DescriptorProtos.FieldDescriptorProto.Type.class);
227-
putEnum(DescriptorProtos.FieldDescriptorProto.Label.getDescriptor(),
229+
putEnum(DescriptorProtos.FieldDescriptorProto.Type.getDescriptor(),
230+
DescriptorProtos.FieldDescriptorProto.Type.class);
231+
putEnum(DescriptorProtos.FieldDescriptorProto.Label.getDescriptor(),
228232
DescriptorProtos.FieldDescriptorProto.Label.class);
229233

230234
put(DescriptorProtos.OneofDescriptorProto.class);
@@ -237,21 +241,21 @@ private Builder addStandardProtobufTypes() {
237241
DescriptorProtos.FileOptions.OptimizeMode.class);
238242
put(DescriptorProtos.MessageOptions.class);
239243
put(DescriptorProtos.FieldOptions.class);
240-
putEnum(DescriptorProtos.FieldOptions.CType.getDescriptor(),
241-
DescriptorProtos.FieldOptions.CType.class);
242-
putEnum(DescriptorProtos.FieldOptions.JSType.getDescriptor(),
243-
DescriptorProtos.FieldOptions.JSType.class);
244+
putEnum(DescriptorProtos.FieldOptions.CType.getDescriptor(),
245+
DescriptorProtos.FieldOptions.CType.class);
246+
putEnum(DescriptorProtos.FieldOptions.JSType.getDescriptor(),
247+
DescriptorProtos.FieldOptions.JSType.class);
244248
put(DescriptorProtos.EnumOptions.class);
245249
put(DescriptorProtos.EnumValueOptions.class);
246250
put(DescriptorProtos.ServiceOptions.class);
247251
put(DescriptorProtos.MethodOptions.class);
248252
put(DescriptorProtos.UninterpretedOption.class);
249253
put(DescriptorProtos.SourceCodeInfo.class);
250-
// Inner types of `SourceCodeInfo`.
251-
put(DescriptorProtos.SourceCodeInfo.Location.class);
254+
// Inner types of `SourceCodeInfo`.
255+
put(DescriptorProtos.SourceCodeInfo.Location.class);
252256
put(DescriptorProtos.GeneratedCodeInfo.class);
253-
// Inner types of `GeneratedCodeInfo`.
254-
put(DescriptorProtos.GeneratedCodeInfo.Annotation.class);
257+
// Inner types of `GeneratedCodeInfo`.
258+
put(DescriptorProtos.GeneratedCodeInfo.Annotation.class);
255259

256260
// Types from `duration.proto`.
257261
put(Duration.class);
@@ -277,8 +281,8 @@ private Builder addStandardProtobufTypes() {
277281
// Types from `type.proto`.
278282
put(Type.class);
279283
put(Field.class);
280-
putEnum(Field.Kind.getDescriptor(), Field.Kind.class);
281-
putEnum(Field.Cardinality.getDescriptor(), Field.Cardinality.class);
284+
putEnum(Field.Kind.getDescriptor(), Field.Kind.class);
285+
putEnum(Field.Cardinality.getDescriptor(), Field.Cardinality.class);
282286
put(com.google.protobuf.Enum.class);
283287
put(EnumValue.class);
284288
put(Option.class);
@@ -313,8 +317,8 @@ private void putEnum(EnumDescriptor desc, Class<? extends EnumLite> enumClass) {
313317
private void put(TypeUrl typeUrl, ClassName className) {
314318
if (resultMap.containsKey(typeUrl)) {
315319
log().warn("Duplicate key in the {} map: {}. " +
316-
"It may be caused by the `task.descriptorSetOptions.includeImports` option " +
317-
"set to `true` in the `build.gradle`.", KnownTypes.class.getName(), typeUrl);
320+
"It may be caused by the `task.descriptorSetOptions.includeImports` option " +
321+
"set to `true` in the `build.gradle`.", KnownTypes.class.getName(), typeUrl);
318322
return;
319323
}
320324
resultMap.put(typeUrl, className);

0 commit comments

Comments
 (0)