/* * Copyright 2005-2011 the original author or authors. * * 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. */ package org.wamblee.xmlrouter.impl; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.wamblee.xmlrouter.common.Id; import org.wamblee.xmlrouter.config.Transformation; public class Transformations { private AtomicInteger sequenceNumber; private Map transformations; private List vertices; private TransformationPath[][] matrix; private Map> sequences; public Transformations() { sequenceNumber = new AtomicInteger(1); transformations = new LinkedHashMap(); vertices = new ArrayList(); matrix = new TransformationPath[0][0]; } public Id addTransformation(Transformation aTransformation) { int seqno = sequenceNumber.getAndIncrement(); Id id = new Id(seqno); transformations.put(seqno, new RobustTransformation(id, aTransformation)); computeTransformationSequences(); return id; } public Collection getPossibleTargetTypes(String aType) { int index = vertices.indexOf(aType); Set res = new HashSet(); for (int j = 0; j < vertices.size(); j++) { if (matrix[index][j] != null) { String value = matrix[index][j].getToType(); if (value == null) { value = aType; } res.add(value); } } res.add(aType); return res; } /** * Gets the transformation path from A to B. * * @param aFrom * From * @param aTo * To * @return Transformatkon path or null if not found. */ public TransformationPath getPath(String aFrom, String aTo) { int i = vertices.indexOf(aFrom); if (i == -1) { if (aFrom.equals(aTo)) { return new TransformationPath(); } return null; } int j = vertices.indexOf(aTo); return matrix[i][j]; } private void computeTransformationSequences() { vertices = new ArrayList(); // Obtain possible starting points. Set v = new HashSet(); for (Transformation transformation : transformations.values()) { v.add(transformation.getFromType()); v.add(transformation.getToType()); } vertices.addAll(v); matrix = new TransformationPath[vertices.size()][vertices.size()]; // Floyd's algorithm. int nvertices = vertices.size(); for (int i = 0; i < nvertices; i++) { matrix[i][i] = new TransformationPath(); } for (Transformation transformation : transformations.values()) { int from = vertices.indexOf(transformation.getFromType()); int to = vertices.indexOf(transformation.getToType()); TransformationPath path = new TransformationPath(transformation); matrix[from][to] = path; } for (int k = 0; k < nvertices; k++) { for (int i = 0; i < nvertices; i++) { for (int j = 0; j < nvertices; j++) { // if the path from i to j through k is shorter then the // existing path then // replace it. int lij = getPathLength(i, j); int lik = getPathLength(i, k); int lkj = getPathLength(k, j); if (lik + lkj < lij) { matrix[i][j] = matrix[i][k].appendPath(matrix[k][j]); } } } } } private int getPathLength(int i, int j) { // We use MAX_INT/3 as infinity. This ensures that the default integer // comparison in Floyd's algorithm does not lead to overflow. return matrix[i][j] == null ? Integer.MAX_VALUE / 3 : matrix[i][j] .size(); } public void removeTransformation(Id aId) { transformations.remove(aId.getId()); computeTransformationSequences(); } public Collection getTransformations() { return Collections.unmodifiableCollection(transformations.values()); } @Override public String toString() { StringBuffer buf = new StringBuffer(); buf.append("Transformations("); int nvertices = vertices.size(); for (int i = 0; i < nvertices; i++) { for (int j = 0; j < nvertices; j++) { TransformationPath path = matrix[i][j]; if (path != null) { buf.append(vertices.get(i)); buf.append(" -> "); buf.append(vertices.get(j)); buf.append(": "); buf.append(path); buf.append("\n"); } } } buf.append(")"); return buf.toString(); } }