/**
* JBoss, Home of Professional Open Source
* Copyright Red Hat, Inc., and individual 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.jboss.aerogear.simplepush.subsystem;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
import static org.jboss.as.controller.parsing.ParseUtils.unexpectedAttribute;
import static org.jboss.as.controller.parsing.ParseUtils.unexpectedElement;
import java.util.List;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import org.jboss.as.controller.parsing.ParseUtils;
import org.jboss.as.controller.persistence.SubsystemMarshallingContext;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;
import org.jboss.staxmapper.XMLElementReader;
import org.jboss.staxmapper.XMLElementWriter;
import org.jboss.staxmapper.XMLExtendedStreamReader;
import org.jboss.staxmapper.XMLExtendedStreamWriter;
public class SimplePushSubsystemParser implements XMLStreamConstants, XMLElementReader<List<ModelNode>>, XMLElementWriter<SubsystemMarshallingContext> {
@Override
public void readElement(final XMLExtendedStreamReader reader, final List<ModelNode> list) throws XMLStreamException {
final ModelNode address = new ModelNode();
address.add(SUBSYSTEM, SimplePushExtension.SUBSYSTEM_NAME);
address.protect();
final ModelNode subsystem = new ModelNode();
subsystem.get(OP).set(ADD);
subsystem.get(OP_ADDR).set(address);
list.add(subsystem);
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
if (reader.isStartElement()) {
readServerType(reader, list, address);
}
}
}
private void readServerType(final XMLExtendedStreamReader reader, final List<ModelNode> modelNodes, final ModelNode parentAddress) throws XMLStreamException {
final ModelNode node = new ModelNode();
node.get(OP).set(ADD);
modelNodes.add(node);
readServerAttributes(reader, node, parentAddress);
readServerElements(reader, node, modelNodes);
ParseUtils.requireNoContent(reader);
}
private void readServerAttributes(final XMLExtendedStreamReader reader, final ModelNode node, final ModelNode parentAddress) throws XMLStreamException {
String serverName = "simplepush";
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
final String name = reader.getAttributeLocalName(i);
final String value = reader.getAttributeValue(i);
switch (ServerDefinition.Element.of(name)) {
case SERVER_NAME:
serverName = value;
break;
case SOCKET_BINDING:
ServerDefinition.SOCKET_BINDING_ATTR.parseAndSetParameter(value, node, reader);
break;
case PASSWORD:
ServerDefinition.PASSWORD_ATTR.parseAndSetParameter(value, node, reader);
break;
case REAPER_TIMEOUT:
ServerDefinition.REAPER_TIMEOUT_ATTR.parseAndSetParameter(value, node, reader);
break;
case ENDPOINT_PREFIX:
ServerDefinition.ENDPOINT_PREFIX_ATTR.parseAndSetParameter(value, node, reader);
break;
case ENDPOINT_TLS:
ServerDefinition.ENDPOINT_TLS_ATTR.parseAndSetParameter(value, node, reader);
break;
case ENDPOINT_ACK_INTERVAL:
ServerDefinition.ENDPOINT_ACK_INTERVAL_ATTR.parseAndSetParameter(value, node, reader);
break;
case ENDPOINT_SOCKET_BINDING:
ServerDefinition.ENDPOINT_SOCKET_BINDING_ATTR.parseAndSetParameter(value, node, reader);
break;
case NOTIFIER_MAX_THREADS:
ServerDefinition.NOTIFIER_MAX_THREADS.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_PREFIX:
ServerDefinition.SOCKJS_PREFIX_ATTR.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_COOKIES_NEEDED:
ServerDefinition.SOCKJS_COOKIES_NEEDED_ATTR.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_URL:
ServerDefinition.SOCKJS_URL_ATTR.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_SESSION_TIMEOUT:
ServerDefinition.SOCKJS_SESSION_TIMEOUT_ATTR.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_HEARTBEAT_INTERVAL:
ServerDefinition.SOCKJS_HEARTBEAT_INTERVAL_ATTR.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_MAX_STREAMING_BYTES_SIZE:
ServerDefinition.SOCKJS_MAX_STREAMING_BYTES_SIZE_ATTR.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_TLS:
ServerDefinition.SOCKJS_TLS_ATTR.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_KEYSTORE:
ServerDefinition.SOCKJS_KEYSTORE_ATTR.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_KEYSTORE_PASSWORD:
ServerDefinition.SOCKJS_KEYSTORE_PASSWORD_ATTR.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_ENABLE_WEBSOCKET:
ServerDefinition.SOCKJS_ENABLE_WEBSOCKET_ATTR.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_WEBSOCKET_HEARTBEAT_INTERVAL:
ServerDefinition.SOCKJS_WEBSOCKET_HEARTBEAT_INTERVAL_ATTR.parseAndSetParameter(value, node, reader);
break;
case SOCKJS_WEBSOCKET_PROTOCOLS:
ServerDefinition.SOCKJS_WEBSOCKET_PROTOCOLS.parseAndSetParameter(value, node, reader);
break;
default:
throw unexpectedAttribute(reader, i);
}
node.get(OP_ADDR).set(parentAddress).add(ServerDefinition.SERVER, serverName);
}
}
private void readServerElements(final XMLExtendedStreamReader reader, final ModelNode node, final List<ModelNode> modelNodes) throws XMLStreamException {
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
final String tagName = reader.getLocalName();
if (tagName.equals(DataStoreDefinition.DATASTORE)) {
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
switch (DataStoreDefinition.Element.of(reader.getLocalName())) {
case JPA: {
final ModelNode jpa = readJpaElement(reader, node.get(OP_ADDR));
modelNodes.add(jpa);
break;
}
case REDIS: {
final ModelNode redis = readRedisElement(reader, node.get(OP_ADDR));
modelNodes.add(redis);
break;
}
case COUCHDB: {
final ModelNode couchdb = readCouchDBElement(reader, node.get(OP_ADDR));
modelNodes.add(couchdb);
break;
}
case IN_MEMORY: {
final ModelNode inmem = readInMemoryDBElement(reader, node.get(OP_ADDR));
modelNodes.add(inmem);
break;
}
default: {
throw unexpectedElement(reader);
}
}
}
}
}
}
private ModelNode readJpaElement(XMLExtendedStreamReader reader, ModelNode parentAddress) throws XMLStreamException {
final ModelNode node = new ModelNode();
node.get(OP).set(ADD);
node.get(OP_ADDR).set(parentAddress).add(DataStoreDefinition.DATASTORE, DataStoreDefinition.Element.JPA.localName());
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
final String name = reader.getAttributeLocalName(i);
final String value = reader.getAttributeValue(i);
switch (DataStoreDefinition.Element.of(name)) {
case DATASOURCE:
DataStoreDefinition.DATASOURCE_ATTR.parseAndSetParameter(value, node, reader);
break;
case PERSISTENCE_UNIT:
DataStoreDefinition.PERSISTENCE_UNIT_ATTR.parseAndSetParameter(value, node, reader);
break;
default:
throw unexpectedAttribute(reader, i);
}
}
return node;
}
private ModelNode readRedisElement(XMLExtendedStreamReader reader, ModelNode parentAddress) throws XMLStreamException {
final ModelNode node = new ModelNode();
node.get(OP).set(ADD);
node.get(OP_ADDR).set(parentAddress).add(DataStoreDefinition.DATASTORE, DataStoreDefinition.Element.REDIS.localName());
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
final String name = reader.getAttributeLocalName(i);
final String value = reader.getAttributeValue(i);
switch (DataStoreDefinition.Element.of(name)) {
case HOST:
DataStoreDefinition.HOST_ATTR.parseAndSetParameter(value, node, reader);
break;
case PORT:
DataStoreDefinition.PORT_ATTR.parseAndSetParameter(value, node, reader);
break;
default:
throw unexpectedAttribute(reader, i);
}
}
return node;
}
private ModelNode readCouchDBElement(XMLExtendedStreamReader reader, ModelNode parentAddress) throws XMLStreamException {
final ModelNode node = new ModelNode();
node.get(OP).set(ADD);
node.get(OP_ADDR).set(parentAddress).add(DataStoreDefinition.DATASTORE, DataStoreDefinition.Element.COUCHDB.localName());
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
final String name = reader.getAttributeLocalName(i);
final String value = reader.getAttributeValue(i);
switch (DataStoreDefinition.Element.of(name)) {
case URL:
DataStoreDefinition.URL_ATTR.parseAndSetParameter(value, node, reader);
break;
case DB_NAME:
DataStoreDefinition.DB_NAME_ATTR.parseAndSetParameter(value, node, reader);
break;
default:
throw unexpectedAttribute(reader, i);
}
}
return node;
}
private ModelNode readInMemoryDBElement(XMLExtendedStreamReader reader, ModelNode parentAddress) throws XMLStreamException {
final ModelNode node = new ModelNode();
node.get(OP).set(ADD);
node.get(OP_ADDR).set(parentAddress).add(DataStoreDefinition.DATASTORE, DataStoreDefinition.Element.IN_MEMORY.localName());
return node;
}
/**
* {@inheritDoc}
*/
@Override
public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
context.startSubsystemElement(SimplePushExtension.NAMESPACE, false);
final ModelNode node = context.getModelNode();
final ModelNode server = node.get(ServerDefinition.SERVER);
for (Property property : server.asPropertyList()) {
writer.writeStartElement(ServerDefinition.SERVER);
final ModelNode entry = property.getValue();
ServerDefinition.SOCKET_BINDING_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.PASSWORD_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.REAPER_TIMEOUT_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.ENDPOINT_TLS_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.ENDPOINT_PREFIX_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.ENDPOINT_ACK_INTERVAL_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.ENDPOINT_SOCKET_BINDING_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.NOTIFIER_MAX_THREADS.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_PREFIX_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_COOKIES_NEEDED_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_URL_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_SESSION_TIMEOUT_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_HEARTBEAT_INTERVAL_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_MAX_STREAMING_BYTES_SIZE_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_TLS_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_KEYSTORE_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_KEYSTORE_PASSWORD_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_ENABLE_WEBSOCKET_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_WEBSOCKET_HEARTBEAT_INTERVAL_ATTR.marshallAsAttribute(entry, true, writer);
ServerDefinition.SOCKJS_WEBSOCKET_PROTOCOLS.marshallAsAttribute(entry, true, writer);
final ModelNode datastore = entry.get(DataStoreDefinition.DATASTORE);
if (datastore.isDefined()) {
writer.writeStartElement(DataStoreDefinition.DATASTORE);
switch (DataStoreDefinition.Element.of(datastore.keys().iterator().next())) {
case JPA:
writer.writeStartElement(DataStoreDefinition.Element.JPA.localName());
final ModelNode jpa = datastore.get(DataStoreDefinition.Element.JPA.localName());
DataStoreDefinition.DATASOURCE_ATTR.marshallAsAttribute(jpa, true, writer);
DataStoreDefinition.PERSISTENCE_UNIT_ATTR.marshallAsAttribute(jpa, true, writer);
writer.writeEndElement();
break;
case REDIS:
writer.writeStartElement(DataStoreDefinition.Element.REDIS.localName());
final ModelNode redis = datastore.get(DataStoreDefinition.Element.REDIS.localName());
DataStoreDefinition.HOST_ATTR.marshallAsAttribute(redis, true, writer);
DataStoreDefinition.PORT_ATTR.marshallAsAttribute(redis, true, writer);
writer.writeEndElement();
break;
case COUCHDB:
writer.writeStartElement(DataStoreDefinition.Element.COUCHDB.localName());
final ModelNode couchdb = datastore.get(DataStoreDefinition.Element.COUCHDB.localName());
DataStoreDefinition.URL_ATTR.marshallAsAttribute(couchdb, true, writer);
DataStoreDefinition.DB_NAME_ATTR.marshallAsAttribute(couchdb, true, writer);
writer.writeEndElement();
break;
case IN_MEMORY:
writer.writeStartElement(DataStoreDefinition.Element.IN_MEMORY.localName());
writer.writeEndElement();
break;
default:
throw new IllegalStateException("Non supported datastore type");
}
writer.writeEndElement();
}
writer.writeEndElement();
}
writer.writeEndElement();
}
}