/*
* ******************************************************************************
* * Copyright 2015 See AUTHORS file.
* *
* * 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 com.puremvc.core;
import java.util.HashMap;
import java.util.Map;
import com.puremvc.patterns.command.Command;
import com.puremvc.patterns.observer.BaseObserver;
import com.puremvc.patterns.observer.Notification;
/**
* A Singleton <code>Controller</code> implementation.
* <p>
* <p>
* In PureMVC, the <code>Controller</code> class follows the
* 'Command and Controller' strategy, and assumes these
* responsibilities:
* <UL>
* <LI> Remembering which <code>ICommand</code>s
* are intended to handle which <code>INotifications</code>.</LI>
* <LI> Registering itself as an <code>IObserver</code> with
* the <code>View</code> for each <code>INotification</code>
* that it has an <code>ICommand</code> mapping for.</LI>
* <LI> Creating a new instance of the proper <code>ICommand</code>
* to handle a given <code>INotification</code> when notified by the <code>View</code>.</LI>
* <LI> Calling the <code>ICommand</code>'s <code>execute</code>
* method, passing in the <code>INotification</code>.</LI>
* </UL>
* <p>
* <p>
* Your application must register <code>ICommands</code> with the
* Controller.
* <p>
* The simplest way is to subclass </code>Facade</code>,
* and use its <code>initializeController</code> method to add your
* registrations.
*
* @see CoreView View
* @see BaseObserver Observer
* @see com.puremvc.patterns.observer.Notification Notification
* @see com.puremvc.patterns.command.SimpleCommand SimpleCommand
* @see com.puremvc.patterns.command.MacroCommand MacroCommand
*/
public class CoreController implements Controller {
/**
* Reference to the singleton instance
*/
protected static CoreController instance;
/**
* Mapping of Notification names to Command Class references
*/
protected Map<String, Class<? extends Command>> commandMap;
/**
* Local reference to View
*/
protected CoreView view;
/**
* Constructor.
* <p>
* <p>
* This <code>IController</code> implementation is a Singleton, so you
* should not call the constructor directly, but instead call the static
* Singleton Factory method <code>Controller.getInstance()</code>
*/
protected CoreController() {
instance = this;
commandMap = new HashMap<>();
initializeController();
}
/**
* <code>Controller</code> Singleton Factory method.
*
* @return the Singleton instance of <code>Controller</code>
*/
public synchronized static CoreController getInstance() {
if (instance == null) {
instance = new CoreController();
}
return instance;
}
/**
* Initialize the Singleton <code>Controller</code> instance.
* <p>
* <P>Called automatically by the constructor.</P>
* <p>
* <P>Note that if you are using a subclass of <code>View</code>
* in your application, you should <i>also</i> subclass <code>Controller</code>
* and override the <code>initializeController</code> method in the
* following way:</P>
* <p>
* <listing>
* // ensure that the Controller is talking to my IView implementation
* override public function initializeController( ) : void
* {
* view = MyView.getInstance();
* }
* </listing>
*/
protected void initializeController() {
view = CoreView.getInstance();
}
/**
* If an <code>ICommand</code> has previously been registered to handle a
* the given <code>INotification</code>, then it is executed.
*
* @param note The notification to send associated with the command to call.
*/
public void executeCommand(Notification note) {
//No reflexion in GWT
Class<? extends Command> commandClass = commandMap.get(note.getName());
if (commandClass != null) {
Command command;
try {
command = commandClass.newInstance();
command.execute(note);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
/**
* Register a particular <code>ICommand</code> class as the handler for a
* particular <code>INotification</code>.
* <p>
* <p>
* If an <code>ICommand</code> has already been registered to handle
* <code>INotification</code>s with this name, it is no longer used, the
* new <code>ICommand</code> is used instead.
* </P>
* <p>
* The Observer for the new ICommand is only created if this the
* first time an ICommand has been regisered for this Notification name.
*
* @param notificationName the name of the <code>Notification</code>
* @param command an instance of <code>Command</code>
*/
public void registerCommand(String notificationName, Class<? extends Command> command) {
if (null != commandMap.put(notificationName, command)) {
return;
}
view.registerObserver
(
notificationName,
new BaseObserver(this::executeCommand, this)
);
}
/**
* Remove a previously registered <code>ICommand</code> to
* <code>INotification</code> mapping.
*
* @param notificationName the name of the <code>INotification</code> to remove the
* <code>ICommand</code> mapping for
*/
public void removeCommand(String notificationName) {
// if the Command is registered...
if (hasCommand(notificationName)) {
// remove the observer
view.removeObserver(notificationName, this);
commandMap.remove(notificationName);
}
}
/**
* Check if a Command is registered for a given Notification
*
* @param notificationName The name of the command to check for existance.
* @return whether a Command is currently registered for the given <code>notificationName</code>.
*/
public boolean hasCommand(String notificationName) {
return commandMap.containsKey(notificationName);
}
}