/*
* Copyright (C) 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.errai.bus.server.util;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.jboss.errai.bus.client.api.Local;
import org.jboss.errai.bus.client.api.messaging.MessageCallback;
import org.jboss.errai.bus.server.annotations.Command;
import org.jboss.errai.bus.server.annotations.Remote;
import org.jboss.errai.bus.server.annotations.Service;
import org.jboss.errai.bus.server.io.CommandBindingsCallback;
/**
* A {@link ServiceParser} implementation for types annotated with {@link Service}.
*
* @author Max Barkley <mbarkley@redhat.com>
*/
public class ServiceTypeParser extends ServiceParser {
private final Class<?> clazz;
/**
* Create a {@link ServiceParser} for classes annotated with {@link Service}.
*
* @param clazz A class annotated with {@link Service}.
* @throws NotAService Thrown if {@code clazz} does not have a {@link Service} annotation.
*/
public ServiceTypeParser(Class<?> clazz) throws NotAService {
this.clazz = clazz;
Service svcAnnotation = clazz.getAnnotation(Service.class);
if (null == svcAnnotation) {
throw new NotAService("The class " + clazz.getName() + " is not a service");
}
local = clazz.isAnnotationPresent(Local.class);
svcName = resolveServiceName(clazz);
this.commandPoints = Collections.unmodifiableMap(getCommandPoints(clazz));
}
/**
* @return The {@link Remote} interface associated with this type service or {@code null} if none exists.
*/
public Class<?> getRemoteImplementation() {
return getRemoteImplementation(clazz);
}
private static Class<?> getRemoteImplementation(Class<?> type) {
for (Class<?> iface : type.getInterfaces()) {
if (iface.isAnnotationPresent(Remote.class)) {
return iface;
}
else if (iface.getInterfaces().length != 0 && ((iface = getRemoteImplementation(iface)) != null)) {
return iface;
}
}
return null;
}
/**
* Get the subject name of a service type.
*/
private static String resolveServiceName(final Class<?> type) {
String subjectName = type.getAnnotation(Service.class).value();
if (subjectName.equals(""))
subjectName = type.getSimpleName();
return subjectName;
}
private static Map<String, Method> getCommandPoints(Class<?> clazz) {
Map<String, Method> commandPoints = new HashMap<String, Method>();
for (final Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Command.class) && !method.isAnnotationPresent(Service.class)) {
Command command = method.getAnnotation(Command.class);
for (String cmdName : command.value()) {
if (cmdName.equals(""))
cmdName = method.getName();
commandPoints.put(cmdName, method);
}
}
}
return commandPoints;
}
@Override
public Class<?> getDelegateClass() {
return clazz;
}
@Override
public boolean isCallback() {
return MessageCallback.class.isAssignableFrom(clazz) && !hasCommandPoints();
}
@Override
public String toString() {
return clazz.toString();
}
@Override
public MessageCallback getCallback(Object delegateInstance) {
if (isCallback()) {
return (MessageCallback) delegateInstance;
}
else if (hasCommandPoints()) {
return new CommandBindingsCallback(getCommandPoints(), delegateInstance);
}
else {
return null;
}
}
}