Java tutorial
/******************************************************************************* * Copyright (c) 2013-2014 Synflow SAS. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Matthieu Wipliez - initial API and implementation and/or initial documentation *******************************************************************************/ package com.synflow.cx.internal.instantiation.properties; import static com.synflow.core.IProperties.PROP_CLOCKS; import java.util.Iterator; import java.util.Map.Entry; import com.google.common.collect.Iterables; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.synflow.models.dpn.DPN; import com.synflow.models.dpn.Entity; import com.synflow.models.dpn.Instance; /** * This class defines a properties checker for an instance. * * @author Matthieu Wipliez * */ public class InstancePropertiesChecker extends PropertiesChecker { private static final String NO_CLOCK = "<no clock>"; public InstancePropertiesChecker(IJsonErrorHandler handler) { super(handler); } /** * Checks properties of <code>instance</code>. * * @param instance * IR instance */ public void checkProperties(Instance instance) { Specializer specializer = new Specializer(handler); specializer.visitArguments(instance); updateClocksInstantiated(instance); } /** * This method creates a clocks object from the entity's clocks and the instance's clocks. * * @param entityClocks * array of entity's clocks * @param instanceClocks * array of instance's clocks * @return a clocks object */ private JsonObject makeClocksObject(JsonArray entityClocks, JsonArray instanceClocks) { JsonObject clocks = new JsonObject(); if (entityClocks.size() == 0) { // when the entity declares no clocks (combinational) // we associate no clocks return clocks; } Iterator<JsonElement> it = instanceClocks.iterator(); for (JsonElement clock : entityClocks) { String clockName = clock.getAsString(); if (it.hasNext()) { clocks.add(clockName, it.next()); } else { if (instanceClocks.size() == 1) { // support repetition of one clock clocks.add(clockName, instanceClocks.get(0)); } else { // not enough clocks given // this is verified and caught by validateClocks // with a !it.hasNext() test. break; } } } while (it.hasNext()) { // too many clocks given // the NO_CLOCK string is not a valid identifier, only used internally clocks.add(NO_CLOCK, it.next()); } return clocks; } /** * Checks and transforms the clocks in the properties of the given instance. Clocks accepts an * array and an object. If clocks is an array, this method transforms it to an object and checks * it. * * @param instance */ private void updateClocksInstantiated(Instance instance) { DPN dpn = instance.getDPN(); JsonArray parentClocks = dpn.getProperties().getAsJsonArray(PROP_CLOCKS); Entity entity = instance.getEntity(); JsonArray entityClocks = entity.getProperties().getAsJsonArray(PROP_CLOCKS); // use {clock: 'name'} as a shortcut for {clocks: ['name']} JsonObject properties = instance.getProperties(); applyClockShortcut(properties); JsonElement clocks = properties.get(PROP_CLOCKS); if (clocks == null) { clocks = makeClocksObject(entityClocks, parentClocks); properties.add(PROP_CLOCKS, clocks); } else { if (clocks.isJsonArray()) { if (checkClockArray(clocks)) { clocks = makeClocksObject(entityClocks, clocks.getAsJsonArray()); properties.add(PROP_CLOCKS, clocks); } else { // do not check clocks return; } } else if (!clocks.isJsonObject()) { // do not check clocks handler.addError(clocks, "clocks must be an array or an object"); return; } } validateClocks(clocks.getAsJsonObject(), parentClocks, entityClocks); } /** * Validates the given clocks object. * * @param clocks * a clocks object * @param parentClocks * a list of parent clocks * @param entityClocks * a list of entity clocks */ private void validateClocks(JsonObject clocks, JsonArray parentClocks, JsonArray entityClocks) { int size = entityClocks.size(); int got = 0; Iterator<JsonElement> it = entityClocks.iterator(); for (Entry<String, JsonElement> pair : clocks.entrySet()) { String clockName = pair.getKey(); if (NO_CLOCK.equals(clockName)) { // no more clocks after this one => mismatch in number of clocks got = clocks.entrySet().size(); break; } if (!it.hasNext()) { // no more entity clocks => mismatch in number of clocks break; } // check we use a valid entity clock name String expected = it.next().getAsString(); if (!clockName.equals(expected)) { handler.addError(clocks, "given clock name '" + clockName + "' does not match entity's clock '" + expected + "'"); } // check value JsonElement value = pair.getValue(); if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isString()) { got++; if (!Iterables.contains(parentClocks, value)) { handler.addError(value, "given clock name '" + value.getAsString() + "' does not appear in parent's clocks " + parentClocks); } } else { handler.addError(value, "invalid clock value: " + value.toString()); } } if (got < size) { String msg = "not enough clocks given, expected " + size + " clocks, got " + got; handler.addError(clocks, msg); } else if (got > size) { String msg = "too many clocks given, expected " + size + " clocks, got " + got; handler.addError(clocks, msg); } } }