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

org.jboss.byteman.contrib.dtest.RuleConstructor Maven / Gradle / Ivy

Go to download

The Byteman dtest jar supports instrumentation of test code executed on remote server hosts and validation of assertions describing the expected operation of the instrumented methods.

The newest version!
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2016, Red Hat, Inc. and/or its affiliates,
 * and individual contributors as indicated by the @author tags.
 * See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU Lesser General Public License, v. 2.1.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License,
 * v.2.1 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 *
 * (C) 2016,
 * @author JBoss, by Red Hat.
 */
package org.jboss.byteman.contrib.dtest;

import java.util.concurrent.atomic.AtomicReference;

import org.jboss.byteman.rule.helper.Helper;

/**
 * 

* Provides a fluent API for creating Byteman rules without needing * to mess around with String concatenation. *

* Example: *

* * RuleConstructor rb = RuleConstructor.createRule("myRule")
* .onClass("org.jboss.byteman.ExampleClass")
* .inMethod("doInterestingStuff")
* .atEntry()
* .ifTrue()
* .doAction("myAction()");
* System.out.println(rb.build()); *
*

* will print: *

* * RULE myRule
* CLASS org.jboss.byteman.ExampleClass
* METHOD doInterestingStuff
* AT ENTRY
* IF true
* DO myAction()
* ENDRULE *
*/ public final class RuleConstructor { private static AtomicReference defaultInstrumentor = new AtomicReference(); private static final String LINEBREAK = String.format("%n"); private static final String CONSTRUCTOR_METHOD = ""; private static final String CLASS_CONSTRUCTOR = ""; private String ruleName; private String className; private boolean isInterface; private boolean isIncludeSubclases; private String methodName; private String helperName = Helper.class.getName(); private String where = "AT ENTRY"; private String bind; private String ifcondition = "true"; private String action; private String imports; private String compile; /** * No use of constructor, new rule creation with: * RuleConstructor.createRule("myRule") */ private RuleConstructor(String ruleName) { this.ruleName = ruleName; } /** *

* Setting default initialize instance of {@link Instrumentor} class * that will be used when {@link #install()}/{@link #submit()} method * is used for the created rule.
* You can define this default Instrumentor which could be used whenever * the new rule is submitted to the Byteman agent.
* null is permitted then {@link #install()} method throws exception *

* * @param instrumentor initiated instrumentor instance or null */ public static final void setDefaultInstrumentor(Instrumentor instrumentor) { defaultInstrumentor.set(instrumentor); } /** * Undefinining value of default instrumentor. * Methods {@link #install()}/{@link #submit()} are illegal to be used from now * up to time it's set again. */ public static final void undefineDefaultInstrumentor() { RuleConstructor.setDefaultInstrumentor(null); } /** * Returning value of the previously set default {@link Instrumentor} instance. * * @return instrumentor instance or null, when was not set */ public static final Instrumentor getDefaultInstrumentor() { return defaultInstrumentor.get(); } /** *

* This is where you start. *

* Byteman rule builder initialization method. * * @param ruleName name of rule is required to construct any rule * @return a rule constructor ready to have its class or interface specified */ public static final RuleConstructor.ClassClause createRule(String ruleName) { return new RuleConstructor(ruleName).new ClassClause(); } /** *

* Installing/submitting rule to the Byteman agent via instance of instrumentor * defined as default to the {@link RuleConstructor} class. *

*

* Internally this: *

    *
  • build the rule where {@link #build()} is called to generate rule as {@link String}
  • *
  • calling submit of the rule over instance of {@link Instrumentor}
  • *

* Prerequisite: you need * set up the instrumentor by call {@link #setDefaultInstrumentor(Instrumentor)} * * @return rule constructor if expected to be used later again * @throws IllegalStateException if default instrumentor is not set * @throws RuntimeException if error happens during installation rule * via default instrumentor instance */ public RuleConstructor install() { if(defaultInstrumentor.get() == null) throw new IllegalStateException("Can't install rule '" + this.getRuleName() + "' as default instrumentor was not set-up"); return install(defaultInstrumentor.get()); } /** *

* Installing/submitting rule to the Byteman agent via instance of instrumentor. *

*

* Internally this: *

    *
  • build the rule where {@link #build()} is called to generate rule as {@link String}
  • *
  • calling submit of the rule over instance of {@link Instrumentor}
  • *
* * @param instrumentor instance of instrumentor to be used to submit the rule to * @return rule constructor if expected to be used later again * @throws NullPointerException if instrumentor param is provided as null * @throws RuntimeException if error happens during installation rule * via default instrumentor instance */ public RuleConstructor install(Instrumentor instrumentor) { if(instrumentor == null) throw new NullPointerException("instrumentor"); try { instrumentor.installRule(this); } catch (Exception e) { throw new RuntimeException("Can't install rule '" + this.getRuleName() + "'", e); } return this; } /** * Facade to method {@link #install()}. * * @return rule constructor, if expected to be used later again * @throws IllegalStateException if default instrumentor is not set * @throws RuntimeException if error happens during installation rule */ public RuleConstructor submit() { return install(); } /** * Facade to method {@link #install(Instrumentor)}. * * @param instrumentor instance of instrumentor to be used to submit the rule to * @return rule constructor, if expected to be used later again * @throws NullPointerException if instrumentor param is provided as null * @throws RuntimeException if error happens during installation rule */ public RuleConstructor submit(Instrumentor instrumentor) { return install(instrumentor); } /** * Builds the rule defined by this instance of {@link RuleConstructor} * and returns its representation as string. * * @return the rule as a string */ public String build() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("RULE "); stringBuilder.append(ruleName); stringBuilder.append(LINEBREAK); if(isInterface) { stringBuilder.append("INTERFACE "); } else { stringBuilder.append("CLASS "); } if(isIncludeSubclases) { stringBuilder.append("^"); } stringBuilder.append(className); stringBuilder.append(LINEBREAK); stringBuilder.append("METHOD "); stringBuilder.append(methodName); stringBuilder.append(LINEBREAK); stringBuilder.append(where); stringBuilder.append(LINEBREAK); if(helperName != null && !helperName.isEmpty()) { stringBuilder.append("HELPER "); stringBuilder.append(helperName); stringBuilder.append(LINEBREAK); } if(imports != null) { stringBuilder.append(imports); } if(compile != null && !compile.isEmpty()) { stringBuilder.append(compile); stringBuilder.append(LINEBREAK); } if(bind != null && !bind.isEmpty()) { stringBuilder.append("BIND "); stringBuilder.append(bind); stringBuilder.append(LINEBREAK); } stringBuilder.append("IF "); stringBuilder.append(ifcondition); stringBuilder.append(LINEBREAK); stringBuilder.append("DO "); stringBuilder.append(action); stringBuilder.append(LINEBREAK); stringBuilder.append("ENDRULE"); stringBuilder.append(LINEBREAK); return stringBuilder.toString(); } public final class ClassClause { /** * Class that rule event is associated to. *

* Example: *

* * new RuleBuilder("rule name")
* .onClass("java.lang.String.class")
* ... *
* * @param clazz class as target of rule injection * @return this, for having fluent api */ public RuleConstructor.MethodClause onClass(Class clazz) { return onSpecifier(clazz.getCanonicalName(), false); } /** * Class name that rule event is associated to. *

* Example: *

* * new RuleBuilder("rule name")
* .onClass("java.lang.String")
* ... *
* * @param className class name as target of rule injection * @return this, for having fluent api */ public RuleConstructor.MethodClause onClass(String className) { return onSpecifier(className, false); } /** * Interface that rule event is associated to. *

* Example: *

* * new RuleBuilder("rule name")
* .onInterface("javax.transaction.xa.XAResource.class")
* ... *
* * @param clazz interface class as target of rule injection * @return this, for having fluent api */ public RuleConstructor.MethodClause onInterface(Class clazz) { return onSpecifier(clazz.getCanonicalName(), true); } /** * Interface name that rule event is associated to. *

* Example: *

* * new RuleBuilder("rule name")
* .onInterface("javax.transaction.xa.XAResource")
* ... *
* * @param className interface class name as target of rule injection * @return this, for having fluent api */ public RuleConstructor.MethodClause onInterface(String className) { return onSpecifier(className, true); } private RuleConstructor.MethodClause onSpecifier(String className, boolean isInterface) { RuleConstructor.this.className = className; RuleConstructor.this.isInterface = isInterface; return RuleConstructor.this.new MethodClause(); } } public final class MethodClause { /** *

* Defining that the rule will be injected to all sub-classes * or classes implementing the interface. *

* By default Byteman injects the rule only to the specified * class and children classes are not instrumented. *

* The rule class definition is enriched with ^. * As example: CLASS ^org.jboss.byteman.ExampleClass. * * @return this, for having fluent api */ public RuleConstructor.MethodClause includeSubclases() { RuleConstructor.this.isIncludeSubclases = true; return this; } /** *

* Defining method where the rule is injected to. *

* Example: *

* * new RuleBuilder("rule name")
* .onInterface("javax.transaction.xa.XAResource")
* .inMethod("commit")
* ... *
* * @param methodName method name for rule injection * @return this, for having fluent api */ public RuleConstructor.LocationClause inMethod(String methodName) { RuleConstructor.this.methodName = methodName; return RuleConstructor.this.new LocationClause(); } /** *

* Defining method specified by argument types where the rule is injected to. * Arguments restrict which methods are instrumented based on parameters definition. *

* Example: *

* * new RuleBuilder("rule name")
* .onInterface("javax.transaction.xa.XAResource")
* .inMethod("commit", "Xid" , "boolean")
* ... *
* * @param methodName method name for rule injection * @param argTypes method argument types to closer specify what method is instrumented * @return this, for having fluent api */ public RuleConstructor.LocationClause inMethod(String methodName, String... argTypes) { RuleConstructor.this.methodName = methodName + "(" + stringJoin(",", argTypes) + ")"; return RuleConstructor.this.new LocationClause(); } /** * Defining constructor, special method type, * as place for rule injection. * * @return this, for having fluent api */ public RuleConstructor.LocationClause inConstructor() { return inMethod(CONSTRUCTOR_METHOD); } /** *

* Defining constructor, special method type, * as place for rule injection. *

* The type of constructor method is specified by its arguments. * * @param argTypes method argument types to closer specify which method * @return this, for having fluent api */ public RuleConstructor.LocationClause inConstructor(String... argTypes) { return inMethod(CONSTRUCTOR_METHOD, argTypes); } /** * Defining class initialization method as place for rule injection. * * @return this, for having fluent api */ public RuleConstructor.LocationClause inClassInitMethod() { return inMethod(CLASS_CONSTRUCTOR); } /** * Defining class initialization method as place for rule injection. * * @param argTypes method argument types to closer specify which method * @return this, for having fluent api */ public RuleConstructor.LocationClause inClassInitMethod(String... argTypes) { return inMethod(CLASS_CONSTRUCTOR, argTypes); } } public final class LocationClause { /** * Byteman helper class to be used in rule definition. * * @param helperClass byteman helper class * @return this, for having fluent api */ public RuleConstructor.LocationClause helper(Class helperClass) { return helper(helperClass.getCanonicalName()); } /** * Class name of Byteman helper class. * * @param helperClassName byteman helper class name * @return this, for having fluent api */ public RuleConstructor.LocationClause helper(String helperClassName) { RuleConstructor.this.helperName = helperClassName; return this; } /** *

* Rule is invoked at entry point of method. *

* Location specifier is set as AT ENTRY. * * @return this, for having fluent api */ public RuleConstructor.ConditionClause atEntry() { return at("ENTRY"); } /** *

* Rule is invoked at exit point of method. *

* Location specifier is set as AT EXIT. * * @return this, for having fluent api */ public RuleConstructor.ConditionClause atExit() { return at("EXIT"); } /** *

* Rule is invoked at specific line of code * within the method. *

* Location specifier is set as AT LINE <line>. * * @param line line number to be rule injection point * @return this, for having fluent api */ public RuleConstructor.ConditionClause atLine(int line) { return at("LINE " + line); } /** *

* Rule is invoked at point where method reads a variable. *

* Location specifier is set as AT READ <variable>. * * @param variable rule is triggered at write from this variable happen * @return this, for having fluent api */ public RuleConstructor.ConditionClause atRead(String variable) { return at("READ " + variable); } /** *

* Rule is invoked at point where method reads a variable * where occurencePosition defines Nth * textual occurrence of the field access. *

* Location specifier is set as AT READ <variable> <occurencePosition>. * * @param variable rule is triggered at write from this variable happen * @param occurencePosition Nth textual occurrence of reading the field * @return this, for having fluent api */ public RuleConstructor.ConditionClause atRead(String variable, int occurencePosition) { return at("READ " + variable + " " + occurencePosition); } /** *

* Rule is invoked after point where method reads a variable. *

* Location specifier is set as AFTER READ <variable>. * * @param variable rule is triggered after write from this variable happen * @return this, for having fluent api */ public RuleConstructor.ConditionClause afterRead(String variable) { return after("READ " + variable); } /** *

* Rule is invoked after point where method reads a variable where occurencePosition * defines Nth textual occurrence of the field access. *

* Location specifier is set as AFTER READ <variable> <occurencePosition>. * * @param variable rule is triggered after write from this variable happen * @param occurencePosition Nth textual occurrence of reading the field * @return this, for having fluent api */ public RuleConstructor.ConditionClause afterRead(String variable, int occurencePosition) { return after("READ " + variable + " " + occurencePosition); } /** *

* Rule is invoked at point where method writes to a variable. *

* Location specifier is set as AT WRITE <variable>. * * @param variable rule is triggered at write to this variable happen * @return this, for having fluent api */ public RuleConstructor.ConditionClause atWrite(String variable) { return at("WRITE " + variable); } /** *

* Rule is invoked at point where method writes to a variable where occurencePosition * defines Nth textual occurrence of the field write. *

* Location specifier is set as AT WRITE <variable> <occurencePosition>. * * @param variable rule is triggered at write to this variable happen * @param occurencePosition Nth textual occurrence of the field write * @return this, for having fluent api */ public RuleConstructor.ConditionClause atWrite(String variable, int occurencePosition) { return at("WRITE " + variable + " " + occurencePosition); } /** *

* Rule is invoked after point where method writes to a variable. *

* Location specifier is set as AFTER WRITE <variable>. * * @param variable rule is triggered after write to this variable happen * @return this, for having fluent api */ public RuleConstructor.ConditionClause afterWrite(String variable) { return after("WRITE " + variable); } /** *

* Rule is invoked after point where method writes to a variable where occurencePosition * defines Nth textual occurrence of the field write. *

* Location specifier is set as AFTER WRITE <variable> <occurencePosition>. * * @param variable rule is triggered after write to this variable happen * @param occurencePosition Nth textual occurrence of the field write * @return this, for having fluent api */ public RuleConstructor.ConditionClause afterWrite(String variable, int occurencePosition) { return after("WRITE " + variable + " " + occurencePosition); } /** *

* Rule is invoked at point of invocation of method within the trigger method. *

* Location specifier is set as AT INVOKE <variable>. * * @param method method name after which invocation the rule is executed * @return this, for having fluent api */ public RuleConstructor.ConditionClause atInvoke(String method) { return at("INVOKE " + method); } /** *

* Rule is invoked at point of invocation of method within the trigger method * where occurencePosition defines Nth textual occurrence * of the method invocation. *

* Location specifier is set as AT INVOKE <variable> <occurencePosition>. * * @param method method name after which invocation the rule is executed * @param occurencePosition Nth textual occurrence of the method invocation * @return this, for having fluent api */ public RuleConstructor.ConditionClause atInvoke(String method, int occurencePosition) { return at("INVOKE " + method + " " + occurencePosition); } /** *

* Rule is invoked after invocation of method within the trigger method. *

* Location specifier is set as AFTER INVOKE <variable>. * * @param method method name after which invocation the rule is executed * @return this, for having fluent api */ public RuleConstructor.ConditionClause afterInvoke(String method) { return after("INVOKE " + method); } /** *

* Rule is invoked after invocation of method within the trigger method * where occurencePosition defines Nth textual occurrence * of the method invocation. *

* Location specifier is set as AFTER INVOKE <variable> <occurencePosition>. * * @param method method name after which invocation the rule is executed * @param occurencePosition Nth textual occurrence of the method invocation * @return this, for having fluent api */ public RuleConstructor.ConditionClause afterInvoke(String method, int occurencePosition) { return after("INVOKE " + method + " " + occurencePosition); } /** *

* Rule is invoked at entry of synchronization block in the target method. *

* Location specifier is set as AT SYNCHRONIZE. * * @return this, for having fluent api */ public RuleConstructor.ConditionClause atSynchronize() { return at("SYNCHRONIZE"); } /** *

* Rule is invoked at point of invocation of method within the trigger method * where occurencePosition defines Nth textual * occurrence of the method invocation. *

* Location specifier is set as AT SYNCHRONIZE <occurencePosition>. * * @param occurencePosition Nth textual occurrence of the method invocation * @return this, for having fluent api */ public RuleConstructor.ConditionClause atSynchronize(int occurencePosition) { return at("SYNCHRONIZE " + occurencePosition); } /** * Rule is invoked after invocation of method within the trigger method.
* Location specifier is set as AFTER SYNCHRONIZE. * * @return this, for having fluent api */ public RuleConstructor.ConditionClause afterSynchronize() { return after("SYNCHRONIZE"); } /** *

* Rule is invoked after invocation of method within the trigger method * where occurencePosition defines Nth textual occurrence * of the method invocation. *

* Location specifier is set as AFTER SYNCHRONIZE <occurencePosition>. * * @param occurencePosition Nth textual occurrence of the method invocation * @return this, for having fluent api */ public RuleConstructor.ConditionClause afterSynchronize(int occurencePosition) { return after("SYNCHRONIZE " + occurencePosition); } /** *

* Identifies a throw operation within the trigger method. *

* Location specifier is set as AT THROW. * * @return this, for having fluent api */ public RuleConstructor.ConditionClause atThrow() { return at("THROW"); } /** *

* Identifies a throw operation within the trigger method, * specified with count as Nth textual occurrence of a throw * inside of the method defining only that occurrence to trigger * execution of the rule. *

* Location specifier is set as AT THROW <occurencePosition>. * * @param occurencePosition which Nth textual occurrence of a throw triggers the rule * @return this, for having fluent api */ public RuleConstructor.ConditionClause atThrow(int occurencePosition) { return at("THROW " + occurencePosition); } /** *

* Identifies the point where a method returns control back to its caller via * unhandled exceptional control flow. *

* Location specifier is set as AT EXCEPTION EXIT. * * @return this, for having fluent api */ public RuleConstructor.ConditionClause atExceptionExit() { return at("EXCEPTION EXIT"); } /** *

* Rule is invoked AT point which is specified with parameter. *

* Location specifier is predefined with AT keyword * and the rest is up to parameter you provide. *

* When you provide LINE 123 as parameter the location specifier * is set as AT LINE 123. * * @param at specifying rule injection point that is enriched * with AT keyword * @return this, for having fluent api */ public RuleConstructor.ConditionClause at(String at) { return where("AT " + at); } /** *

* Rule is invoked AFTER point which is specified with parameter. *

* Location specifier is predefined with AFTER keyword * and the rest is up to parameter you provide. *

* When you provide READ $0 as parameter the location specifier * is set as AFTER READ $0. * * @param after specifying rule injection point that is enriched * with AFTER keyword * @return this, for having fluent api */ public RuleConstructor.ConditionClause after(String after) { return where("AFTER " + after); } /** *

* Location specifier definition. *

* Defined string is directly used in rule definition. *

* The parameter is expected to be defined as whole location specifier. * For example when you provide AT LINE 123 as parameter * the location specifier is set as AT LINE 123. * * @param where location specifier * @return this, for having fluent api */ RuleConstructor.ConditionClause where(String where) { RuleConstructor.this.where = where; return RuleConstructor.this.new ConditionClause(); } } public final class ConditionClause { /** * Byteman helper class to be used in rule definition. * * @param helperClass byteman helper class * @return this, for having fluent api */ public RuleConstructor.ConditionClause helper(Class helperClass) { return helper(helperClass.getCanonicalName()); } /** * Class name of Byteman helper class. * * @param helperClassName byteman helper class name * @return this, for having fluent api */ public RuleConstructor.ConditionClause helper(String helperClassName) { RuleConstructor.this.helperName = helperClassName; return this; } /** *

* Definition of bind clause. *

* When called as * bind("engine:CoordinatorEngine = $0", "identifier:String = engine.getId()") *

* rule looks *

* * BIND bind("engine:CoordinatorEngine = $0"; * "identifier:String = engine.getId() * * * @param bindClauses bind clauses to be part of the rule * @return this, for having fluent api */ public RuleConstructor.ConditionClause bind(String... bindClauses) { RuleConstructor.this.bind = stringifyClauses(bindClauses); return this; } /** *

* Setting module import definition for the rule. *

* For module import functionality works you need to use parameter * -javaagent modules:. The only provided implementation class * which is to manage module imports is * org.jboss.byteman.modules.jbossmodules.JbossModulesSystem * * @param imports specifying imports clauses which will be added * to byteman rule configuration * @return this, for having fluent api */ public RuleConstructor.ConditionClause imports(String... imports) { StringBuffer importsBuf = new StringBuffer(); for(String importString: imports) { importsBuf .append("IMPORT ") .append(importString) .append(LINEBREAK); } RuleConstructor.this.imports = importsBuf.toString(); return this; } /** *

* Defines rule for being compiled. *

* Default behaviour is to use the interpreter. * * @return this, for having fluent api */ public RuleConstructor.ConditionClause compile() { RuleConstructor.this.compile = "COMPILE"; return this; } /** *

* Defines rule for not being compiled. *

* Default behaviour is to use the interpreter * but byteman system property could be used to change * the default behaviour for rules being compiled every time * then this settings could be useful. * * @return this, for having fluent api */ public RuleConstructor.ConditionClause nocompile() { RuleConstructor.this.compile = "NOCOMPILE"; return this; } /** *

* Rule condition when rule will be executed. *

* Defined string is directly used in rule definition. *

* Rule condition is set as IF <condition>. * * @param condition rule condition string that is used for the rule * @return this, for having fluent api */ public RuleConstructor.ActionClause ifCondition(String condition) { RuleConstructor.this.ifcondition = condition; return RuleConstructor.this.new ActionClause(); } /** *

* Condition ensuring that rule will be executed. *

* Rule condition is set as IF true. * * @return this, for having fluent api */ public RuleConstructor.ActionClause ifTrue() { return ifCondition("true"); } /** *

* Condition ensuring that rule won't be executed. *

* Rule condition is set as IF false. * * @return this, for having fluent api */ public RuleConstructor.ActionClause ifFalse() { return ifCondition("false"); } } public final class ActionClause { /** *

* Definition of actions for the rule. *

* When called as *

* doAction("debug(\"killing JVM\")", "killJVM()") *

* rule looks *

* * DO debug("killing JVM"); * killJVM() * * * @param actions actions definitions to be part of the rule * @return this, for having fluent api */ public RuleConstructor doAction(String... actions) { RuleConstructor.this.action = stringifyClauses(actions); return RuleConstructor.this; } } String getRuleName() { return RuleConstructor.this.ruleName; } private String stringJoin(String join, String... strings) { if (strings == null || strings.length == 0) { return ""; } else if (strings.length == 1) { return strings[0]; } else { StringBuilder sb = new StringBuilder(); sb.append(strings[0]); for (int i = 1; i < strings.length; i++) { sb.append(join).append(strings[i]); } return sb.toString(); } } private String stringifyClauses(String... clauses) { StringBuffer actionsBuffer = new StringBuffer(); boolean isFirstAddition = true; boolean isSemicolon = true; for(String clause: clauses) { if(!isFirstAddition && !isSemicolon) actionsBuffer.append(";"); if(!isFirstAddition) actionsBuffer.append(LINEBREAK); if(!clause.trim().endsWith(";")) isSemicolon = false; if(isFirstAddition) isFirstAddition = false; actionsBuffer.append(clause.trim()); } return actionsBuffer.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy