diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java index 3b46ded638f72120733d9865bc58a37c82409512..df2856c64f84834ee1737d93616cfe63298546d0 100644 --- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java +++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java @@ -37,12 +37,14 @@ import org.projectfloodlight.openflow.types.OFPort; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.ListenableFuture; - +import net.floodlightcontroller.core.web.serializers.IOFSwitchSerializer; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; /** * An openflow switch connecting to the controller. This interface offers * methods for interacting with switches using OpenFlow, and retrieving * information about the switches. */ +@JsonSerialize(using=IOFSwitchSerializer.class) public interface IOFSwitch extends IOFMessageWriter { // Attribute keys // These match our YANG schema, make sure they are in sync diff --git a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java index d8564f5703ec17b30cf53642e3225dd7f549e9ca..f749345acf654c723541e520d55c8367bbeba61a 100644 --- a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.ArrayList; import java.util.Collection; import java.util.Set; @@ -29,7 +30,7 @@ import net.floodlightcontroller.core.HARole; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.internal.IOFSwitchService; import net.floodlightcontroller.util.FilterIterator; - +import net.floodlightcontroller.core.web.serializers.IOFSwitchSerializer; import org.projectfloodlight.openflow.protocol.OFCapabilities; import org.projectfloodlight.openflow.protocol.OFPortDesc; import org.projectfloodlight.openflow.types.DatapathId; @@ -38,166 +39,52 @@ import org.restlet.data.Form; import org.restlet.data.Status; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; - +import com.fasterxml.jackson.databind.annotation.JsonSerialize; /** * Get a list of switches connected to the controller * @author readams */ public class ControllerSwitchesResource extends ServerResource { - /** - * A wrapper class around IOFSwitch that defines the REST serialization - * fields. Could have written a Jackson serializer but this is easier. - */ - public static class SwitchJsonSerializerWrapper { - private final IOFSwitch sw; - - public SwitchJsonSerializerWrapper(IOFSwitch sw) { - this.sw = sw; - } - - public Set<OFActionType> getActions() { - return sw.getActions(); - } - - public Map<Object, Object> getAttributes() { - return sw.getAttributes(); - } - - public Map<String,String> getDescription() { - Map<String,String> rv = new HashMap<String, String>(); - if (sw.getSwitchDescription() == null) { - rv.put("manufacturer", ""); - rv.put("hardware", ""); - rv.put("software", ""); - rv.put("serialNum", ""); - rv.put("datapath", ""); - } else { - rv.put("manufacturer", - sw.getSwitchDescription().getManufacturerDescription()); - rv.put("hardware", - sw.getSwitchDescription().getHardwareDescription()); - rv.put("software", - sw.getSwitchDescription().getSoftwareDescription()); - rv.put("serialNum", - sw.getSwitchDescription().getSerialNumber()); - rv.put("datapath", - sw.getSwitchDescription().getDatapathDescription()); - } - return rv; - } - - public long getBuffers() { - return sw.getBuffers(); - } - - public Set<OFCapabilities> getCapabilities() { - return sw.getCapabilities(); - } - - public long getConnectedSince() { - if (sw.getConnectedSince() == null) - return 0; - return sw.getConnectedSince().getTime(); - } - - public String getDpid() { - return sw.getId().toString(); - } - - public String getHarole() { - if (sw.getControllerRole() == null) - return "null"; - return HARole.ofOFRole(sw.getControllerRole()).toString(); - } - - public String getInetAddress() { - SocketAddress addr = sw.getInetAddress(); - if (addr == null) - return null; - return addr.toString(); - } - - public Collection<OFPortDesc> getPorts() { - return sw.getPorts(); - } - } - - /** - * Wraps an iterator of IOFSwitch into an iterator of - * SwitchJsonSerializerWrapper - * @author gregor - */ - private static class SwitchJsonSerializerWrapperIterator - implements Iterator<SwitchJsonSerializerWrapper> { - private final Iterator<IOFSwitch> iter; - - public SwitchJsonSerializerWrapperIterator(Iterator<IOFSwitch> iter) { - this.iter = iter; - } - - @Override - public boolean hasNext() { - return this.iter.hasNext(); - } - - @Override - public SwitchJsonSerializerWrapper next() { - return new SwitchJsonSerializerWrapper(iter.next()); - } - - @Override - public void remove() { - this.iter.remove(); - } - } - + public static final String DPID_ERROR = "Invalid Switch DPID: must be a 64-bit quantity, expressed in " + "hex as AA:BB:CC:DD:EE:FF:00:11"; @Get("json") - public Iterator<SwitchJsonSerializerWrapper> retrieve() { - IOFSwitchService switchService = - (IOFSwitchService) getContext().getAttributes(). - get(IOFSwitchService.class.getCanonicalName()); - + public Collection<IOFSwitch> retrieve(){ + IOFSwitchService switchService = + (IOFSwitchService) getContext().getAttributes(). + get(IOFSwitchService.class.getCanonicalName()); DatapathId switchDPID = null; - + ArrayList<IOFSwitch> result = new ArrayList<IOFSwitch>(); Form form = getQuery(); String dpid = form.getFirstValue("dpid", true); - if (dpid != null) { - try { + if( dpid != null){ + try{ switchDPID = DatapathId.of(dpid); - } catch (Exception e) { - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, DPID_ERROR); + }catch(Exception e){ + setStatus(Status.CLIENT_ERROR_BAD_REQUEST,DPID_ERROR); return null; } } - if (switchDPID != null) { - IOFSwitch sw = - switchService.getSwitch(switchDPID); - if (sw != null) { - SwitchJsonSerializerWrapper wrappedSw = - new SwitchJsonSerializerWrapper(sw); - return Collections.singleton(wrappedSw).iterator(); + if (switchDPID != null){ + IOFSwitch sw = switchService.getSwitch(switchDPID); + if ( sw != null){ + result.add(sw); } - return Collections.<SwitchJsonSerializerWrapper>emptySet().iterator(); + return result; + } + final String dpidStartsWith = + form.getFirstValue("dpid__startswith",true); + if(dpidStartsWith != null){ + for(IOFSwitch sw: switchService.getAllSwitchMap().values()){ + if( sw.getId().toString().startsWith(dpidStartsWith)) + result.add(sw); + } + return result; } - final String dpidStartsWith = - form.getFirstValue("dpid__startswith", true); + return switchService.getAllSwitchMap().values(); - Iterator<IOFSwitch> iofSwitchIter = - switchService.getAllSwitchMap().values().iterator(); - Iterator<SwitchJsonSerializerWrapper> switer = - new SwitchJsonSerializerWrapperIterator(iofSwitchIter); - if (dpidStartsWith != null) { - return new FilterIterator<SwitchJsonSerializerWrapper>(switer) { - @Override - protected boolean matches(SwitchJsonSerializerWrapper value) { - return value.getDpid().startsWith(dpidStartsWith); - } - }; - } - return switer; + } } diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/IOFSwitchSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/IOFSwitchSerializer.java new file mode 100644 index 0000000000000000000000000000000000000000..667ff543a7f35db0dad179c246d230973c2b3cdc --- /dev/null +++ b/src/main/java/net/floodlightcontroller/core/web/serializers/IOFSwitchSerializer.java @@ -0,0 +1,198 @@ +/** +* Copyright 2011,2012 Big Switch Networks, Inc. +* Originally created by David Erickson, Stanford University +* +* 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 net.floodlightcontroller.core.web.serializers; + +import java.io.IOException; +import java.util.Set; +import java.util.Map; +import java.util.Collection; +import java.util.EnumSet; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import org.projectfloodlight.openflow.util.HexString; +import org.projectfloodlight.openflow.types.DatapathId; +import org.projectfloodlight.openflow.protocol.OFCapabilities; +import org.projectfloodlight.openflow.protocol.OFPortDesc; +import org.projectfloodlight.openflow.protocol.OFPortConfig; +import org.projectfloodlight.openflow.protocol.OFPortFeatures; +import org.projectfloodlight.openflow.protocol.OFPortState; +import org.projectfloodlight.openflow.protocol.OFActionType; +import org.projectfloodlight.openflow.protocol.OFControllerRole; +import org.projectfloodlight.openflow.protocol.OFFlowWildcards; +import org.projectfloodlight.openflow.protocol.OFVersion; +import net.floodlightcontroller.core.HARole; +import net.floodlightcontroller.core.IOFSwitch; +import net.floodlightcontroller.core.SwitchDescription; +/** + * Serialize a IOFSwitch for more readable information + */ +public class IOFSwitchSerializer extends JsonSerializer<IOFSwitch> { + + @Override + public void serialize(IOFSwitch sw, JsonGenerator jGen, + SerializerProvider serializer) + throws IOException, JsonProcessingException { + jGen.writeStartObject(); + jGen.writeStringField("dpid",sw.getId().toString()); + serializeCapabilities(sw.getCapabilities(),jGen); + serializeDescription(sw.getSwitchDescription(),jGen); + serializeHarole(sw.getControllerRole(),jGen); + serializeActions(sw.getActions(),jGen); + serializeAttributes(sw.getAttributes(),jGen); + serializePorts(sw.getPorts(),jGen); + jGen.writeNumberField("buffers",sw.getBuffers()); + jGen.writeStringField("inetAddress",sw.getInetAddress().toString()); + jGen.writeNumberField("tables",sw.getTables()); + jGen.writeNumberField("connectedSince",sw.getConnectedSince().getTime()); + jGen.writeEndObject(); + } + + public void serializeActions(Set<OFActionType> actions, JsonGenerator jGen) + throws IOException, JsonProcessingException { + if ( null == actions) + jGen.writeStringField("actions","null"); + else{ + jGen.writeFieldName("actions"); + jGen.writeStartArray(); + for(OFActionType action : actions){ + jGen.writeString(action.toString()); + } + jGen.writeEndArray(); + } + } + + public void serializeAttributes(Map<Object, Object> attributes, JsonGenerator jGen) + throws IOException, JsonProcessingException { + if ( null == attributes) + jGen.writeStringField("attributes","null"); + else{ + jGen.writeFieldName("attributes"); + jGen.writeStartObject(); + for (Map.Entry<Object, Object> entry : attributes.entrySet()) { + if( entry.getValue() instanceof EnumSet<?>){ + jGen.writeFieldName(entry.getKey().toString()); + jGen.writeStartArray(); + //Maybe need to check other type. + for(OFFlowWildcards wildcard : (EnumSet<OFFlowWildcards>)entry.getValue()){ + jGen.writeString(wildcard.toString()); + } + jGen.writeEndArray(); + } + else + jGen.writeStringField(entry.getKey().toString(),entry.getValue().toString()); + } + jGen.writeEndObject(); + } + } + public void serializePorts(Collection<OFPortDesc> portDecs, JsonGenerator jGen) + throws IOException, JsonProcessingException { + if ( portDecs == null) + jGen.writeStringField("ports","null"); + else{ + jGen.writeFieldName("ports"); + jGen.writeStartArray(); + for(OFPortDesc port : portDecs){ + jGen.writeStartObject(); + jGen.writeNumberField("PortNo",port.getPortNo().getPortNumber()); + jGen.writeStringField("HwAddr",port.getHwAddr().toString()); + jGen.writeStringField("Name",port.getName()); + if ( port.getVersion() != OFVersion.OF_10){ + jGen.writeNumberField("CurrSpeed",port.getCurrSpeed()); + jGen.writeNumberField("MaxSpeed",port.getMaxSpeed()); + } + jGen.writeFieldName("config"); + jGen.writeStartArray(); + for(OFPortConfig config : port.getConfig()){ + jGen.writeString(config.toString()); + } + jGen.writeEndArray(); + jGen.writeFieldName("state"); + jGen.writeStartArray(); + for(OFPortState state : port.getState()){ + jGen.writeString(state.toString()); + } + jGen.writeEndArray(); + + jGen.writeFieldName("curr"); + jGen.writeStartArray(); + for(OFPortFeatures curr : port.getCurr()){ + jGen.writeString(curr.toString()); + } + jGen.writeEndArray(); + jGen.writeFieldName("advertised"); + jGen.writeStartArray(); + for(OFPortFeatures advertised : port.getAdvertised()){ + jGen.writeString(advertised.toString()); + } + jGen.writeEndArray(); + jGen.writeFieldName("supported"); + jGen.writeStartArray(); + for(OFPortFeatures support : port.getSupported()){ + jGen.writeString(support.toString()); + } + jGen.writeEndArray(); + jGen.writeFieldName("peer"); + jGen.writeStartArray(); + for(OFPortFeatures peer : port.getPeer()){ + jGen.writeString(peer.toString()); + } + jGen.writeEndArray(); + jGen.writeEndObject(); + } + jGen.writeEndArray(); + + } + } + public void serializeDescription(SwitchDescription swDescription, JsonGenerator jGen) + throws IOException, JsonProcessingException { + if( null == swDescription) + jGen.writeStringField("description","null"); + else{ + jGen.writeFieldName("description"); + jGen.writeStartObject(); + jGen.writeStringField("datapath",swDescription.getDatapathDescription()); + jGen.writeStringField("hardware",swDescription.getHardwareDescription()); + jGen.writeStringField("manufacturer",swDescription.getManufacturerDescription()); + jGen.writeStringField("serialNum",swDescription.getSerialNumber()); + jGen.writeStringField("software",swDescription.getSoftwareDescription()); + jGen.writeEndObject(); + } + } + public void serializeCapabilities(Set<OFCapabilities> ofCapabilities, JsonGenerator jGen) + throws IOException, JsonProcessingException { + if (null == ofCapabilities) + jGen.writeStringField("capabilities","null"); + else{ + jGen.writeFieldName("capabilities"); + jGen.writeStartArray(); + for(OFCapabilities ofCapability : ofCapabilities){ + jGen.writeString(ofCapability.toString()); + } + jGen.writeEndArray(); + } + } + public void serializeHarole(OFControllerRole role, JsonGenerator jGen) + throws IOException, JsonProcessingException { + if ( null == role ) + jGen.writeStringField("harole","null"); + else + jGen.writeStringField("harole",HARole.ofOFRole(role).toString()); + } +}