Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* #%L
* FlatPack serialization code
* %%
* Copyright (C) 2012 Perka Inc.
* %%
* 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.
* #L%
*/
package com.getperka.flatpack.codexes;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import com.getperka.flatpack.HasUuid;
import com.getperka.flatpack.PostUnpack;
import com.getperka.flatpack.PreUnpack;
import com.getperka.flatpack.ext.Codex;
import com.getperka.flatpack.ext.DeserializationContext;
import com.getperka.flatpack.ext.EntityResolver;
import com.getperka.flatpack.ext.JsonKind;
import com.getperka.flatpack.ext.PrincipalMapper;
import com.getperka.flatpack.ext.Property;
import com.getperka.flatpack.ext.PropertyPath;
import com.getperka.flatpack.ext.SerializationContext;
import com.getperka.flatpack.ext.Type;
import com.getperka.flatpack.ext.TypeContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.stream.JsonWriter;
public class EntityCodex extends Codex {
public static class MyReceiver implements PropertyPath.Receiver {
private final Principal lookFor;
private final PrincipalMapper mapper;
private boolean result;
public MyReceiver(PrincipalMapper mapper, Principal lookFor) {
this.lookFor = lookFor;
this.mapper = mapper;
}
public boolean getResult() {
return result;
}
@Override
public boolean receive(Object value) {
if (value instanceof HasUuid) {
List principals = mapper.getPrincipals((HasUuid) value);
if (principals != null && principals.contains(lookFor)) {
result = true;
return false;
}
}
return true;
}
}
private final Class clazz;
private final List preUnpackMethods;
private final List postUnpackMethods;
public EntityCodex(Class clazz) {
this.clazz = clazz;
List pre = new ArrayList();
List post = new ArrayList();
// Iterate over all methods in the type and then its supertypes
for (Class> lookAt = clazz; lookAt != null; lookAt = lookAt.getSuperclass()) {
for (Method m : lookAt.getDeclaredMethods()) {
Class>[] params = m.getParameterTypes();
switch (params.length) {
case 0:
if (m.isAnnotationPresent(PreUnpack.class)) {
m.setAccessible(true);
pre.add(m);
}
if (m.isAnnotationPresent(PostUnpack.class)) {
m.setAccessible(true);
post.add(m);
}
break;
case 1:
if (m.isAnnotationPresent(PreUnpack.class) && params[0].equals(JsonObject.class)) {
m.setAccessible(true);
pre.add(m);
}
break;
}
}
}
// Reverse the list to call supertype methods first
Collections.reverse(pre);
Collections.reverse(post);
preUnpackMethods = pre.isEmpty() ? Collections. emptyList() :
Collections.unmodifiableList(pre);
postUnpackMethods = post.isEmpty() ? Collections. emptyList() :
Collections.unmodifiableList(post);
}
/**
* Performs a minimal amount of work to create an empty stub object to fill in later.
*
* @param element a JsonObject containing a {@code uuid} property. If {@code null}, a
* randomly-generated UUID will be assigned to the allocated object
* @param context this method will call {@link DeserializationContext#putEntity} to store the
* newly-allocated entity
*/
public T allocate(JsonElement element, DeserializationContext context) {
JsonElement uuidElement = element.getAsJsonObject().get("uuid");
if (uuidElement == null) {
context.fail(new IllegalArgumentException("Data entry missing uuid:\n"
+ element.toString()));
}
UUID uuid = UUID.fromString(uuidElement.getAsString());
T toReturn = allocate(uuid, context, true);
// Register PostUnpack methods
if (!postUnpackMethods.isEmpty()) {
context.addPostWork(new PostUnpackInvoker(toReturn, postUnpackMethods));
}
return toReturn;
}
@Override
public Type describe(TypeContext context) {
return new Type.Builder()
.withJsonKind(JsonKind.STRING)
.withName(context.getPayloadName(clazz))
.build();
}
@Override
public String getPropertySuffix() {
return "Uuid";
}
@Override
public T readNotNull(JsonElement element, DeserializationContext context) {
UUID uuid = UUID.fromString(element.getAsString());
HasUuid entity = context.getEntity(uuid);
/*
* If the UUID is a reference to an entity that isn't in the data section, delegate to the
* allocate() method. The entity will either be provided by an EntityResolver or a blank entity
* will be created if possible.
*/
if (entity == null) {
entity = allocate(uuid, context, true);
}
try {
return clazz.cast(entity);
} catch (ClassCastException e) {
throw new ClassCastException("Cannot cast a " + entity.getClass().getName()
+ " to a " + clazz.getName() + ". Duplicate UUID in data payload?");
}
}
public void readProperties(T object, JsonObject element, DeserializationContext context) {
context.pushPath("(EntityCodex.readProperties())" + object.getUuid());
try {
if (!context.checkAccess(object)) {
return;
}
// Allow the object to see the data that's about to be applied
for (Method m : preUnpackMethods) {
if (m.getParameterTypes().length == 0) {
m.invoke(object);
} else {
m.invoke(object, element);
}
}
List roles = context.getRoles();
for (Property prop : context.getTypeContext().extractProperties(clazz)) {
if (!prop.maySet(roles)) {
continue;
}
String simplePropertyName = prop.getName();
context.pushPath("." + simplePropertyName);
try {
Object value;
if (prop.isEmbedded()) {
/*
* Embedded objects are never referred to by uuid in the payload, so an instance will
* need to be allocated before reading in the properties.
*/
@SuppressWarnings("unchecked")
EntityCodex codex = (EntityCodex) prop.getCodex();
HasUuid embedded = codex.allocate(UUID.randomUUID(), context, false);
codex.readProperties(embedded, element, context);
value = embedded;
} else {
@SuppressWarnings("unchecked")
Codex