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

org.nuiton.jaxx.compiler.binding.DataBindingHelper Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * JAXX :: Compiler
 * %%
 * Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */
package org.nuiton.jaxx.compiler.binding;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.nuiton.jaxx.compiler.CompilerException;
import org.nuiton.jaxx.compiler.I18nHelper;
import org.nuiton.jaxx.compiler.JAXXCompiler;

/**
 * Helper to be used by compiler to treate data bindings.
 * 

* Note : The code in this class was previously directly in JAXXCompiler, now prefer have a separate * class to make {@link JAXXCompiler} more simple and clear. *

* Created: 27 nov. 2009 * * @author Tony Chemit - [email protected] * @since 2.0.0 */ public class DataBindingHelper { /** To debug binding without any log interference */ public static boolean SHOW_LOG; /** left brace matcher */ protected static final Matcher leftBraceMatcher = Pattern.compile("^(\\{)|[^\\\\](\\{)").matcher(""); /** right brace matcher */ protected static final Matcher rightBraceMatcher = Pattern.compile("^(\\})|[^\\\\](\\})").matcher(""); /** * Registred data binding for the compiler, then after the invocation of method {@link #finalizeBindings()} * only the real data bindings, the simple bindings will be moved to {@link #simpleBindings}. */ protected final List dataBindings = new ArrayList<>(); /** Simpel bindings for the compiler */ protected final List simpleBindings = new ArrayList<>(); /** Associated compiler */ protected final JAXXCompiler compiler; /** Counter by unsafe type */ protected final Map autoUnsafeGenIds = new TreeMap<>(); public DataBindingHelper(JAXXCompiler compiler) { this.compiler = compiler; } /** * Examine an attribute value for data binding expressions. Returns a 'cooked' expression which * can be used to determine the resulting value. It is expected that this expression will be used * as the source expression in a call to {@link #registerDataBinding}. * If the attribute value does not invoke data binding, this method returns null * * @param stringValue the string value of the property from the XML * @return a processed version of the expression * @throws CompilerException ? */ public String processDataBindings(String stringValue) throws CompilerException { I18nHelper.tryToRegisterI18nInvocation(compiler,stringValue); int pos = getNextLeftBrace(stringValue, 0); if (pos != -1) { StringBuilder expression = new StringBuilder(); int lastPos = 0; while (pos != -1 && pos < stringValue.length()) { if (pos > lastPos) { if (expression.length() > 0) { expression.append(" + "); } expression.append('"'); expression.append(JAXXCompiler.escapeJavaString(stringValue.substring(lastPos, pos))); expression.append('"'); } boolean multi = expression.length() > 0; if (multi) { expression.append(" + "); expression.append('('); } int pos2 = getNextRightBrace(stringValue, pos + 1); if (pos2 == -1) { throw new CompilerException("unmatched '{' in expression: " + stringValue); } expression.append(stringValue.substring(pos + 1, pos2)); if (multi) { expression.append(')'); } pos2++; if (pos2 < stringValue.length()) { pos = getNextLeftBrace(stringValue, pos2); lastPos = pos2; } else { pos = stringValue.length(); lastPos = pos; } } if (lastPos < stringValue.length()) { if (expression.length() > 0) { expression.append(" + "); } expression.append('"'); expression.append(JAXXCompiler.escapeJavaString(stringValue.substring(lastPos))); expression.append('"'); } //TC-20091027 : developper must write exact databinding // the fact of adding the String boxed for String type binding is not // a good thing, since it add one more call to process in binding // and add nothing special more ? // return type == ClassDescriptorHelper.getClassDescriptor(String.class) ? "String.valueOf(" + expression + ")" : expression.toString(); return expression.toString(); } return null; } public DataBinding[] getDataBindings() { return dataBindings.toArray(new DataBinding[dataBindings.size()]); } public DataBinding[] getSimpleBindings() { return simpleBindings.toArray(new DataBinding[simpleBindings.size()]); } public void registerDataBinding(String id, String binding, String assignment) { binding = compiler.checkJavaCode(binding); registerDataBinding(new DataBinding(id, binding, assignment, true)); } public void registerDataBinding(DataBinding binding) { dataBindings.add(binding); } public void clear() { simpleBindings.clear(); dataBindings.clear(); autoUnsafeGenIds.clear(); } /** * Obtain the next safe id for the given binding id. *

* With css, we can obtain the same binding id, so we must * check for unicity each time we want a new binding id. *

* If an id is already taken, we suffix by {@code _XXX} until * found a free id. * * @param id the id of the binding * @return the safe id of the binding */ public String getSafeId(String id) { Integer integer = autoUnsafeGenIds.get(id); String result = id; if (integer == null) { integer = 0; } else { result += "_" + integer; } autoUnsafeGenIds.put(id, ++integer); return result; } /** * Revert a previous computed safe id. *

* This is needed when a binding compiled is not an data binding, we want to free * the safe id to avoid hole in numbers. * * @param id the original id to revert in counter. */ public void revertSafeId(String id) { Integer integer = autoUnsafeGenIds.get(id); if (integer != null) { integer--; if (integer > 0) { autoUnsafeGenIds.put(id, integer); } else { autoUnsafeGenIds.remove(id); } } } /** * Compile all binding discovered previously. *

* If a binding is not a dataBinding, then move it from the list {@link #dataBindings} to {@link #simpleBindings}. */ public void finalizeBindings() { for (Iterator itr = dataBindings.iterator(); itr.hasNext(); ) { DataBinding binding = itr.next(); boolean isBinding = binding.compile(compiler); if (!isBinding) { // ce n'est pas un binding, on enregistre le code d'init (si il existe) simpleBindings.add(binding); // on supprime le faux binding itr.remove(); } } } protected static int getNextLeftBrace(String string, int pos) { leftBraceMatcher.reset(string); return leftBraceMatcher.find(pos) ? Math.max(leftBraceMatcher.start(1), leftBraceMatcher.start(2)) : -1; } protected static int getNextRightBrace(String string, int pos) { leftBraceMatcher.reset(string); rightBraceMatcher.reset(string); int openCount = 1; int rightPos; while (openCount > 0) { pos++; int leftPos = leftBraceMatcher.find(pos) ? Math.max(leftBraceMatcher.start(1), leftBraceMatcher.start(2)) : -1; rightPos = rightBraceMatcher.find(pos) ? Math.max(rightBraceMatcher.start(1), rightBraceMatcher.start(2)) : -1; assert leftPos == -1 || leftPos >= pos; assert rightPos == -1 || rightPos >= pos; if (leftPos != -1 && leftPos < rightPos) { pos = leftPos; openCount++; } else if (rightPos != -1) { pos = rightPos; openCount--; } else { openCount = 0; } } return pos; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy