/*
|
* Copyright 2011-17 Fraunhofer ISE, energy & meteo Systems GmbH and other contributors
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*
|
*/
|
package org.openmuc.openiec61850;
|
|
import java.util.ArrayList;
|
import java.util.Collection;
|
import java.util.HashMap;
|
import java.util.Iterator;
|
import java.util.LinkedHashMap;
|
import java.util.LinkedList;
|
import java.util.List;
|
import java.util.Map;
|
|
import org.openmuc.openiec61850.internal.mms.asn1.AlternateAccessSelection;
|
import org.openmuc.openiec61850.internal.mms.asn1.ObjectName;
|
import org.openmuc.openiec61850.internal.mms.asn1.ObjectName.DomainSpecific;
|
import org.openmuc.openiec61850.internal.mms.asn1.VariableDefs;
|
|
public final class ServerModel extends ModelNode {
|
|
private final Map<String, DataSet> dataSets = new LinkedHashMap<>();
|
|
private final Map<String, Urcb> urcbs = new HashMap<>();
|
private final Map<String, Brcb> brcbs = new HashMap<>();
|
|
public ServerModel(List<LogicalDevice> logicalDevices, Collection<DataSet> dataSets) {
|
children = new LinkedHashMap<>();
|
objectReference = null;
|
for (LogicalDevice logicalDevice : logicalDevices) {
|
children.put(logicalDevice.getReference().getName(), logicalDevice);
|
logicalDevice.setParent(this);
|
}
|
|
if (dataSets != null) {
|
addDataSets(dataSets);
|
}
|
|
for (LogicalDevice ld : logicalDevices) {
|
for (ModelNode ln : ld.getChildren()) {
|
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
|
urcbs.put(urcb.getReference().toString(), urcb);
|
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
|
}
|
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
|
brcbs.put(brcb.getReference().toString(), brcb);
|
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
|
}
|
}
|
}
|
|
}
|
|
@Override
|
public ServerModel copy() {
|
List<LogicalDevice> childCopies = new ArrayList<>(children.size());
|
for (ModelNode childNode : children.values()) {
|
childCopies.add((LogicalDevice) childNode.copy());
|
}
|
|
List<DataSet> dataSetCopies = new ArrayList<>(dataSets.size());
|
for (DataSet dataSet : dataSets.values()) {
|
dataSetCopies.add(dataSet);
|
}
|
|
return new ServerModel(childCopies, dataSetCopies);
|
}
|
|
/**
|
* Get the data set with the given reference. Return null if none is found.
|
*
|
* @param reference
|
* the reference of the requested data set.
|
* @return the data set with the given reference.
|
*/
|
public DataSet getDataSet(String reference) {
|
return dataSets.get(reference);
|
}
|
|
void addDataSet(DataSet dataSet) {
|
dataSets.put(dataSet.getReferenceStr().replace('$', '.'), dataSet);
|
for (ModelNode ld : children.values()) {
|
for (ModelNode ln : ld.getChildren()) {
|
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
|
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
|
}
|
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
|
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
|
}
|
}
|
}
|
}
|
|
void addDataSets(Collection<DataSet> dataSets) {
|
for (DataSet dataSet : dataSets) {
|
addDataSet(dataSet);
|
}
|
for (ModelNode ld : children.values()) {
|
for (ModelNode ln : ld.getChildren()) {
|
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
|
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
|
}
|
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
|
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
|
}
|
}
|
}
|
}
|
|
List<String> getDataSetNames(String ldName) {
|
// TODO make thread save
|
List<String> dataSetNames = new LinkedList<>();
|
for (String dataSetRef : dataSets.keySet()) {
|
if (dataSetRef.startsWith(ldName)) {
|
dataSetNames.add(dataSetRef.substring(dataSetRef.indexOf('/') + 1).replace('.', '$'));
|
}
|
}
|
return dataSetNames;
|
}
|
|
/**
|
* Get a collection of all data sets that exist in this model.
|
*
|
* @return a collection of all data sets
|
*/
|
public Collection<DataSet> getDataSets() {
|
return dataSets.values();
|
}
|
|
/**
|
*
|
* @param dataSetReference
|
* @return returns the DataSet that was removed, null if no DataSet with the given reference was found or the data
|
* set is not deletable.
|
*/
|
DataSet removeDataSet(String dataSetReference) {
|
DataSet dataSet = dataSets.get(dataSetReference);
|
if (dataSet == null || !dataSet.isDeletable()) {
|
return null;
|
}
|
DataSet removedDataSet = dataSets.remove(dataSetReference);
|
for (ModelNode ld : children.values()) {
|
for (ModelNode ln : ld.getChildren()) {
|
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
|
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
|
}
|
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
|
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
|
}
|
}
|
}
|
return removedDataSet;
|
}
|
|
void addUrcb(Urcb urcb) {
|
urcbs.put(urcb.getReference().getName(), urcb);
|
}
|
|
/**
|
* Get the unbuffered report control block (URCB) with the given reference.
|
*
|
* @param reference
|
* the reference of the requested URCB.
|
* @return the reference to the requested URCB or null if none with the given reference is found.
|
*/
|
public Urcb getUrcb(String reference) {
|
return urcbs.get(reference);
|
}
|
|
/**
|
* Get a collection of all unbuffered report control blocks (URCB) that exist in this model.
|
*
|
* @return a collection of all unbuffered report control blocks (URCB)
|
*/
|
public Collection<Urcb> getUrcbs() {
|
return urcbs.values();
|
}
|
|
/**
|
* Get the buffered report control block (BRCB) with the given reference.
|
*
|
* @param reference
|
* the reference of the requested BRCB.
|
* @return the reference to the requested BRCB or null if none with the given reference is found.
|
*/
|
public Brcb getBrcb(String reference) {
|
return brcbs.get(reference);
|
}
|
|
/**
|
* Get a collection of all buffered report control blocks (BRCB) that exist in this model.
|
*
|
* @return a collection of all buffered report control blocks (BRCB)
|
*/
|
public Collection<Brcb> getBrcbs() {
|
return brcbs.values();
|
}
|
|
public String getBaseDevName() {
|
String dev_n = "ZJDY";
|
for (ModelNode logicalDevice : children.values()) {
|
String nm = logicalDevice.toString();
|
if(true == nm.contains("BTSE")) {
|
dev_n = nm.substring(0, nm.indexOf("BTSE"));
|
break;
|
}
|
}
|
|
return dev_n;
|
}
|
|
@Override
|
public String toString() {
|
StringBuilder sb = new StringBuilder();
|
for (ModelNode logicalDevice : children.values()) {
|
//if(logicalDevice.toString().contains("BTS")) {
|
sb.append(logicalDevice.toString());
|
//}
|
}
|
sb.append("\n\n\n---------------------\nURCBs:");
|
for (Urcb urcb : getUrcbs()) {
|
sb.append("\n\n").append(urcb);
|
}
|
|
sb.append("\n\n\n---------------------\nBRCBs:");
|
for (Brcb brcb : getBrcbs()) {
|
sb.append("\n\n").append(brcb);
|
}
|
|
sb.append("\n\n\n---------------------\nData sets:");
|
for (DataSet dataSet : getDataSets()) {
|
sb.append("\n\n").append(dataSet);
|
}
|
|
return sb.toString();
|
}
|
|
/**
|
* Searches and returns the model node with the given object reference and FC. If searching for Logical Devices and
|
* Logical Nodes the given fc parameter may be <code>null</code>.
|
*
|
* @param objectReference
|
* the object reference of the node that is being searched for. It has a syntax like "ldname/ln.do....".
|
* @param fc
|
* the functional constraint of the requested model node. May be null for Logical Device and Logical Node
|
* references.
|
* @return the model node if it was found or null otherwise
|
*/
|
public ModelNode findModelNode(ObjectReference objectReference, Fc fc) {
|
|
ModelNode currentNode = this;
|
Iterator<String> searchedNodeReferenceIterator = objectReference.iterator();
|
|
while (searchedNodeReferenceIterator.hasNext()) {
|
currentNode = currentNode.getChild(searchedNodeReferenceIterator.next(), fc);
|
if (currentNode == null) {
|
return null;
|
}
|
}
|
return currentNode;
|
}
|
|
/**
|
* Searches and returns the model node with the given object reference and FC. If searching for Logical Devices and
|
* Logical Nodes the given fc parameter may be <code>null</code>.
|
*
|
* @param objectReference
|
* the object reference of the node that is being searched for. It has a syntax like "ldname/ln.do....".
|
* @param fc
|
* the functional constraint of the requested model node. May be null for Logical Device and Logical Node
|
* references.
|
* @return the model node if it was found or null otherwise
|
*/
|
public ModelNode findModelNode(String objectReference, Fc fc) {
|
return findModelNode(new ObjectReference(objectReference), fc);
|
}
|
|
/**
|
* Returns the subModelNode that is referenced by the given VariableDef. Return null in case the referenced
|
* ModelNode is not found.
|
*
|
* @param variableDef
|
* @return the subModelNode that is referenced by the given VariableDef
|
* @throws ServiceError
|
*/
|
FcModelNode getNodeFromVariableDef(VariableDefs.SEQUENCE variableDef) throws ServiceError {
|
|
ObjectName objectName = variableDef.getVariableSpecification().getName();
|
|
if (objectName == null) {
|
throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
|
"name in objectName is not selected");
|
}
|
|
DomainSpecific domainSpecific = objectName.getDomainSpecific();
|
|
if (domainSpecific == null) {
|
throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
|
"domain_specific in name is not selected");
|
}
|
|
ModelNode modelNode = getChild(domainSpecific.getDomainID().toString());
|
|
if (modelNode == null) {
|
return null;
|
}
|
|
String mmsItemId = domainSpecific.getItemID().toString();
|
int index1 = mmsItemId.indexOf('$');
|
|
if (index1 == -1) {
|
throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
|
"invalid mms item id: " + domainSpecific.getItemID());
|
}
|
|
LogicalNode ln = (LogicalNode) modelNode.getChild(mmsItemId.substring(0, index1));
|
|
if (ln == null) {
|
return null;
|
}
|
|
int index2 = mmsItemId.indexOf('$', index1 + 1);
|
|
if (index2 == -1) {
|
throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, "invalid mms item id");
|
}
|
|
Fc fc = Fc.fromString(mmsItemId.substring(index1 + 1, index2));
|
|
if (fc == null) {
|
throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
|
"unknown functional constraint: " + mmsItemId.substring(index1 + 1, index2));
|
}
|
|
index1 = index2;
|
|
index2 = mmsItemId.indexOf('$', index1 + 1);
|
|
if (index2 == -1) {
|
if (fc == Fc.RP) {
|
return ln.getUrcb(mmsItemId.substring(index1 + 1));
|
}
|
if (fc == Fc.BR) {
|
return ln.getBrcb(mmsItemId.substring(index1 + 1));
|
}
|
return (FcModelNode) ln.getChild(mmsItemId.substring(index1 + 1), fc);
|
}
|
|
if (fc == Fc.RP) {
|
modelNode = ln.getUrcb(mmsItemId.substring(index1 + 1, index2));
|
}
|
else if (fc == Fc.BR) {
|
modelNode = ln.getBrcb(mmsItemId.substring(index1 + 1, index2));
|
}
|
else {
|
modelNode = ln.getChild(mmsItemId.substring(index1 + 1, index2), fc);
|
}
|
|
index1 = index2;
|
index2 = mmsItemId.indexOf('$', index1 + 1);
|
while (index2 != -1) {
|
modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1, index2));
|
index1 = index2;
|
index2 = mmsItemId.indexOf('$', index1 + 1);
|
}
|
|
modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1));
|
|
if (variableDef.getAlternateAccess() == null) {
|
// no array is in this node path
|
return (FcModelNode) modelNode;
|
}
|
|
AlternateAccessSelection altAccIt = variableDef.getAlternateAccess().getCHOICE().get(0).getUnnamed();
|
|
if (altAccIt.getSelectAlternateAccess() != null) {
|
// path to node below an array element
|
modelNode = ((Array) modelNode)
|
.getChild(altAccIt.getSelectAlternateAccess().getAccessSelection().getIndex().intValue());
|
|
String mmsSubArrayItemId = altAccIt.getSelectAlternateAccess()
|
.getAlternateAccess()
|
.getCHOICE()
|
.get(0)
|
.getUnnamed()
|
.getSelectAccess()
|
.getComponent()
|
.getBasic()
|
.toString();
|
|
index1 = -1;
|
index2 = mmsSubArrayItemId.indexOf('$');
|
while (index2 != -1) {
|
modelNode = modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1, index2));
|
index1 = index2;
|
index2 = mmsItemId.indexOf('$', index1 + 1);
|
}
|
|
return (FcModelNode) modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1));
|
}
|
else {
|
// path to an array element
|
return (FcModelNode) ((Array) modelNode).getChild(altAccIt.getSelectAccess().getIndex().intValue());
|
}
|
|
}
|
}
|