blob: a51e499c4d0373ce3495fbf703c8251e5b475d89 [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
34 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;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080040
41 // ***********
42 // Application
43 // ***********
44
45 protected class RestApplication extends Application {
46 protected Context context;
47
48 public RestApplication() {
49 super(new Context());
50 this.context = getContext();
51 }
52
53 @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
61 Filter slashFilter = new Filter() {
62 @Override
63 protected int beforeHandle(Request request, Response response) {
64 Reference ref = request.getResourceRef();
65 String originalPath = ref.getPath();
66 if (originalPath.contains("//"))
67 {
68 String newPath = originalPath.replaceAll("/+", "/");
69 ref.setPath(newPath);
70 }
71 return Filter.CONTINUE;
72 }
73
74 };
75 slashFilter.setNext(baseRouter);
76
77 return slashFilter;
78 }
79
80 public void run(FloodlightModuleContext fmlContext, int restPort) {
81 setStatusService(new StatusService() {
82 @Override
83 public Representation getRepresentation(Status status,
84 Request request,
85 Response response) {
86 return new JacksonRepresentation<Status>(status);
87 }
88 });
89
90 // Add everything in the module context to the rest
91 for (Class<? extends IFloodlightService> s : fmlContext.getAllServices()) {
92 if (logger.isTraceEnabled()) {
93 logger.trace("Adding {} for service {} into context",
94 s.getCanonicalName(), fmlContext.getServiceImpl(s));
95 }
96 context.getAttributes().put(s.getCanonicalName(),
97 fmlContext.getServiceImpl(s));
98 }
99
100 // Start listening for REST requests
101 try {
102 final Component component = new Component();
Jonathan Hart285f2c22013-07-03 16:26:46 +1200103 Server server = component.getServers().add(Protocol.HTTP, restPort);
104 if (numThreads != null){
105 logger.debug("Setting number of REST API threads to {}", numThreads);
106 server.getContext().getParameters().add("defaultThreads", numThreads);
107 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800108 component.getDefaultHost().attach(this);
109 component.start();
110 } catch (Exception e) {
111 throw new RuntimeException(e);
112 }
113 }
114 }
115
116 // ***************
117 // IRestApiService
118 // ***************
119
120 @Override
121 public void addRestletRoutable(RestletRoutable routable) {
122 restlets.add(routable);
123 }
124
125 @Override
126 public void run() {
127 if (logger.isDebugEnabled()) {
128 StringBuffer sb = new StringBuffer();
129 sb.append("REST API routables: ");
130 for (RestletRoutable routable : restlets) {
131 sb.append(routable.getClass().getSimpleName());
132 sb.append(" (");
133 sb.append(routable.basePath());
134 sb.append("), ");
135 }
136 logger.debug(sb.toString());
137 }
138
139 RestApplication restApp = new RestApplication();
140 restApp.run(fmlContext, restPort);
141 }
142
143 // *****************
144 // IFloodlightModule
145 // *****************
146
147 @Override
148 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
149 Collection<Class<? extends IFloodlightService>> services =
150 new ArrayList<Class<? extends IFloodlightService>>(1);
151 services.add(IRestApiService.class);
152 return services;
153 }
154
155 @Override
156 public Map<Class<? extends IFloodlightService>, IFloodlightService>
157 getServiceImpls() {
158 Map<Class<? extends IFloodlightService>,
159 IFloodlightService> m =
160 new HashMap<Class<? extends IFloodlightService>,
161 IFloodlightService>();
162 m.put(IRestApiService.class, this);
163 return m;
164 }
165
166 @Override
167 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
168 // We don't have any
169 return null;
170 }
171
172 @Override
173 public void init(FloodlightModuleContext context)
174 throws FloodlightModuleException {
175 // This has to be done here since we don't know what order the
176 // startUp methods will be called
177 this.restlets = new ArrayList<RestletRoutable>();
178 this.fmlContext = context;
179
180 // read our config options
181 Map<String, String> configOptions = context.getConfigParams(this);
182 String port = configOptions.get("port");
183 if (port != null) {
184 restPort = Integer.parseInt(port);
185 }
186 logger.debug("REST port set to {}", restPort);
Jonathan Hart285f2c22013-07-03 16:26:46 +1200187
188 String numThreads = configOptions.get("dispatcherthreads");
189 if (numThreads != null) {
190 this.numThreads = numThreads;
191 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800192 }
193
194 @Override
195 public void startUp(FloodlightModuleContext Context) {
196 // no-op
197 }
198}