org.rapidoid.setup.PojoHandlersSetup Maven / Gradle / Ivy
package org.rapidoid.setup;
import org.rapidoid.RapidoidThing;
import org.rapidoid.annotation.*;
import org.rapidoid.beany.Metadata;
import org.rapidoid.cache.Cached;
import org.rapidoid.cls.Cls;
import org.rapidoid.ioc.IoCContext;
import org.rapidoid.log.Log;
import org.rapidoid.security.Secure;
import org.rapidoid.u.U;
import org.rapidoid.util.Constants;
import org.rapidoid.util.Msc;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Set;
/*
* #%L
* rapidoid-http-server
* %%
* Copyright (C) 2014 - 2017 Nikolche Mihajlovski and 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.
* #L%
*/
@Authors("Nikolche Mihajlovski")
@Since("5.1.0")
public class PojoHandlersSetup extends RapidoidThing {
private static final Set CONTROLLER_ANNOTATIONS = U.set(
Page.class.getName(), GET.class.getName(), POST.class.getName(),
PUT.class.getName(), DELETE.class.getName(), PATCH.class.getName(),
OPTIONS.class.getName(), HEAD.class.getName(), TRACE.class.getName()
);
private final Setup setup;
private final Object[] beans;
private PojoHandlersSetup(Setup setup, Object[] beans) {
this.setup = setup;
this.beans = beans;
}
public static PojoHandlersSetup from(Setup setup, Object[] beans) {
return new PojoHandlersSetup(setup, beans);
}
public void register() {
process(true);
}
public void deregister() {
process(false);
}
private void process(boolean register) {
for (Object bean : beans) {
processBean(register, bean);
}
}
private void processBean(boolean register, Object bean) {
Class> clazz;
U.notNull(bean, "bean");
IoCContext context = setup.context();
if (bean instanceof Class>) {
clazz = (Class>) bean;
bean = null;
} else {
clazz = bean.getClass();
}
if (!Cls.isAppBeanType(clazz)) {
throw new RuntimeException("Expected a bean, but found value of type: " + clazz.getName());
}
if (!Msc.matchingProfile(clazz)) {
return;
}
Log.debug("Processing bean", "class", clazz, "instance", bean);
List componentPaths = getControllerUris(clazz);
for (String ctxPath : componentPaths) {
for (Method method : Cls.getMethods(clazz)) {
if (shouldExpose(method)) {
if (bean == null) {
bean = register ? context.singleton(clazz) : null;
}
registerOrDeregister(register, bean, ctxPath, method);
}
}
}
}
private boolean shouldExpose(Method method) {
boolean isUserDefined = !method.getDeclaringClass().equals(Object.class);
int modifiers = method.getModifiers();
boolean isAbstract = Modifier.isAbstract(modifiers);
boolean isStatic = Modifier.isStatic(modifiers);
boolean isPrivate = Modifier.isPrivate(modifiers);
boolean isProtected = Modifier.isProtected(modifiers);
if (isUserDefined && !isAbstract && !isStatic && !isPrivate && !isProtected && method.getAnnotations().length > 0) {
for (Annotation ann : method.getAnnotations()) {
String annoName = ann.annotationType().getName();
if (CONTROLLER_ANNOTATIONS.contains(annoName)) {
return true;
}
}
}
return false;
}
protected List getControllerUris(Class> component) {
Controller controller = Metadata.classAnnotation(component, Controller.class);
if (controller != null) {
return U.list(controller.value());
} else {
return U.list("/");
}
}
private void registerOrDeregister(boolean register, Object bean, String ctxPath, Method method) {
for (Annotation ann : method.getAnnotations()) {
if (ann instanceof Page) {
Page page = (Page) ann;
String path = pathOf(method, ctxPath, uriOf(ann));
if (register) {
OnRoute route = route(setup.page(path), method);
if (U.notEmpty(page.view())) {
route.view(page.view());
}
if (page.raw()) {
route.html(method, bean);
} else {
route.mvc(method, bean);
}
} else {
setup.deregister(Constants.GET_OR_POST, path);
}
} else if (ann instanceof GET) {
String path = pathOf(method, ctxPath, uriOf(ann));
if (register) {
route(setup.get(path), method).json(method, bean);
} else {
setup.deregister(Constants.GET, path);
}
} else if (ann instanceof POST) {
String path = pathOf(method, ctxPath, uriOf(ann));
if (register) {
route(setup.post(path), method).json(method, bean);
} else {
setup.deregister(Constants.POST, path);
}
} else if (ann instanceof PUT) {
String path = pathOf(method, ctxPath, uriOf(ann));
if (register) {
route(setup.put(path), method).json(method, bean);
} else {
setup.deregister(Constants.PUT, path);
}
} else if (ann instanceof DELETE) {
String path = pathOf(method, ctxPath, uriOf(ann));
if (register) {
route(setup.delete(path), method).json(method, bean);
} else {
setup.deregister(Constants.DELETE, path);
}
} else if (ann instanceof PATCH) {
String path = pathOf(method, ctxPath, uriOf(ann));
if (register) {
route(setup.patch(path), method).json(method, bean);
} else {
setup.deregister(Constants.PATCH, path);
}
} else if (ann instanceof OPTIONS) {
String path = pathOf(method, ctxPath, uriOf(ann));
if (register) {
route(setup.options(path), method).json(method, bean);
} else {
setup.deregister(Constants.OPTIONS, path);
}
} else if (ann instanceof HEAD) {
String path = pathOf(method, ctxPath, uriOf(ann));
if (register) {
route(setup.head(path), method).json(method, bean);
} else {
setup.deregister(Constants.HEAD, path);
}
} else if (ann instanceof TRACE) {
String path = pathOf(method, ctxPath, uriOf(ann));
if (register) {
route(setup.trace(path), method).json(method, bean);
} else {
setup.deregister(Constants.TRACE, path);
}
}
}
}
private OnRoute route(OnRoute route, Method method) {
// TRANSACTION
Transaction transaction = method.getAnnotation(Transaction.class);
if (transaction != null) {
route.transaction(transaction.value());
}
// ROLES
Set rolesAllowed = Secure.getRolesAllowed(method);
String[] roles = U.arrayOf(String.class, rolesAllowed);
route.roles(roles);
// CACHE
Cached cached = method.getAnnotation(Cached.class);
if (cached != null) {
route.cacheTTL(cached.ttl());
}
return route;
}
private String uriOf(Annotation ann) {
Method valueMethod = Cls.getMethod(ann.getClass(), "value");
String uri = Cls.invoke(valueMethod, ann);
if (U.isEmpty(uri)) {
Method uriMethod = Cls.getMethod(ann.getClass(), "uri");
uri = Cls.invoke(uriMethod, ann);
}
return uri;
}
private String pathOf(Method method, String ctxPath, String uri) {
String path = !U.isEmpty(uri) ? uri : method.getName();
return Msc.uri(ctxPath, path);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy