All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.getperka.flatpack.ext.BaseContext Maven / Gradle / Ivy

There is a newer version: 2.21.0
Show newest version
/*
 * #%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.ext;

import static com.getperka.flatpack.util.FlatPackCollections.listForAny;
import static com.getperka.flatpack.util.FlatPackCollections.mapForIteration;

import java.io.Closeable;
import java.io.IOException;
import java.security.Principal;
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;

import javax.inject.Inject;

import com.getperka.flatpack.FlatPackEntity;
import com.getperka.flatpack.HasUuid;

/**
 * Contains common data that affects the serialization process.
 * 

* This class also provides an error-assignment mechanism that tracks the current path of the * serializer/deserializer through the object graph. When writing a {@link Codex} subtype, the * following pattern should be used: * *

 * void read/write(BaseContext context) {
 *   context.pushPath("useful information");
 *   try {
 *     // Do work, possibly utilizing other Codexes
 *   } catch (CheckedException e) {
 *     context.fail(e);
 *   } finally {
 *     context.popPath();
 *   }
 * }
 * 
*/ public abstract class BaseContext implements Closeable { private final Deque path = new ArrayDeque(); private final List> postWork = listForAny(); @Inject private Principal principal; private final Map warnings = mapForIteration(); BaseContext() { path.addLast(""); } /** * Add a Callable to be executed when the (de)-serialization pass is completed. This is used * primarily for fixing up "implied" properties across on-to-many relationships. */ public void addPostWork(Callable r) { postWork.add(r); } /** * Add a warning message to be reported via the {@link FlatPackEntity} being processed. */ public void addWarning(HasUuid entity, String format, Object... args) { warnings.put(entity.getUuid(), String.format(format, args)); } @Override public void close() throws IOException {} /** * Updates the exception's stack trace with the current path elements and performs a "sneaky" * throw to continue to propagate the (checked) exception up the stack. */ public void fail(Throwable e) { StackTraceElement newElement = new StackTraceElement("FlatPack", toString(), null, 0); StackTraceElement[] stack = e.getStackTrace(); if (stack == null || stack.length == 0) { e.setStackTrace(new StackTraceElement[] { newElement }); } else if (!"FlatPack".equals(stack[0].getClassName())) { StackTraceElement[] newStack = new StackTraceElement[stack.length + 1]; newStack[0] = newElement; System.arraycopy(stack, 0, newStack, 1, stack.length); e.setStackTrace(newStack); } this. sneakyThrow(e); } public Principal getPrincipal() { return principal; } public Map getWarnings() { return Collections.unmodifiableMap(warnings); } /** * Removes the topmost path. * * @return the removed path element */ public String popPath() { return path.removeLast(); } /** * Adds a path to the error-reporting stack. * * @param element the path element to add */ public void pushPath(String element) { path.addLast(element); } /** * Executes all work items passed ino {@link #addPostWork(Callable)}. */ public void runPostWork() { // Sort work by priority Collections.sort(postWork, new PostWorkComparator()); for (Callable callable : postWork) { pushPath("" + callable.getClass().getName()); try { callable.call(); } catch (Exception e) { fail(e); } finally { popPath(); } } postWork.clear(); } /** * Returns the current error-reporting stack. */ @Override public String toString() { StringBuilder sb = new StringBuilder(); for (String p : path) { sb.append(p); } return sb.toString(); } /** * A method to throw a possibly checked exception. */ @SuppressWarnings("unchecked") private void sneakyThrow(Throwable t) throws T { throw (T) t; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy