blob: 031a239b73ba14022026921c6d49edc8e0cda4b1 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001package net.floodlightcontroller.restserver;
2
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.HashMap;
6import java.util.List;
7import java.util.Map;
8
Jonathan Hart285f2c22013-07-03 16:26:46 +12009import net.floodlightcontroller.core.module.FloodlightModuleContext;
10import net.floodlightcontroller.core.module.FloodlightModuleException;
11import net.floodlightcontroller.core.module.IFloodlightModule;
12import net.floodlightcontroller.core.module.IFloodlightService;
13
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080014import org.restlet.Application;
15import org.restlet.Component;
16import org.restlet.Context;
17import org.restlet.Request;
18import org.restlet.Response;
19import org.restlet.Restlet;
Jonathan Hart285f2c22013-07-03 16:26:46 +120020import org.restlet.Server;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080021import org.restlet.data.Protocol;
22import org.restlet.data.Reference;
23import org.restlet.data.Status;
24import org.restlet.ext.jackson.JacksonRepresentation;
25import org.restlet.representation.Representation;
26import org.restlet.routing.Filter;
27import org.restlet.routing.Router;
28import org.restlet.routing.Template;
29import org.restlet.service.StatusService;
30import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
32
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080033public class RestApiServer
Ray Milkey269ffb92014-04-03 14:43:30 -070034 implements IFloodlightModule, IRestApiService {
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070035 protected final static Logger logger = LoggerFactory.getLogger(RestApiServer.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080036 protected List<RestletRoutable> restlets;
37 protected FloodlightModuleContext fmlContext;
38 protected int restPort = 8080;
Jonathan Hart285f2c22013-07-03 16:26:46 +120039 protected String numThreads = null;
Ray Milkey269ffb92014-04-03 14:43:30 -070040
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080041 // ***********
42 // Application
43 // ***********
Ray Milkey269ffb92014-04-03 14:43:30 -070044
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080045 protected class RestApplication extends Application {
46 protected Context context;
Ray Milkey269ffb92014-04-03 14:43:30 -070047
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080048 public RestApplication() {
49 super(new Context());
50 this.context = getContext();
51 }
Ray Milkey269ffb92014-04-03 14:43:30 -070052
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080053 @Override
54 public Restlet createInboundRoot() {
55 Router baseRouter = new Router(context);
56 baseRouter.setDefaultMatchingMode(Template.MODE_STARTS_WITH);
57 for (RestletRoutable rr : restlets) {
58 baseRouter.attach(rr.basePath(), rr.getRestlet(context));
59 }
60
Ray Milkey269ffb92014-04-03 14:43:30 -070061 Filter slashFilter = new Filter() {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080062 @Override
63 protected int beforeHandle(Request request, Response response) {
64 Reference ref = request.getResourceRef();
65 String originalPath = ref.getPath();
Ray Milkey269ffb92014-04-03 14:43:30 -070066 if (originalPath.contains("//")) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080067 String newPath = originalPath.replaceAll("/+", "/");
68 ref.setPath(newPath);
69 }
70 return Filter.CONTINUE;
71 }
72
73 };
74 slashFilter.setNext(baseRouter);
Ray Milkey269ffb92014-04-03 14:43:30 -070075
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080076 return slashFilter;
77 }
Ray Milkey269ffb92014-04-03 14:43:30 -070078
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080079 public void run(FloodlightModuleContext fmlContext, int restPort) {
80 setStatusService(new StatusService() {
81 @Override
82 public Representation getRepresentation(Status status,
83 Request request,
84 Response response) {
85 return new JacksonRepresentation<Status>(status);
Ray Milkey269ffb92014-04-03 14:43:30 -070086 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080087 });
Ray Milkey269ffb92014-04-03 14:43:30 -070088
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080089 // Add everything in the module context to the rest
90 for (Class<? extends IFloodlightService> s : fmlContext.getAllServices()) {
91 if (logger.isTraceEnabled()) {
92 logger.trace("Adding {} for service {} into context",
Ray Milkey269ffb92014-04-03 14:43:30 -070093 s.getCanonicalName(), fmlContext.getServiceImpl(s));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080094 }
Ray Milkey269ffb92014-04-03 14:43:30 -070095 context.getAttributes().put(s.getCanonicalName(),
96 fmlContext.getServiceImpl(s));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080097 }
Ray Milkey269ffb92014-04-03 14:43:30 -070098
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080099 // Start listening for REST requests
100 try {
101 final Component component = new Component();
Jonathan Hart285f2c22013-07-03 16:26:46 +1200102 Server server = component.getServers().add(Protocol.HTTP, restPort);
Ray Milkey269ffb92014-04-03 14:43:30 -0700103 if (numThreads != null) {
104 logger.debug("Setting number of REST API threads to {}", numThreads);
105 server.getContext().getParameters().add("defaultThreads", numThreads);
Jonathan Hart285f2c22013-07-03 16:26:46 +1200106 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800107 component.getDefaultHost().attach(this);
108 component.start();
109 } catch (Exception e) {
110 throw new RuntimeException(e);
111 }
112 }
113 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700114
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800115 // ***************
116 // IRestApiService
117 // ***************
Ray Milkey269ffb92014-04-03 14:43:30 -0700118
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800119 @Override
120 public void addRestletRoutable(RestletRoutable routable) {
121 restlets.add(routable);
122 }
123
124 @Override
125 public void run() {
126 if (logger.isDebugEnabled()) {
127 StringBuffer sb = new StringBuffer();
128 sb.append("REST API routables: ");
129 for (RestletRoutable routable : restlets) {
130 sb.append(routable.getClass().getSimpleName());
131 sb.append(" (");
132 sb.append(routable.basePath());
133 sb.append("), ");
134 }
135 logger.debug(sb.toString());
136 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700137
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800138 RestApplication restApp = new RestApplication();
139 restApp.run(fmlContext, restPort);
140 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700141
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800142 // *****************
143 // IFloodlightModule
144 // *****************
Ray Milkey269ffb92014-04-03 14:43:30 -0700145
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800146 @Override
147 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
148 Collection<Class<? extends IFloodlightService>> services =
149 new ArrayList<Class<? extends IFloodlightService>>(1);
150 services.add(IRestApiService.class);
151 return services;
152 }
153
154 @Override
155 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Ray Milkey269ffb92014-04-03 14:43:30 -0700156 getServiceImpls() {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800157 Map<Class<? extends IFloodlightService>,
Ray Milkey269ffb92014-04-03 14:43:30 -0700158 IFloodlightService> m =
159 new HashMap<Class<? extends IFloodlightService>,
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800160 IFloodlightService>();
161 m.put(IRestApiService.class, this);
162 return m;
163 }
164
165 @Override
166 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
167 // We don't have any
168 return null;
169 }
170
171 @Override
172 public void init(FloodlightModuleContext context)
173 throws FloodlightModuleException {
174 // This has to be done here since we don't know what order the
175 // startUp methods will be called
176 this.restlets = new ArrayList<RestletRoutable>();
177 this.fmlContext = context;
Ray Milkey269ffb92014-04-03 14:43:30 -0700178
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800179 // read our config options
180 Map<String, String> configOptions = context.getConfigParams(this);
181 String port = configOptions.get("port");
182 if (port != null) {
183 restPort = Integer.parseInt(port);
184 }
185 logger.debug("REST port set to {}", restPort);
Ray Milkey269ffb92014-04-03 14:43:30 -0700186
Jonathan Hart285f2c22013-07-03 16:26:46 +1200187 String numThreads = configOptions.get("dispatcherthreads");
188 if (numThreads != null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700189 this.numThreads = numThreads;
Jonathan Hart285f2c22013-07-03 16:26:46 +1200190 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800191 }
192
193 @Override
194 public void startUp(FloodlightModuleContext Context) {
195 // no-op
196 }
197}