/*
* Copyright 2011 cruxframework.org.
*
* 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.cruxframework.crux.core.rebind.context.scanner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.cruxframework.crux.core.client.controller.Controller;
import org.cruxframework.crux.core.client.controller.Global;
import org.cruxframework.crux.core.client.controller.WidgetController;
import org.cruxframework.crux.core.client.screen.DeviceAdaptive.Device;
import org.cruxframework.crux.core.client.utils.StringUtils;
import org.cruxframework.crux.core.rebind.CruxGeneratorException;
import org.cruxframework.crux.core.rebind.context.JClassScanner;
import org.cruxframework.crux.core.rebind.screen.widget.WidgetLibraries;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.user.client.ui.IsWidget;
/**
* Maps all controllers in a module.
* @author Thiago Bustamante
*
*/
public class ControllerScanner
{
private Map<String, Map<String, String>> controllersCanonicalNames;
private List<String> globalControllers;
private boolean initialized = false;
private JClassScanner jClassScanner;
private Map<String, Set<String>> widgetControllers;
public ControllerScanner(JClassScanner jClassScanner)
{
this.jClassScanner = jClassScanner;
}
/**
* @param name
* @return
*/
public String getController(String name, Device device) throws ResourceNotFoundException
{
initializeControllers();
Map<String, String> map = controllersCanonicalNames.get(name);
String result = map.get(device.toString());
if (result == null && !device.equals(Device.all))
{
result = map.get(Device.all.toString());
}
if (result == null)
{
throw new ResourceNotFoundException("Can not found requested controller ["+name+"], for device ["+device+"].");
}
return result;
}
/**
*
* @param controller
* @return
*/
public Class<?> getControllerClass(String controller, Device device) throws ResourceNotFoundException
{
String result = getController(controller, device);
try
{
return Class.forName(result);
}
catch (Exception e)
{
throw new ResourceNotFoundException("Can not found requested controller ["+controller+"], for device ["+device+"].");
}
}
/**
*
* @param name
* @return
*/
public boolean hasController(String name)
{
initializeControllers();
return (name != null && controllersCanonicalNames.containsKey(name));
}
/**
* @return
*/
public Iterator<String> iterateControllers()
{
initializeControllers();
return controllersCanonicalNames.keySet().iterator();
}
/**
* @return
*/
public Iterator<String> iterateGlobalControllers()
{
initializeControllers();
return globalControllers.iterator();
}
/**
* @param widgetClass
* @return
*/
public Iterator<String> iterateWidgetControllers(String widgetType)
{
initializeControllers();
Set<String> controllers = widgetControllers.get(widgetType);
if (controllers == null)
{
return null;
}
return controllers.iterator();
}
/**
*
*/
protected void initializeControllers()
{
if (!initialized)
{
try
{
controllersCanonicalNames = new HashMap<String, Map<String, String>>();
globalControllers = new ArrayList<String>();
widgetControllers = new HashMap<String, Set<String>>();
JClassType[] controllerTypes = jClassScanner.searchClassesByAnnotation(Controller.class);
if (controllerTypes != null)
{
for (JClassType controllerClass : controllerTypes)
{
Controller annot = controllerClass.getAnnotation(Controller.class);
Device[] devices = annot.supportedDevices();
String resourceKey = annot.value();
if (devices == null || devices.length ==0)
{
addResource(controllerClass, resourceKey, Device.all);
}
else
{
for (Device device : devices)
{
addResource(controllerClass, resourceKey, device);
}
}
if (controllerClass.getAnnotation(Global.class) != null)
{
globalControllers.add(annot.value());
}
initWidgetControllers(controllerClass, annot);
}
}
initialized = true;
}
catch (Exception e)
{
throw new CruxGeneratorException("Error initializing controllers scanner.", e);
}
}
}
/**
*
* @param controllerClass
* @param controllerKey
* @param device
*/
private void addResource(JClassType controllerClass, String controllerKey, Device device)
{
if (!controllersCanonicalNames.containsKey(controllerKey))
{
controllersCanonicalNames.put(controllerKey, new HashMap<String, String>());
}
Map<String, String> canonicallClassNamesByDevice = controllersCanonicalNames.get(controllerKey);
String deviceKey = device.toString();
if (controllersCanonicalNames.containsKey(deviceKey))
{
throw new CruxGeneratorException("Duplicated Client Controller: ["+controllerKey+"].");
}
canonicallClassNamesByDevice.put(deviceKey, controllerClass.getQualifiedSourceName());
}
/**
* @param controllerClass
* @param annot
*/
private void initWidgetControllers(JClassType controllerClass, Controller annot)
{
WidgetController widgetControllerAnnot = controllerClass.getAnnotation(WidgetController.class);
if (widgetControllerAnnot != null)
{
Class<? extends IsWidget>[] widgets = widgetControllerAnnot.value();
for (Class<? extends IsWidget> widgetClass : widgets)
{
String widgetType = WidgetLibraries.getInstance().getWidgetType(widgetClass);
if (!StringUtils.isEmpty(widgetType))
{
Set<String> controllers = widgetControllers.get(widgetType);
if (controllers == null)
{
controllers = new HashSet<String>();
widgetControllers.put(widgetType, controllers);
}
controllers.add(annot.value());
}
}
}
}
}