package com.getperka.flatpack;
/*
* #%L
* FlatPack serialization code
* %%
* Copyright (C) 2012 - 2013 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%
*/
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import com.getperka.flatpack.ext.Codex;
import com.getperka.flatpack.ext.TypeContext;
import com.getperka.flatpack.ext.VisitorContext;
import com.getperka.flatpack.ext.Walker;
import com.getperka.flatpack.ext.Walkers;
/**
* A utility class that allows visitors to be written to traverse a FlatPack object graph.
*/
@Singleton
public class Visitors {
class FlatPackEntityWalker<T> implements Walker<FlatPackEntity<T>> {
@Override
public void walk(FlatPackVisitor visitor, FlatPackEntity<T> entity,
VisitorContext<FlatPackEntity<T>> context) {
@SuppressWarnings("unchecked")
Codex<T> codex = (Codex<T>) typeContext.getCodex(entity.getType());
if (visitor.visit(entity, codex, context)) {
entity.withValue(context.walkSingleton(codex).accept(visitor, entity.getValue()));
// Traverse the extra entities as a list, to allow insertion
Codex<HasUuid> extraCodex = typeContext.getCodex(HasUuid.class);
List<HasUuid> mutable = new ArrayList<HasUuid>(entity.getExtraEntities());
context.walkList(extraCodex).accept(visitor, mutable);
entity.setExtraEntities(new HashSet<HasUuid>(mutable));
}
visitor.endVisit(entity, codex, context);
}
}
@Inject
TypeContext typeContext;
@Inject
Walkers walkers;
protected Visitors() {}
/**
* Returns a {@link VisitorContext} for performing ad-hoc traversals.
*/
public Walkers getWalkers() {
return walkers;
}
/**
* Visit a {@link FlatPackEntity}, including its {@link FlatPackEntity#getValue() value} and
* {@link FlatPackEntity#getExtraEntities() extra entities};
*
* @param visitor the visitor to receive the object graph
* @param entity the FlatPackEntity to traverse
* @return {@code entity} or its replacement
*/
public <T> FlatPackEntity<T> visit(FlatPackVisitor visitor, FlatPackEntity<T> entity) {
return getWalkers().walkSingleton(new FlatPackEntityWalker<T>()).accept(visitor, entity);
}
/**
* Visit an entity.
*
* @param visitor the visitor to receive the object graph
* @param entity the entity to traverse
* @return {@code entity} or its replacement
*/
public <T extends HasUuid> T visit(FlatPackVisitor visitor, T entity) {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) entity.getClass();
Codex<T> codex = typeContext.getCodex(clazz);
return getWalkers().walkSingleton(codex).accept(visitor, entity);
}
}