public void setLastSeenTimestamp(Date lastSeenTimestamp) {
if (activeSince == null
|| (activeSince.getTime() + ACTIVITY_TIMEOUT) < lastSeenTimestamp
- .getTime())
+ .getTime()) {
this.activeSince = lastSeenTimestamp;
+ }
this.lastSeenTimestamp = lastSeenTimestamp;
}
@Override
public int hashCode() {
- if (hashCode != 0)
+ if (hashCode != 0) {
return hashCode;
+ }
final int prime = 31;
hashCode = 1;
hashCode = prime * hashCode
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
+ }
+ if (obj == null) {
return false;
- if (getClass() != obj.getClass())
+ }
+ if (getClass() != obj.getClass()) {
return false;
+ }
Entity other = (Entity) obj;
if (ipv4Address == null) {
- if (other.ipv4Address != null)
+ if (other.ipv4Address != null) {
return false;
- } else if (!ipv4Address.equals(other.ipv4Address))
+ }
+ } else if (!ipv4Address.equals(other.ipv4Address)) {
return false;
- if (macAddress != other.macAddress)
+ }
+ if (macAddress != other.macAddress) {
return false;
+ }
if (port == null) {
- if (other.port != null)
+ if (other.port != null) {
return false;
- } else if (!port.equals(other.port))
+ }
+ } else if (!port.equals(other.port)) {
return false;
+ }
if (vlan == null) {
- if (other.vlan != null)
+ if (other.vlan != null) {
return false;
- } else if (!vlan.equals(other.vlan))
+ }
+ } else if (!vlan.equals(other.vlan)) {
return false;
+ }
return true;
}
Comparable switchId = (Comparable) port.getNode().getID();
Comparable oswitchId = (Comparable) o.port.getNode().getID();
r = switchId.compareTo(oswitchId);
- if (r != 0)
+ if (r != 0) {
return r;
+ }
Comparable portId = (Comparable) port.getID();
Comparable oportId = (Comparable) o.port.getID();
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
+ }
+ if (obj == null) {
return false;
- if (getClass() != obj.getClass())
+ }
+ if (getClass() != obj.getClass()) {
return false;
+ }
SwitchPort other = (SwitchPort) obj;
- if (errorStatus != other.errorStatus)
+ if (errorStatus != other.errorStatus) {
return false;
+ }
if (port == null) {
- if (other.port != null)
+ if (other.port != null) {
return false;
- } else if (!port.equals(other.port))
+ }
+ } else if (!port.equals(other.port)) {
return false;
+ }
return true;
}
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (!super.equals(obj))
+ }
+ if (!super.equals(obj)) {
return false;
- if (getClass() != obj.getClass())
+ }
+ if (getClass() != obj.getClass()) {
return false;
+ }
HostNodeConnector other = (HostNodeConnector) obj;
if (nodeConnector == null) {
- if (other.nodeConnector != null)
+ if (other.nodeConnector != null) {
return false;
- } else if (!nodeConnector.equals(other.nodeConnector))
+ }
+ } else if (!nodeConnector.equals(other.nodeConnector)) {
return false;
- if (staticHost != other.staticHost)
+ }
+ if (staticHost != other.staticHost) {
return false;
- if (vlan != other.vlan)
+ }
+ if (vlan != other.vlan) {
return false;
+ }
return true;
}
EthernetAddress e = (EthernetAddress) getDataLayerAddress();
macaddr = e.getValue();
}
- if (macaddr == null)
+ if (macaddr == null) {
return false;
+ }
return !Arrays.equals(emptyArray, macaddr);
}
Object item = it.next();
for (TypeInfo child : _types.values()) {
Object val = child.retrieve(item, query, index);
- if (val != null) objects.add(val);
+ if (val != null) {
+ objects.add(val);
+ }
}
}
return objects;
@Override
public synchronized void explore() {
- if (_explored) return;
+ if (_explored) {
+ return;
+ }
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("exploring iteratable type: {} gtype: {}", _class,
_accessor.getGenericType());
@Override
public <T> Query<T> createQuery(String queryString, Class<T> type) throws QueryException {
- if (queryString == null || queryString.trim().length() == 0) return null;
+ if (queryString == null || queryString.trim().length() == 0) {
+ return null;
+ }
try {
- if (LOGGER.isDebugEnabled()) LOGGER.debug("Processing query: {}", queryString);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Processing query: {}", queryString);
+ }
// FiqlParser is a parser generated by javacc
Expression expression = FiqlParser.parse(queryString);
- if (LOGGER.isDebugEnabled()) LOGGER.debug("Query expression: {}", expression);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Query expression: {}", expression);
+ }
// create Query and return;
return new QueryImpl<T>(type, expression);
} catch (Exception ex) {
- if (LOGGER.isDebugEnabled()) LOGGER.error("Query processing failed = {}",
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.error("Query processing failed = {}",
queryString, ex);
+ }
throw new QueryException("Unable to parse query.", ex);
}
}
}
private boolean compare(Object valueToMatch, Object actualValue, OP operator) {
- if (valueToMatch == null || actualValue == null) return false;
+ if (valueToMatch == null || actualValue == null) {
+ return false;
+ }
if (ALLOW_OBJECT_STRING_COMPARE && (valueToMatch instanceof String)
&& !(actualValue instanceof String)) {
actualValue = actualValue.toString();
}
}
private Object parse(String arg, Object value) {
- if (value == null) return null;
+ if (value == null) {
+ return null;
+ }
try {
if (value instanceof String) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("retrieve: {}/{} type:{}", index, query.length, target.getClass());
}
- if (index >= query.length) return null;
+ if (index >= query.length) {
+ return null;
+ }
explore();
if (!target.getClass().equals(_class)) {
if (_class.isAssignableFrom(target.getClass())) {
}
}
TypeInfo child = getChild(query[index]);
- if (child == null) return null;
+ if (child == null) {
+ return null;
+ }
target = child.getAccessor().getValue(target);
if (index+1 == query.length) {
// match found
* Explore the type info for children.
*/
public synchronized void explore() {
- if (_explored) return;
+ if (_explored) {
+ return;
+ }
for (Class<?> c = _class; c != null; c = c.getSuperclass()) {
- if (c.equals(Object.class)) break;
+ if (c.equals(Object.class)) {
+ break;
+ }
// Currently only fields and methods annotated with JAXB annotations are
// considered as valid for search purposes.
//check methods first
for (Method m : c.getDeclaredMethods()) {
String tn = getTypeName(m, _accessType);
if (tn != null) {
- if (LOGGER.isDebugEnabled()) LOGGER.debug(
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug(
"exploring type: {} name: {} method: {}",
_class.getSimpleName(), tn, m);
+ }
_types.put(tn, createTypeInfo(tn, new Accessor(m)));
}
}
for (Field f : c.getDeclaredFields()) {
String tn = getTypeName(f, _accessType);
if (tn != null) {
- if (LOGGER.isDebugEnabled()) LOGGER.debug(
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug(
"exploring type: {} name: {} field: {}",
_class.getSimpleName(), tn, f);
+ }
_types.put(tn, createTypeInfo(tn, new Accessor(f)));
}
}
PropertyDescriptor[] props = info.getPropertyDescriptors();
for (PropertyDescriptor pd : props)
{
- if (m.equals(pd.getReadMethod())) return pd.getName();
+ if (m.equals(pd.getReadMethod())) {
+ return pd.getName();
+ }
}
}
catch (IntrospectionException e)
// root is always a composite type
// FIXME assert its a JAXB type
XmlRootElement root = clz.getAnnotation(XmlRootElement.class);
- if (root == null) throw new IllegalArgumentException("Not a JAXB type: " + clz);
- if (name == null) name = getRootName(clz);
+ if (root == null) {
+ throw new IllegalArgumentException("Not a JAXB type: " + clz);
+ }
+ if (name == null) {
+ name = getRootName(clz);
+ }
return new TypeInfo(name, clz, null);
}
public static String getRootName(Class<?> cls) {
XmlRootElement root = cls.getAnnotation(XmlRootElement.class);
- if (root == null) return null;
+ if (root == null) {
+ return null;
+ }
String rootName = root.name();
if (DEFAULT_NAME.equals(rootName)) {
String clsName = cls.getSimpleName();
return null;
}
}
- if (DEFAULT_NAME.equals(name)) return dflt;
+ if (DEFAULT_NAME.equals(name)) {
+ return dflt;
+ }
return name;
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("retrieve collection: {}/{}", index, query.length);
}
- if (index >= query.length) return null;
+ if (index >= query.length) {
+ return null;
+ }
explore();
TypeInfo child = getChild(query[index]);
- if (child == null) return null;
+ if (child == null) {
+ return null;
+ }
if (query.length == index+1) { // skipping this node
return target;
}else { // if list of list go to next node to get value
@Override
public synchronized void explore() {
- if (_explored) return;
+ if (_explored) {
+ return;
+ }
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("exploring wrapper type: {} gtype: {}", _class,
_accessor.getGenericType());
public static void checkCondition(boolean condition, String message,
JmxAttribute jmxAttribute) throws JmxAttributeValidationException {
- if (condition == false) {
+ if (!condition) {
throw new JmxAttributeValidationException(
jmxAttribute.getAttributeName() + " " + message,
jmxAttribute);
if (quoted == null) {
throw new IllegalArgumentException("Cannot find " + SERVICE_QNAME_KEY + " in " + objectName);
}
- if (quoted.startsWith("\"") == false || quoted.endsWith("\"") == false) {
+ if (!quoted.startsWith("\"") || !quoted.endsWith("\"")) {
throw new IllegalArgumentException("Quotes not found in " + objectName);
}
String substring = quoted.substring(1);
throw new IllegalArgumentException(
"Expected ObjectName with transaction:" + inputON);
}
- if (ON_DOMAIN.equals(inputON.getDomain()) == false) {
+ if (!ON_DOMAIN.equals(inputON.getDomain())) {
throw new IllegalArgumentException("Expected different domain: "
+ inputON);
}
Map<String, String> allProperties = getAdditionalProperties(on);
Map<String, String> result = new HashMap<>();
for (Entry<String, String> entry : allProperties.entrySet()) {
- if (blacklist.contains(entry.getKey()) == false) {
+ if (!blacklist.contains(entry.getKey())) {
result.put(entry.getKey(), entry.getValue());
}
}
* {@inheritDoc}
*/
@Override
- @SuppressWarnings("PMD.AvoidCatchingThrowable")
public synchronized CommitStatus commitConfig(ObjectName transactionControllerON)
throws ConflictingVersionException, ValidationException {
final String transactionName = ObjectNameUtil
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static java.lang.String.format;
-
/**
* Contains common code for readable/rw dynamic mbean wrappers. Routes all
* requests (getAttribute, setAttribute, invoke) into the actual instance, but
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>binding-type-provider</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-util</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
final String javaNamePrefix) {
return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName, dataNodeContainer, moduleLocalNameFromXPath,
- typeProviderWrapper, javaNamePrefix, currentModule).values();
+ typeProviderWrapper, javaNamePrefix, currentModule, schemaContext).values();
}
import static com.google.common.base.Preconditions.checkState;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
/**
* Holds information about runtime bean to be generated. There are two kinds of
* lined via children so that a tree with all beans can be created.
*/
public class RuntimeBeanEntry {
+
+ private static final Function<SchemaNode, QName> QNAME_FROM_NODE = new Function<SchemaNode, QName>() {
+ @Override
+ public QName apply(final SchemaNode input) {
+ return input.getQName();
+ }
+ };
+
+ private static final Function<UnknownSchemaNode, String> UNKNOWN_NODE_TO_STRING = new Function<UnknownSchemaNode, String>() {
+ @Override
+ public String apply(final UnknownSchemaNode input) {
+ return input.getQName().getLocalName() + input.getNodeParameter();
+ }
+ };
+
private final String packageName;
private final String yangName, javaNamePrefix;
private final boolean isRoot;
public static Map<String, RuntimeBeanEntry> extractClassNameToRuntimeBeanMap(
final String packageName, final DataNodeContainer container,
final String moduleYangName, final TypeProviderWrapper typeProviderWrapper,
- final String javaNamePrefix, final Module currentModule) {
+ final String javaNamePrefix, final Module currentModule, final SchemaContext schemaContext) {
- Map<QName, Set<RpcDefinition>> identitiesToRpcs = getIdentitiesToRpcs(currentModule);
AttributesRpcsAndRuntimeBeans attributesRpcsAndRuntimeBeans = extractSubtree(
packageName, container, typeProviderWrapper, currentModule,
- identitiesToRpcs);
+ schemaContext);
Map<String, RuntimeBeanEntry> result = new HashMap<>();
List<AttributeIfc> attributes;
return result;
}
- private static Map<QName/* of identity */, Set<RpcDefinition>> getIdentitiesToRpcs(
- final Module currentModule) {
- // currently only looks for local identities (found in currentModule)
- Map<QName, Set<RpcDefinition>> result = new HashMap<>();
- for (IdentitySchemaNode identity : currentModule.getIdentities()) {
- // add all
- result.put(identity.getQName(), new HashSet<RpcDefinition>());
- }
+ private static Multimap<QName/* of identity */, RpcDefinition> getIdentitiesToRpcs(
+ final SchemaContext schemaCtx) {
+ Multimap<QName, RpcDefinition> result = HashMultimap.create();
+ for (Module currentModule : schemaCtx.getModules()) {
- for (RpcDefinition rpc : currentModule.getRpcs()) {
- ContainerSchemaNode input = rpc.getInput();
- if (input != null) {
- for (UsesNode uses : input.getUses()) {
+ // Find all identities in current module for later identity->rpc mapping
+ Set<QName> allIdentitiesInModule = Sets.newHashSet(Collections2.transform(currentModule.getIdentities(), QNAME_FROM_NODE));
- if (uses.getGroupingPath().getPath().size() != 1) {
- continue;
- }
+ for (RpcDefinition rpc : currentModule.getRpcs()) {
+ ContainerSchemaNode input = rpc.getInput();
+ if (input != null) {
+ for (UsesNode uses : input.getUses()) {
- // check grouping path
- QName qname = uses.getGroupingPath().getPath().get(0);
- if (false == qname
- .equals(ConfigConstants.RPC_CONTEXT_REF_GROUPING_QNAME)) {
- continue;
- }
+ // Check if the rpc is config rpc by looking for input argument rpc-context-ref
+ Iterator<QName> pathFromRoot = uses.getGroupingPath().getPathFromRoot().iterator();
+ if (!pathFromRoot.hasNext() ||
+ !pathFromRoot.next().equals(ConfigConstants.RPC_CONTEXT_REF_GROUPING_QNAME)) {
+ continue;
+ }
- for (SchemaNode refinedNode : uses.getRefines().values()) {
-
- for (UnknownSchemaNode unknownSchemaNode : refinedNode
- .getUnknownSchemaNodes()) {
- if (ConfigConstants.RPC_CONTEXT_INSTANCE_EXTENSION_QNAME
- .equals(unknownSchemaNode.getNodeType())) {
- String localIdentityName = unknownSchemaNode
- .getNodeParameter();
- QName identityQName = QName.create(
- currentModule.getNamespace(),
- currentModule.getRevision(),
- localIdentityName);
- Set<RpcDefinition> rpcDefinitions = result
- .get(identityQName);
- if (rpcDefinitions == null) {
- throw new IllegalArgumentException(
- "Identity referenced by rpc not found. Identity:"
- + localIdentityName + " , rpc "
- + rpc);
+ for (SchemaNode refinedNode : uses.getRefines().values()) {
+ for (UnknownSchemaNode unknownSchemaNode : refinedNode
+ .getUnknownSchemaNodes()) {
+ if (ConfigConstants.RPC_CONTEXT_INSTANCE_EXTENSION_QNAME
+ .equals(unknownSchemaNode.getNodeType())) {
+ String localIdentityName = unknownSchemaNode
+ .getNodeParameter();
+ QName identityQName = QName.create(
+ currentModule.getNamespace(),
+ currentModule.getRevision(),
+ localIdentityName);
+ Preconditions.checkArgument(allIdentitiesInModule.contains(identityQName),
+ "Identity referenced by rpc not found. Identity: %s, rpc: %s", localIdentityName, rpc);
+ result.put(identityQName, rpc);
}
- rpcDefinitions.add(rpc);
}
}
}
private static AttributesRpcsAndRuntimeBeans extractSubtree(
final String packageName, final DataNodeContainer subtree,
final TypeProviderWrapper typeProviderWrapper, final Module currentModule,
- final Map<QName, Set<RpcDefinition>> identitiesToRpcs) {
+ final SchemaContext ctx) {
+
+ Multimap<QName, RpcDefinition> identitiesToRpcs = getIdentitiesToRpcs(ctx);
List<AttributeIfc> attributes = Lists.newArrayList();
List<RuntimeBeanEntry> runtimeBeanEntries = new ArrayList<>();
ListSchemaNode listSchemaNode = (ListSchemaNode) child;
RuntimeBeanEntry hierarchicalChild = createHierarchical(
packageName, listSchemaNode, typeProviderWrapper,
- currentModule, identitiesToRpcs);
+ currentModule, ctx);
runtimeBeanEntries.add(hierarchicalChild);
} else /* ordinary list attribute */{
ListAttribute listAttribute = ListAttribute.create(
if (ConfigConstants.RPC_CONTEXT_INSTANCE_EXTENSION_QNAME
.equals(unknownSchemaNode.getNodeType())) {
String localIdentityName = unknownSchemaNode.getNodeParameter();
- QName identityQName = QName.create(currentModule.getNamespace(),
- currentModule.getRevision(), localIdentityName);
- Set<RpcDefinition> rpcDefinitions = identitiesToRpcs
- .get(identityQName);
- if (rpcDefinitions == null) {
- throw new IllegalArgumentException("Cannot find identity "
- + localIdentityName + " to be used as "
- + "context reference when resolving "
- + unknownSchemaNode);
- }
+ QName identityQName = unknownSchemaNode.isAddedByUses() ?
+ findQNameFromGrouping(subtree, ctx, unknownSchemaNode, localIdentityName) :
+ QName.create(currentModule.getNamespace(), currentModule.getRevision(), localIdentityName);
// convert RpcDefinition to Rpc
- for (RpcDefinition rpcDefinition : rpcDefinitions) {
+ for (RpcDefinition rpcDefinition : identitiesToRpcs.get(identityQName)) {
String name = TypeProviderWrapper
.findJavaParameter(rpcDefinition);
AttributeIfc returnType;
attributes, rpcs);
}
+ /**
+ * Find "proper" qname of unknown node in case it comes from a grouping
+ */
+ private static QName findQNameFromGrouping(final DataNodeContainer subtree, final SchemaContext ctx, final UnknownSchemaNode unknownSchemaNode, final String localIdentityName) {
+ QName identityQName = null;
+ for (UsesNode usesNode : subtree.getUses()) {
+ SchemaNode dataChildByName = SchemaContextUtil.findDataSchemaNode(ctx, usesNode.getGroupingPath());
+ Module m = SchemaContextUtil.findParentModule(ctx, dataChildByName);
+ List<UnknownSchemaNode> unknownSchemaNodes = dataChildByName.getUnknownSchemaNodes();
+ if(Collections2.transform(unknownSchemaNodes, UNKNOWN_NODE_TO_STRING).contains(UNKNOWN_NODE_TO_STRING.apply(unknownSchemaNode))) {
+ identityQName = QName.create(dataChildByName.getQName(), localIdentityName);
+ }
+ }
+ return identityQName;
+ }
+
private static AttributeIfc getReturnTypeAttribute(final DataSchemaNode child, final TypeProviderWrapper typeProviderWrapper,
final String packageName) {
if (child instanceof LeafSchemaNode) {
private static RuntimeBeanEntry createHierarchical(final String packageName,
final ListSchemaNode listSchemaNode,
final TypeProviderWrapper typeProviderWrapper, final Module currentModule,
- final Map<QName, Set<RpcDefinition>> identitiesToRpcs) {
+ final SchemaContext ctx) {
// supported are numeric types, strings, enums
// get all attributes
AttributesRpcsAndRuntimeBeans attributesRpcsAndRuntimeBeans = extractSubtree(
packageName, listSchemaNode, typeProviderWrapper,
- currentModule, identitiesToRpcs);
+ currentModule, ctx);
Optional<String> keyYangName;
if (listSchemaNode.getKeyDefinition().isEmpty()) {
.getUnknownSchemaNodes();
Map<String, RuntimeBeanEntry> runtimeBeans = RuntimeBeanEntry
.extractClassNameToRuntimeBeanMap(PACKAGE_NAME, caseNode, "test-name", new TypeProviderWrapper(new
- TypeProviderImpl(context)), "test", jmxImplModule);
+ TypeProviderImpl(context)), "test", jmxImplModule, context);
assertEquals(1, runtimeBeans.size());
RuntimeBeanEntry runtimeMXBean = runtimeBeans.get("testRuntimeMXBean");
assertTrue(runtimeMXBean.isRoot());
package org.opendaylight.controller.config.yang.test.util;
import com.google.common.collect.Lists;
+import java.math.BigInteger;
import java.util.List;
import org.opendaylight.controller.config.yang.test.impl.Asdf;
import org.opendaylight.controller.config.yang.test.impl.Deep2;
return asdf;
}
+ @Override
+ public BigInteger getCommonStat() {
+ return new BigInteger("54");
+ }
+
@Override
public String noArg(final String arg1) {
return arg1.toUpperCase();
}
+ @Override
+ public Long commonRpcTwo() {
+ return 1L;
+ }
+
+ @Override
+ public String commonRpcThree() {
+ return "true";
+ }
+
+ @Override
+ public Boolean commonRpc() {
+ return true;
+ }
+
+ @Override
+ public void netconfImplRpcFromGrouping() {
+ // rpc from grouping within same yang module
+ }
+
});
for (int i = 0; i < module.getSimpleShort(); i++) {
import ietf-inet-types { prefix inet; revision-date 2010-09-24;}
import rpc-context { prefix rpcx; revision-date 2013-06-17; }
import test-types { prefix tt; revision-date 2013-11-27; }
+ import test-groups { prefix tg; revision-date 2014-12-08; }
description
"Testing IMPL";
}
}
+ grouping netconf-impl-rpc {
+ rpcx:rpc-context-instance netconf-impl-rpc-ctx;
+ }
+
+ identity netconf-impl-rpc-ctx;
+
+ rpc netconf-impl-rpc-from-grouping {
+ input {
+ uses rpcx:rpc-context-ref {
+ refine context-instance {
+ rpcx:rpc-context-instance "netconf-impl-rpc-ctx";
+ }
+ }
+ }
+ }
+
augment "/config:modules/config:module/config:state" {
case impl-netconf {
when "/config:modules/config:module/config:type = 'impl-netconf'";
// rpc
rpcx:rpc-context-instance "test-rpc";
+ // add some stats + rpc from groupings outside this module
+ uses tt:common-operational;
+ uses tg:common-operational-rpc;
+ uses netconf-impl-rpc;
+
// root runtime bean
leaf created-sessions {
type uint32;
--- /dev/null
+module test-groups {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:test:groups";
+ prefix "tg";
+
+ import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+
+ description
+ "Groupings generated for testing";
+
+ revision "2014-12-08";
+
+ grouping common-operational-rpc {
+ rpcx:rpc-context-instance common-rpc-ctx;
+ rpcx:rpc-context-instance common-rpc-ctx-two;
+ }
+
+ identity common-rpc-ctx;
+ identity common-rpc-ctx-two;
+
+ rpc common-rpc {
+ input {
+ uses rpcx:rpc-context-ref {
+ refine context-instance {
+ rpcx:rpc-context-instance "common-rpc-ctx";
+ }
+ }
+ }
+
+ output {
+ leaf output {
+ type boolean;
+ }
+ }
+ }
+
+ rpc common-rpc-two {
+ input {
+ uses rpcx:rpc-context-ref {
+ refine context-instance {
+ rpcx:rpc-context-instance "common-rpc-ctx-two";
+ }
+ }
+ }
+
+ output {
+ leaf output {
+ type uint32;
+ }
+ }
+ }
+}
namespace "urn:opendaylight:params:xml:ns:yang:controller:config:test:types";
prefix "tt";
+ import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+
description
"Types generated for testing";
identity test-identity2 {
base test-identity1;
}
+
+ grouping common-operational {
+ leaf common-stat {
+ type uint64;
+ }
+ // This would not work, since it clashes with identity common-rpc-ctx from test-groups
+ // Both grouping add the same unknown node "rpcx:rpc-context-instance common-rpc-ctx-three;"
+ // and we cannot match the unknown node to the grouping that added it
+ //rpcx:rpc-context-instance common-rpc-ctx-three;
+ rpcx:rpc-context-instance common-rpc-ctx-three;
+ }
+
+ //identity common-rpc-ctx;
+ identity common-rpc-ctx-three;
+
+ rpc common-rpc-three {
+ input {
+ uses rpcx:rpc-context-ref {
+ refine context-instance {
+ rpcx:rpc-context-instance "common-rpc-ctx-three";
+ }
+ }
+ }
+
+ output {
+ leaf output {
+ type string;
+ }
+ }
+ }
}
package org.opendaylight.controller.md.sal.dom.store.benchmark;
import java.util.concurrent.TimeUnit;
+
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
-import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl;
+import org.opendaylight.controller.md.sal.dom.broker.impl.SerializedDOMDataBroker;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Measurement;
*/
public abstract class AbstractInMemoryBrokerWriteTransactionBenchmark extends AbstractInMemoryWriteTransactionBenchmark {
- protected DOMDataBrokerImpl domBroker;
+ protected SerializedDOMDataBroker domBroker;
protected void initTestNode() throws Exception {
final YangInstanceIdentifier testPath = YangInstanceIdentifier.builder(BenchmarkModel.TEST_PATH)
package org.opendaylight.controller.sal.binding.codegen.impl;
import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.setRoutingTable;
-
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-
+import javax.annotation.concurrent.GuardedBy;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
public class RpcRouterCodegenInstance<T extends RpcService> implements //
RpcRouter<T>, RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
return new DefaultRpcImplementationRegistration(service);
}
- private class RoutedRpcRegistrationImpl extends AbstractObjectRegistration<T> implements RoutedRpcRegistration<T> {
+ private final class RoutedRpcRegistrationImpl extends AbstractObjectRegistration<T> implements RoutedRpcRegistration<T> {
+ /*
+ * FIXME: retaining this collection is not completely efficient. We really should be storing
+ * a reference to this registration, as a particular listener may be registered multiple
+ * times -- and then this goes kaboom in various aspects.
+ */
+ @GuardedBy("this")
+ private final Collection<Class<? extends BaseIdentity>> contexts = new ArrayList<>(1);
public RoutedRpcRegistrationImpl(final T instance) {
super(instance);
}
@Override
- public void registerPath(final Class<? extends BaseIdentity> context, final InstanceIdentifier<?> path) {
+ public synchronized void registerPath(final Class<? extends BaseIdentity> context, final InstanceIdentifier<?> path) {
+ if (isClosed()) {
+ LOG.debug("Closed registration of {} ignoring new path {}", getInstance(), path);
+ return;
+ }
+
routingTables.get(context).updateRoute(path, getInstance());
+ contexts.add(context);
}
@Override
- public void unregisterPath(final Class<? extends BaseIdentity> context, final InstanceIdentifier<?> path) {
+ public synchronized void unregisterPath(final Class<? extends BaseIdentity> context, final InstanceIdentifier<?> path) {
+ if (isClosed()) {
+ LOG.debug("Closed unregistration of {} ignoring new path {}", getInstance(), path);
+ return;
+ }
+
routingTables.get(context).removeRoute(path, getInstance());
+ contexts.remove(context);
}
+ @Deprecated
@Override
public void registerInstance(final Class<? extends BaseIdentity> context, final InstanceIdentifier<?> instance) {
registerPath(context, instance);
}
+ @Deprecated
@Override
public void unregisterInstance(final Class<? extends BaseIdentity> context, final InstanceIdentifier<?> instance) {
unregisterPath(context, instance);
}
@Override
- protected void removeRegistration() {
-
+ protected synchronized void removeRegistration() {
+ for (Class<? extends BaseIdentity> ctx : contexts) {
+ routingTables.get(ctx).removeAllReferences(getInstance());
+ }
+ contexts.clear();
}
}
- private class DefaultRpcImplementationRegistration extends AbstractObjectRegistration<T> implements RpcRegistration<T> {
+ private final class DefaultRpcImplementationRegistration extends AbstractObjectRegistration<T> implements RpcRegistration<T> {
protected DefaultRpcImplementationRegistration(final T instance) {
package org.opendaylight.controller.sal.binding.codegen.impl;
import java.util.Collections;
+import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-class RpcRoutingTableImpl<C extends BaseIdentity, S extends RpcService> //
-implements //
+final class RpcRoutingTableImpl<C extends BaseIdentity, S extends RpcService> implements
Mutable, //
RpcRoutingTable<C, S>, //
RouteChangePublisher<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
private RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> listener;
private S defaultRoute;
- public RpcRoutingTableImpl(String routerName,Class<C> contextType, Class<S> serviceType) {
+ public RpcRoutingTableImpl(final String routerName,final Class<C> contextType, final Class<S> serviceType) {
super();
this.routerName = routerName;
this.serviceType = serviceType;
}
@Override
- public void setDefaultRoute(S target) {
+ public void setDefaultRoute(final S target) {
defaultRoute = target;
}
@Override
public <L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
- L listener) {
+ final L listener) {
return new SingletonListenerRegistration<L>(listener);
}
@Override
@SuppressWarnings("unchecked")
- public void updateRoute(InstanceIdentifier<?> path, S service) {
+ public void updateRoute(final InstanceIdentifier<?> path, final S service) {
S previous = this.routes.put(path, service);
LOGGER.debug("Route {} updated to {} in routing table {}",path,service,this);
@Override
@SuppressWarnings("unchecked")
- public void removeRoute(InstanceIdentifier<?> path) {
+ public void removeRoute(final InstanceIdentifier<?> path) {
S previous = this.routes.remove(path);
LOGGER.debug("Route {} to {} removed in routing table {}",path,previous,this);
@SuppressWarnings("rawtypes")
}
}
- public void removeRoute(InstanceIdentifier<?> path, S service) {
+ void removeRoute(final InstanceIdentifier<?> path, final S service) {
@SuppressWarnings("rawtypes")
RouteChangeListener listenerCapture = listener;
if (routes.remove(path, service) && listenerCapture != null) {
}
@Override
- public S getRoute(InstanceIdentifier<?> nodeInstance) {
+ public S getRoute(final InstanceIdentifier<?> nodeInstance) {
S route = routes.get(nodeInstance);
if (route != null) {
return route;
return unmodifiableRoutes;
}
- protected void removeAllReferences(S service) {
-
+ void removeAllReferences(final S service) {
+ // FIXME: replace this via properly-synchronized BiMap (or something)
+ final Iterator<S> it = routes.values().iterator();
+ while (it.hasNext()) {
+ final S s = it.next();
+ if (service.equals(s)) {
+ it.remove();
+ }
+ }
}
-
-
@Override
public String toString() {
return "RpcRoutingTableImpl [router=" + routerName + ", service=" + serviceType.getSimpleName() + ", context="
+ contextType.getSimpleName() + "]";
}
-
-
private class SingletonListenerRegistration<L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> extends
AbstractObjectRegistration<L>
implements ListenerRegistration<L> {
- public SingletonListenerRegistration(L instance) {
+ public SingletonListenerRegistration(final L instance) {
super(instance);
listener = instance;
}
package org.opendaylight.controller.sal.binding.impl;
import static com.google.common.base.Preconditions.checkState;
-
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.util.concurrent.UncheckedExecutionException;
import java.util.EventListener;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
-
import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Throwables;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.util.concurrent.UncheckedExecutionException;
-
public class RpcProviderRegistryImpl implements RpcProviderRegistry, RouteChangePublisher<RpcContextIdentifier, InstanceIdentifier<?>> {
private RuntimeCodeGenerator rpcFactory = SingletonHolder.RPC_GENERATOR_IMPL;
}
@Override
- public final <T extends RpcService> RpcRegistration<T> addRpcImplementation(final Class<T> type, final T implementation)
- throws IllegalStateException {
+ public final <T extends RpcService> RpcRegistration<T> addRpcImplementation(final Class<T> type, final T implementation) {
// FIXME: This should be well documented - addRpcImplementation for
// routed RPCs
}
- private class RouteChangeForwarder<T extends RpcService> implements RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
-
+ private final class RouteChangeForwarder<T extends RpcService> implements RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
private final Class<T> type;
- public RouteChangeForwarder(final Class<T> type) {
+ RouteChangeForwarder(final Class<T> type) {
this.type = type;
}
}
}
- public static class RpcProxyRegistration<T extends RpcService> extends AbstractObjectRegistration<T> implements RpcRegistration<T> {
-
+ private static final class RpcProxyRegistration<T extends RpcService> extends AbstractObjectRegistration<T> implements RpcRegistration<T> {
+ private final RpcProviderRegistryImpl registry;
private final Class<T> serviceType;
- private RpcProviderRegistryImpl registry;
- public RpcProxyRegistration(final Class<T> type, final T service, final RpcProviderRegistryImpl registry) {
+ RpcProxyRegistration(final Class<T> type, final T service, final RpcProviderRegistryImpl registry) {
super(service);
+ this.registry = Preconditions.checkNotNull(registry);
this.serviceType = type;
- this.registry = registry;
}
@Override
@Override
protected void removeRegistration() {
- if (registry != null) {
- T publicProxy = registry.getRpcService(serviceType);
- RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy);
- if (currentDelegate == getInstance()) {
- RuntimeCodeHelper.setDelegate(publicProxy, null);
- }
- registry = null;
+ T publicProxy = registry.getRpcService(serviceType);
+ RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy);
+ if (currentDelegate == getInstance()) {
+ RuntimeCodeHelper.setDelegate(publicProxy, null);
}
}
}
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
-
import com.google.common.base.Function;
-import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.Callable;
-
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
-import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
import org.opendaylight.controller.sal.core.api.RpcImplementation;
import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.yangtools.concepts.CompositeObjectRegistration;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final Set<QName> supportedRpcs;
private final WeakReference<Class<? extends RpcService>> rpcServiceType;
- private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
+ private Set<RoutedRpcRegistration> registrations;
private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
private final RpcService proxy;
private final RpcProviderRegistry baRpcRegistry;
private final RpcProviderRegistryImpl baRpcRegistryImpl;
- private final Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> toDOMInstanceIdentifier;
+ private final Function<InstanceIdentifier<?>, YangInstanceIdentifier> toDOMInstanceIdentifier;
private final static Method EQUALS_METHOD;
this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
this.supportedRpcs = mappingService.getRpcQNamesFor(service);
- toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier>() {
-
+ this.toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, YangInstanceIdentifier>() {
@Override
- public org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier apply(final InstanceIdentifier<?> input) {
+ public YangInstanceIdentifier apply(final InstanceIdentifier<?> input) {
return mappingService.toDataDom(input);
}
};
final RpcProvisionRegistry biRpcRegistry, final RpcProviderRegistry baRpcRegistry, final RpcProviderRegistryImpl registryImpl) {
this(service, mappingService, biRpcRegistry, baRpcRegistry,registryImpl);
- final ImmutableSet.Builder<Broker.RoutedRpcRegistration> registrationsBuilder = ImmutableSet.builder();
+ final ImmutableSet.Builder<RoutedRpcRegistration> registrationsBuilder = ImmutableSet.builder();
try {
for (QName rpc : supportedRpcs) {
registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
public void registerPaths(final Class<? extends BaseIdentity> context,
final Class<? extends RpcService> service, final Set<InstanceIdentifier<?>> set) {
QName ctx = BindingReflections.findQName(context);
- for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier path : FluentIterable.from(set).transform(
- toDOMInstanceIdentifier)) {
- for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
+ for (YangInstanceIdentifier path : Collections2.transform(set, toDOMInstanceIdentifier)) {
+ for (RoutedRpcRegistration reg : registrations) {
reg.registerPath(ctx, path);
}
}
public void removePaths(final Class<? extends BaseIdentity> context, final Class<? extends RpcService> service,
final Set<InstanceIdentifier<?>> set) {
QName ctx = BindingReflections.findQName(context);
- for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier path : FluentIterable.from(set).transform(
- toDOMInstanceIdentifier)) {
- for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
+ for (YangInstanceIdentifier path : Collections2.transform(set, toDOMInstanceIdentifier)) {
+ for (RoutedRpcRegistration reg : registrations) {
reg.unregisterPath(ctx, path);
}
}
package org.opendaylight.controller.sal.binding.impl.connect.dom;
+import com.google.common.base.Optional;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.WeakHashMap;
-
import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
-import com.google.common.base.Optional;
-
/**
* Manager responsible for instantiating forwarders responsible for
* forwarding of RPC invocations from DOM Broker to Binding Aware Broker
@Override
public void onRouteChange(final RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
- for (Map.Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
- bindingRoutesAdded(entry);
+ // Process removals first
+ for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getRemovals().entrySet()) {
+ final Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
+ if (context != null) {
+ final Class<? extends RpcService> service = entry.getKey().getRpcService();
+ getRpcForwarder(service, context).removePaths(context, service, entry.getValue());
+ }
}
- }
- private void bindingRoutesAdded(final Map.Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
- Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
- Class<? extends RpcService> service = entry.getKey().getRpcService();
- if (context != null) {
- getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
+ for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
+ final Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
+ if (context != null) {
+ final Class<? extends RpcService> service = entry.getKey().getRpcService();
+ getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
+ }
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. 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
+ */
+
+package org.opendaylight.controller.cluster.raft.protobuff.client.messages;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.GeneratedMessage;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.UnknownFieldSet;
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.ref.SoftReference;
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.controller.protobuff.messages.cluster.raft.AppendEntriesMessages;
+import org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CompositeModificationByteStringPayload extends Payload implements
+ Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private ByteString byteString;
+ private SoftReference<PersistentMessages.CompositeModification> modificationReference;
+ private static final Logger LOG = LoggerFactory.getLogger(CompositeModificationByteStringPayload.class);
+
+ public CompositeModificationByteStringPayload(){
+ byteString = null;
+ }
+ public CompositeModificationByteStringPayload(Object modification){
+ this(((PersistentMessages.CompositeModification) modification).toByteString());
+ this.modificationReference = new SoftReference<>((PersistentMessages.CompositeModification) modification);
+ }
+
+ private CompositeModificationByteStringPayload(ByteString byteString){
+ this.byteString = Preconditions.checkNotNull(byteString, "byteString should not be null");
+ }
+
+
+ @Override
+ public Map<GeneratedMessage.GeneratedExtension, PersistentMessages.CompositeModification> encode() {
+ Preconditions.checkState(byteString!=null);
+ Map<GeneratedMessage.GeneratedExtension, PersistentMessages.CompositeModification> map = new HashMap<>();
+ map.put(org.opendaylight.controller.protobuff.messages.shard.CompositeModificationPayload.modification,
+ getModificationInternal());
+ return map;
+ }
+
+ @Override
+ public Payload decode(
+ AppendEntriesMessages.AppendEntries.ReplicatedLogEntry.Payload payload) {
+ PersistentMessages.CompositeModification modification = payload
+ .getExtension(
+ org.opendaylight.controller.protobuff.messages.shard.CompositeModificationPayload.modification);
+
+ // The extension was put in the unknown field.
+ // This is because extensions need to be registered
+ // see org.opendaylight.controller.mdsal.CompositeModificationPayload.registerAllExtensions
+ // also see https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/ExtensionRegistry
+ // If that is not done then on the other end the extension shows up as an unknown field
+ // Need to figure out a better way to do this
+ if(payload.getUnknownFields().hasField(2)){
+ UnknownFieldSet.Field field =
+ payload.getUnknownFields().getField(2);
+
+ return new CompositeModificationByteStringPayload(field.getLengthDelimitedList().get(0));
+ }
+
+ return new CompositeModificationByteStringPayload(modification);
+ }
+
+ public Object getModification(){
+ return getModificationInternal();
+ }
+
+ private PersistentMessages.CompositeModification getModificationInternal(){
+ if(this.modificationReference != null && this.modificationReference.get() != null){
+ return this.modificationReference.get();
+ }
+ try {
+ PersistentMessages.CompositeModification compositeModification = PersistentMessages.CompositeModification.parseFrom(this.byteString);
+ this.modificationReference = new SoftReference<>(compositeModification);
+ return compositeModification;
+ } catch (InvalidProtocolBufferException e) {
+ LOG.error("Unexpected exception occurred when parsing byteString to CompositeModification", e);
+ }
+
+ return null;
+ }
+
+ public int size(){
+ return byteString.size();
+ }
+
+ private void writeObject(java.io.ObjectOutputStream stream)
+ throws IOException {
+ byteString.writeTo(stream);
+ }
+
+ private void readObject(java.io.ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ byteString = ByteString.readFrom(stream);
+ }
+
+ @VisibleForTesting
+ public void clearModificationReference(){
+ if(this.modificationReference != null) {
+ this.modificationReference.clear();
+ }
+ }
+}
\ No newline at end of file
import org.opendaylight.controller.cluster.raft.RaftActor;
import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply;
+import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationByteStringPayload;
import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationPayload;
import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
cohortEntry.getCohort().preCommit().get();
Shard.this.persistData(getSender(), transactionID,
- new CompositeModificationPayload(cohortEntry.getModification().toSerializable()));
+ new CompositeModificationByteStringPayload(cohortEntry.getModification().toSerializable()));
} catch (InterruptedException | ExecutionException e) {
LOG.error(e, "An exception occurred while preCommitting transaction {}",
cohortEntry.getTransactionID());
protected void appendRecoveredLogEntry(final Payload data) {
if (data instanceof CompositeModificationPayload) {
currentLogRecoveryBatch.add(((CompositeModificationPayload) data).getModification());
+ } else if (data instanceof CompositeModificationByteStringPayload) {
+ currentLogRecoveryBatch.add(((CompositeModificationByteStringPayload) data).getModification());
} else {
LOG.error("Unknown state received {} during recovery", data);
}
if (data instanceof CompositeModificationPayload) {
Object modification = ((CompositeModificationPayload) data).getModification();
- if(modification == null) {
- LOG.error(
- "modification is null - this is very unexpected, clientActor = {}, identifier = {}",
- identifier, clientActor != null ? clientActor.path().toString() : null);
- } else if(clientActor == null) {
- // There's no clientActor to which to send a commit reply so we must be applying
- // replicated state from the leader.
- commitWithNewTransaction(MutableCompositeModification.fromSerializable(
- modification, schemaContext));
- } else {
- // This must be the OK to commit after replication consensus.
- finishCommit(clientActor, identifier);
- }
+ applyModificationToState(clientActor, identifier, modification);
+ } else if(data instanceof CompositeModificationByteStringPayload ){
+ Object modification = ((CompositeModificationByteStringPayload) data).getModification();
+
+ applyModificationToState(clientActor, identifier, modification);
+
} else {
LOG.error("Unknown state received {} Class loader = {} CompositeNodeMod.ClassLoader = {}",
data, data.getClass().getClassLoader(),
}
+ private void applyModificationToState(ActorRef clientActor, String identifier, Object modification) {
+ if(modification == null) {
+ LOG.error(
+ "modification is null - this is very unexpected, clientActor = {}, identifier = {}",
+ identifier, clientActor != null ? clientActor.path().toString() : null);
+ } else if(clientActor == null) {
+ // There's no clientActor to which to send a commit reply so we must be applying
+ // replicated state from the leader.
+ commitWithNewTransaction(MutableCompositeModification.fromSerializable(
+ modification, schemaContext));
+ } else {
+ // This must be the OK to commit after replication consensus.
+ finishCommit(clientActor, identifier);
+ }
+ }
+
private void updateJournalStats() {
ReplicatedLogEntry lastLogEntry = getLastLogEntry();
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. 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
+ */
+
+package org.opendaylight.controller.cluster.datastore;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang.SerializationUtils;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.modification.Modification;
+import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification;
+import org.opendaylight.controller.cluster.datastore.modification.WriteModification;
+import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
+import org.opendaylight.controller.cluster.raft.ReplicatedLogImplEntry;
+import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
+import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationByteStringPayload;
+import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class CompositeModificationByteStringPayloadTest {
+
+ private static final SchemaContext SCHEMA_CONTEXT = TestModel.createTestContext();
+
+ @Test
+ public void testSerialization(){
+ WriteModification writeModification =
+ new WriteModification(TestModel.TEST_PATH, ImmutableNodes
+ .containerNode(TestModel.TEST_QNAME),
+ TestModel.createTestContext());
+
+ MutableCompositeModification compositeModification =
+ new MutableCompositeModification();
+
+ compositeModification.addModification(writeModification);
+
+ CompositeModificationByteStringPayload compositeModificationByteStringPayload
+ = new CompositeModificationByteStringPayload(compositeModification.toSerializable());
+
+ byte[] bytes = SerializationUtils.serialize(compositeModificationByteStringPayload);
+
+ Object deserialize = SerializationUtils.deserialize(bytes);
+
+ assertTrue(deserialize instanceof CompositeModificationByteStringPayload);
+
+ }
+
+ @Test
+ public void testAppendEntries(){
+ List<ReplicatedLogEntry> entries = new ArrayList<>();
+
+ CompositeModificationByteStringPayload payload = newByteStringPayload(
+ new WriteModification(TestModel.OUTER_LIST_PATH,
+ ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build(),
+ SCHEMA_CONTEXT));
+
+ payload.clearModificationReference();
+
+ entries.add(new ReplicatedLogImplEntry(0, 1, payload));
+
+
+ assertNotNull(new AppendEntries(10, "foobar", 10, 10, entries, 10).toSerializable());
+ }
+
+
+
+ private CompositeModificationByteStringPayload newByteStringPayload(final Modification... mods) {
+ MutableCompositeModification compMod = new MutableCompositeModification();
+ for(Modification mod: mods) {
+ compMod.addModification(mod);
+ }
+
+ return new CompositeModificationByteStringPayload(compMod.toSerializable());
+ }
+
+}
import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout;
import org.opendaylight.controller.cluster.raft.client.messages.FindLeader;
import org.opendaylight.controller.cluster.raft.client.messages.FindLeaderReply;
+import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationByteStringPayload;
import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationPayload;
import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper;
ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build(),
SCHEMA_CONTEXT))));
- int nListEntries = 11;
+ int nListEntries = 16;
Set<Integer> listEntryKeys = new HashSet<>();
- for(int i = 1; i <= nListEntries; i++) {
+ for(int i = 1; i <= nListEntries-5; i++) {
listEntryKeys.add(Integer.valueOf(i));
YangInstanceIdentifier path = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
.nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i).build();
newPayload(mod)));
}
+ // Add some of the new CompositeModificationByteStringPayload
+ for(int i = 11; i <= nListEntries; i++) {
+ listEntryKeys.add(Integer.valueOf(i));
+ YangInstanceIdentifier path = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+ .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i).build();
+ Modification mod = new MergeModification(path,
+ ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i),
+ SCHEMA_CONTEXT);
+ InMemoryJournal.addEntry(shardID.toString(), i, new ReplicatedLogImplEntry(i, 1,
+ newByteStringPayload(mod)));
+ }
+
+
InMemoryJournal.addEntry(shardID.toString(), nListEntries + 1,
new ApplyLogEntries(nListEntries));
return new CompositeModificationPayload(compMod.toSerializable());
}
+ private CompositeModificationByteStringPayload newByteStringPayload(final Modification... mods) {
+ MutableCompositeModification compMod = new MutableCompositeModification();
+ for(Modification mod: mods) {
+ compMod.addModification(mod);
+ }
+
+ return new CompositeModificationByteStringPayload(compMod.toSerializable());
+ }
+
+
private DOMStoreThreePhaseCommitCohort setupMockWriteTransaction(final String cohortName,
final InMemoryDOMDataStore dataStore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
final MutableCompositeModification modification) {
return new BrokerImpl(router, services);
}
+ @Deprecated
private DataProviderService createLegacyDataService(final DataStore legacyStore, final SchemaService schemaService) {
YangInstanceIdentifier rootPath = YangInstanceIdentifier.builder().toInstance();
DataBrokerImpl dataService = new DataBrokerImpl();
// For debugging purposes, allow dumping of the modification. Coupled with the above
// precondition log, it should allow us to understand what went on.
- LOG.trace("Store Tx: {} modifications: {}", modification);
+ LOG.trace("Store Tx: {} modifications: {} tree: {}", modification, dataTree);
return Futures.immediateFailedFuture(new TransactionCommitFailedException("Data did not pass validation.", e));
} catch (Exception e) {
import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.ERROR_TAG_QNAME;
import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.ERROR_TYPE_QNAME;
import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.NAMESPACE;
-
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
public class RestconfDocumentedExceptionMapper implements ExceptionMapper<RestconfDocumentedException> {
private final static Logger LOG = LoggerFactory.getLogger(RestconfDocumentedExceptionMapper.class);
+ private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
@Context
private HttpHeaders headers;
private Transformer createTransformer() throws TransformerFactoryConfigurationError,
TransformerConfigurationException {
- TransformerFactory tf = TransformerFactory.newInstance();
- Transformer transformer = tf.newTransformer();
+ Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
}
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+
factory.setNamespaceAware(true);
factory.setCoalescing(true);
factory.setIgnoringElementContentWhitespace(true);
static {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ try {
+ factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ factory.setXIncludeAware(false);
+ factory.setExpandEntityReferences(false);
+ } catch (ParserConfigurationException e) {
+ throw new ExceptionInInitializerError(e);
+ }
factory.setNamespaceAware(true);
factory.setCoalescing(true);
factory.setIgnoringElementContentWhitespace(true);
public class XmlToCompositeNodeReader {
private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
+ static {
+ xmlInputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
+ }
private XMLEventReader eventReader;
public Node<?> read(InputStream entityStream) throws XMLStreamException,
private List<InputStream> getYangs() throws FileNotFoundException {
List<String> paths = Arrays.asList("/META-INF/yang/config.yang", "/META-INF/yang/rpc-context.yang",
"/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang", "/META-INF/yang/test-types.yang",
- "/META-INF/yang/ietf-inet-types.yang");
+ "/META-INF/yang/test-groups.yang", "/META-INF/yang/ietf-inet-types.yang");
final Collection<InputStream> yangDependencies = new ArrayList<>();
for (String path : paths) {
final InputStream is = Preconditions
static {
BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
+ try {
+ BUILDER_FACTORY.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ BUILDER_FACTORY.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ BUILDER_FACTORY.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ BUILDER_FACTORY.setXIncludeAware(false);
+ BUILDER_FACTORY.setExpandEntityReferences(false);
+ } catch (ParserConfigurationException e) {
+ throw new ExceptionInInitializerError(e);
+ }
BUILDER_FACTORY.setNamespaceAware(true);
BUILDER_FACTORY.setCoalescing(true);
BUILDER_FACTORY.setIgnoringElementContentWhitespace(true);
"/META-INF/yang/config-test.yang",
"/META-INF/yang/config-test-impl.yang",
"/META-INF/yang/test-types.yang",
+ "/META-INF/yang/test-groups.yang",
"/META-INF/yang/ietf-inet-types.yang");
final Collection<InputStream> yangDependencies = new ArrayList<>();
}
notificationVerifier.assertNotificationCount(2);
- notificationVerifier.assertNotificationContent(0, 0, 0, 8);
- notificationVerifier.assertNotificationContent(1, 4, 3, 8);
+ notificationVerifier.assertNotificationContent(0, 0, 0, 9);
+ notificationVerifier.assertNotificationContent(1, 4, 3, 9);
mockedAggregator.assertSnapshotCount(2);
// Capabilities are stripped for persister
import org.openexi.proc.grammars.GrammarCache;
import org.openexi.sax.EXIReader;
import org.openexi.sax.Transmogrifier;
+import org.openexi.sax.TransmogrifierException;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
public final class NetconfEXICodec {
/**
* of the stream. This is really useful, so let's output it now.
*/
private static final boolean OUTPUT_EXI_COOKIE = true;
+ /**
+ * OpenEXI does not allow us to directly prevent resolution of external entities. In order
+ * to prevent XXE attacks, we reuse a single no-op entity resolver.
+ */
+ private static final EntityResolver ENTITY_RESOLVER = new EntityResolver() {
+ @Override
+ public InputSource resolveEntity(final String publicId, final String systemId) {
+ return new InputSource();
+ }
+ };
+
private final EXIOptions exiOptions;
public NetconfEXICodec(final EXIOptions exiOptions) {
final EXIReader r = new EXIReader();
r.setPreserveLexicalValues(exiOptions.getPreserveLexicalValues());
r.setGrammarCache(getGrammarCache());
+ r.setEntityResolver(ENTITY_RESOLVER);
return r;
}
- Transmogrifier getTransmogrifier() throws EXIOptionsException {
+ Transmogrifier getTransmogrifier() throws EXIOptionsException, TransmogrifierException {
final Transmogrifier transmogrifier = new Transmogrifier();
transmogrifier.setAlignmentType(exiOptions.getAlignmentType());
transmogrifier.setBlockSize(exiOptions.getBlockSize());
transmogrifier.setGrammarCache(getGrammarCache());
transmogrifier.setOutputCookie(OUTPUT_EXI_COOKIE);
transmogrifier.setOutputOptions(HeaderOptionsOutputType.all);
+ transmogrifier.setResolveExternalGeneralEntities(false);
return transmogrifier;
}
}
import io.netty.handler.codec.MessageToByteEncoder;
import java.io.IOException;
import java.io.OutputStream;
-import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
-import javax.xml.transform.sax.SAXTransformerFactory;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.openexi.proc.common.EXIOptionsException;
import org.openexi.sax.Transmogrifier;
+import org.openexi.sax.TransmogrifierException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class NetconfMessageToEXIEncoder extends MessageToByteEncoder<NetconfMessage> {
-
private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageToEXIEncoder.class);
-
- private static final SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
private final NetconfEXICodec codec;
public NetconfMessageToEXIEncoder(final NetconfEXICodec codec) {
}
@Override
- protected void encode(final ChannelHandlerContext ctx, final NetconfMessage msg, final ByteBuf out) throws EXIOptionsException, IOException, TransformerException {
+ protected void encode(final ChannelHandlerContext ctx, final NetconfMessage msg, final ByteBuf out) throws EXIOptionsException, IOException, TransformerException, TransmogrifierException {
LOG.trace("Sent to encode : {}", msg);
try (final OutputStream os = new ByteBufOutputStream(out)) {
final Transmogrifier transmogrifier = codec.getTransmogrifier();
transmogrifier.setOutputStream(os);
- final Transformer transformer = saxTransformerFactory.newTransformer();
- transformer.transform(new DOMSource(msg.getDocument()), new SAXResult(transmogrifier.getSAXTransmogrifier()));
+ ThreadLocalTransformers.getDefaultTransformer().transform(new DOMSource(msg.getDocument()), new SAXResult(transmogrifier.getSAXTransmogrifier()));
}
}
}
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.opendaylight.controller.netconf.api.NetconfMessage;
public class NetconfMessageToXMLEncoder extends MessageToByteEncoder<NetconfMessage> {
private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageToXMLEncoder.class);
- private static final TransformerFactory FACTORY = TransformerFactory.newInstance();
private final Optional<String> clientId;
this(Optional.<String>absent());
}
- public NetconfMessageToXMLEncoder(Optional<String> clientId) {
+ public NetconfMessageToXMLEncoder(final Optional<String> clientId) {
this.clientId = clientId;
}
@Override
@VisibleForTesting
- public void encode(ChannelHandlerContext ctx, NetconfMessage msg, ByteBuf out) throws IOException, TransformerException {
+ public void encode(final ChannelHandlerContext ctx, final NetconfMessage msg, final ByteBuf out) throws IOException, TransformerException {
LOG.trace("Sent to encode : {}", msg);
if (clientId.isPresent()) {
}
try (OutputStream os = new ByteBufOutputStream(out)) {
- Transformer transformer = FACTORY.newTransformer();
- transformer.setOutputProperty(OutputKeys.INDENT, "yes");
- transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
-
// Wrap OutputStreamWriter with BufferedWriter as suggested in javadoc for OutputStreamWriter
StreamResult result = new StreamResult(new BufferedWriter(new OutputStreamWriter(os)));
DOMSource source = new DOMSource(msg.getDocument());
- transformer.transform(source, result);
+ ThreadLocalTransformers.getPrettyTransformer().transform(source, result);
}
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. 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
+ */
+package org.opendaylight.controller.netconf.nettyutil.handler;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+
+/**
+ * Utility class for cached thread-local transformers. This class exists mostly for use by handlers.
+ */
+final class ThreadLocalTransformers {
+ private static final TransformerFactory FACTORY = TransformerFactory.newInstance();
+
+ private static final ThreadLocal<Transformer> DEFAULT_TRANSFORMER = new ThreadLocal<Transformer>() {
+ @Override
+ protected Transformer initialValue() {
+ try {
+ return FACTORY.newTransformer();
+ } catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) {
+ throw new IllegalStateException("Unexpected error while instantiating a Transformer", e);
+ }
+ };
+
+ @Override
+ public void set(final Transformer value) {
+ throw new UnsupportedOperationException();
+ };
+ };
+
+ private static final ThreadLocal<Transformer> PRETTY_TRANSFORMER = new ThreadLocal<Transformer>() {
+ @Override
+ protected Transformer initialValue() {
+ final Transformer ret;
+
+ try {
+ ret = FACTORY.newTransformer();
+ } catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) {
+ throw new IllegalStateException("Unexpected error while instantiating a Transformer", e);
+ }
+
+ ret.setOutputProperty(OutputKeys.INDENT, "yes");
+ ret.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ return ret;
+ };
+
+ @Override
+ public void set(final Transformer value) {
+ throw new UnsupportedOperationException();
+ };
+ };
+
+ private ThreadLocalTransformers() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ /**
+ * Get the transformer with default configuration.
+ *
+ * @return A transformer with default configuration based on the default implementation.
+ */
+ public static Transformer getDefaultTransformer() {
+ return DEFAULT_TRANSFORMER.get();
+ }
+
+ /**
+ * Get the transformer with default configuration, but with automatic indentation
+ * and the XML declaration removed.
+ *
+ * @return A transformer with human-friendly configuration.
+ */
+ public static Transformer getPrettyTransformer() {
+ return PRETTY_TRANSFORMER.get();
+ }
+}
server = dispatcher.createLocalServer(tcpLocalAddress);
try {
final SshProxyServer sshServer = new SshProxyServer(minaTimerExecutor, nettyThreadgroup, nioExecutor);
- sshServer.bind(getSshConfiguration(bindingAddress, tcpLocalAddress));
+ sshServer.bind(getSshConfiguration(bindingAddress, tcpLocalAddress, keyPairProvider));
sshWrappers.add(sshServer);
} catch (final BindException e) {
LOG.warn("Cannot start simulated device on {}, port already in use. Skipping.", address);
return openDevices;
}
- private SshProxyServerConfiguration getSshConfiguration(final InetSocketAddress bindingAddress, final LocalAddress tcpLocalAddress) throws IOException {
+ private SshProxyServerConfiguration getSshConfiguration(final InetSocketAddress bindingAddress, final LocalAddress tcpLocalAddress, final PEMGeneratorHostKeyProvider keyPairProvider) throws IOException {
return new SshProxyServerConfigurationBuilder()
.setBindingAddress(bindingAddress)
.setLocalAddress(tcpLocalAddress)
return true;
}
})
- .setKeyPairProvider(new PEMGeneratorHostKeyProvider(Files.createTempFile("prefix", "suffix").toAbsolutePath().toString()))
+ .setKeyPairProvider(keyPairProvider)
.setIdleTimeout(Integer.MAX_VALUE)
.createSshProxyServerConfiguration();
}
package org.opendaylight.controller.netconf.util.xml;
+import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
public final class XMLNetconfUtil {
+ private static final XPathFactory FACTORY = XPathFactory.newInstance();
+ private static final NamespaceContext NS_CONTEXT = new HardcodedNamespaceResolver("netconf",
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
- private XMLNetconfUtil() {}
+ private XMLNetconfUtil() {
+ throw new UnsupportedOperationException("Utility class");
+ }
- public static XPathExpression compileXPath(String xPath) {
- final XPathFactory xPathfactory = XPathFactory.newInstance();
- final XPath xpath = xPathfactory.newXPath();
- xpath.setNamespaceContext(new HardcodedNamespaceResolver("netconf",
- XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0));
+ public static XPathExpression compileXPath(final String xPath) {
+ final XPath xpath = FACTORY.newXPath();
+ xpath.setNamespaceContext(NS_CONTEXT);
try {
return xpath.compile(xPath);
} catch (final XPathExpressionException e) {
public static final String XMLNS_ATTRIBUTE_KEY = "xmlns";
public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
- private static final DocumentBuilderFactory BUILDERFACTORY;
+ private static final DocumentBuilderFactory BUILDER_FACTORY;
+ private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
+ private static final SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
static {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ try {
+ factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ factory.setXIncludeAware(false);
+ factory.setExpandEntityReferences(false);
+ } catch (ParserConfigurationException e) {
+ throw new ExceptionInInitializerError(e);
+ }
factory.setNamespaceAware(true);
factory.setCoalescing(true);
factory.setIgnoringElementContentWhitespace(true);
factory.setIgnoringComments(true);
- BUILDERFACTORY = factory;
+ BUILDER_FACTORY = factory;
}
- private XmlUtil() {}
+ private XmlUtil() {
+ throw new UnsupportedOperationException("Utility class");
+ }
- public static Element readXmlToElement(String xmlContent) throws SAXException, IOException {
+ public static Element readXmlToElement(final String xmlContent) throws SAXException, IOException {
Document doc = readXmlToDocument(xmlContent);
return doc.getDocumentElement();
}
- public static Element readXmlToElement(InputStream xmlContent) throws SAXException, IOException {
+ public static Element readXmlToElement(final InputStream xmlContent) throws SAXException, IOException {
Document doc = readXmlToDocument(xmlContent);
return doc.getDocumentElement();
}
- public static Document readXmlToDocument(String xmlContent) throws SAXException, IOException {
+ public static Document readXmlToDocument(final String xmlContent) throws SAXException, IOException {
return readXmlToDocument(new ByteArrayInputStream(xmlContent.getBytes(Charsets.UTF_8)));
}
// TODO improve exceptions throwing
// along with XmlElement
- public static Document readXmlToDocument(InputStream xmlContent) throws SAXException, IOException {
+ public static Document readXmlToDocument(final InputStream xmlContent) throws SAXException, IOException {
DocumentBuilder dBuilder;
try {
- dBuilder = BUILDERFACTORY.newDocumentBuilder();
+ dBuilder = BUILDER_FACTORY.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new IllegalStateException("Failed to parse XML document", e);
}
return doc;
}
- public static Element readXmlToElement(File xmlFile) throws SAXException, IOException {
+ public static Element readXmlToElement(final File xmlFile) throws SAXException, IOException {
return readXmlToDocument(new FileInputStream(xmlFile)).getDocumentElement();
}
public static Document newDocument() {
try {
- DocumentBuilder builder = BUILDERFACTORY.newDocumentBuilder();
+ DocumentBuilder builder = BUILDER_FACTORY.newDocumentBuilder();
return builder.newDocument();
} catch (ParserConfigurationException e) {
throw new IllegalStateException("Failed to create document", e);
}
}
- public static Element createElement(final Document document, String qName, Optional<String> namespaceURI) {
+ public static Element createElement(final Document document, final String qName, final Optional<String> namespaceURI) {
if(namespaceURI.isPresent()) {
final Element element = document.createElementNS(namespaceURI.get(), qName);
String name = XMLNS_ATTRIBUTE_KEY;
return document.createElement(qName);
}
- public static Element createTextElement(Document document, String qName, String content, Optional<String> namespaceURI) {
+ public static Element createTextElement(final Document document, final String qName, final String content, final Optional<String> namespaceURI) {
Element typeElement = createElement(document, qName, namespaceURI);
typeElement.appendChild(document.createTextNode(content));
return typeElement;
}
- public static Element createTextElementWithNamespacedContent(Document document, String qName, String prefix,
- String namespace, String contentWithoutPrefix) {
+ public static Element createTextElementWithNamespacedContent(final Document document, final String qName, final String prefix,
+ final String namespace, final String contentWithoutPrefix) {
return createTextElementWithNamespacedContent(document, qName, prefix, namespace, contentWithoutPrefix, Optional.<String>absent());
}
- public static Element createTextElementWithNamespacedContent(Document document, String qName, String prefix,
- String namespace, String contentWithoutPrefix, Optional<String> namespaceURI) {
+ public static Element createTextElementWithNamespacedContent(final Document document, final String qName, final String prefix,
+ final String namespace, final String contentWithoutPrefix, final Optional<String> namespaceURI) {
String content = createPrefixedValue(XmlNetconfConstants.PREFIX, contentWithoutPrefix);
Element element = createTextElement(document, qName, content, namespaceURI);
return element;
}
- public static String createPrefixedValue(String prefix, String value) {
+ public static String createPrefixedValue(final String prefix, final String value) {
return prefix + ":" + value;
}
- public static String toString(Document document) {
+ public static String toString(final Document document) {
return toString(document.getDocumentElement());
}
- public static String toString(Element xml) {
+ public static String toString(final Element xml) {
return toString(xml, false);
}
- public static String toString(XmlElement xmlElement) {
+ public static String toString(final XmlElement xmlElement) {
return toString(xmlElement.getDomElement(), false);
}
- public static String toString(Element xml, boolean addXmlDeclaration) {
+ public static String toString(final Element xml, final boolean addXmlDeclaration) {
try {
- Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, addXmlDeclaration ? "no" : "yes");
}
}
- public static String toString(Document doc, boolean addXmlDeclaration) {
+ public static String toString(final Document doc, final boolean addXmlDeclaration) {
return toString(doc.getDocumentElement(), addXmlDeclaration);
}
- public static Schema loadSchema(InputStream... fromStreams) {
+ public static Schema loadSchema(final InputStream... fromStreams) {
Source[] sources = new Source[fromStreams.length];
int i = 0;
for (InputStream stream : fromStreams) {
sources[i++] = new StreamSource(stream);
}
- final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
- return schemaFactory.newSchema(sources);
+ return SCHEMA_FACTORY.newSchema(sources);
} catch (SAXException e) {
throw new IllegalStateException("Failed to instantiate XML schema", e);
}
}
- public static Object evaluateXPath(XPathExpression expr, Object rootNode, QName returnType) {
+ public static Object evaluateXPath(final XPathExpression expr, final Object rootNode, final QName returnType) {
try {
return expr.evaluate(rootNode, returnType);
} catch (XPathExpressionException e) {
}
}
- public static Document createDocumentCopy(Document original) {
+ public static Document createDocumentCopy(final Document original) {
final Document copiedDocument = newDocument();
final Node copiedRoot = copiedDocument.importNode(original.getDocumentElement(), true);
copiedDocument.appendChild(copiedRoot);
}
+ @Test(expected = SAXParseException.class)
+ public void testXXEFlaw() throws Exception {
+ XmlUtil.readXmlToDocument("<!DOCTYPE foo [ \n" +
+ "<!ELEMENT foo ANY >\n" +
+ "<!ENTITY xxe SYSTEM \"file:///etc/passwd\" >]>\n" +
+ "<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ " <capabilities>\n" +
+ " <capability>urn:ietf:params:netconf:base:1.0 &xxe;</capability>\n" +
+ " </capabilities>\n" +
+ " </hello>]]>]]>");
+ }
+
@Test
public void testXPath() throws Exception {
final XPathExpression correctXPath = XMLNetconfUtil.compileXPath("/top/innerText");