Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pluggable Architecture

skiera
September 07, 2012

Pluggable Architecture

Erweiterbarkeit ist eine wichtige Eigenschaft moderner Software. Dies gilt nicht nur für das Klassendesign, sondern auch für die Möglichkeit, Funktionen auf Basis von Plugins hinzuzufügen. Dieser Vortrag stellt verschiedene Möglichkeiten von Plugin-Architekturen vor und erzählt dabei Erfahrungen aus guten und weniger guten Ansätzen.

skiera

September 07, 2012
Tweet

Other Decks in Programming

Transcript

  1. Definition: Plug-In (Wikipedia) "In computing, a plug-in (or plugin) is

    a set of software components that adds specific abilities to a larger software application. If supported, plug-ins enable customizing the functionality of an application. For example, plug-ins are commonly used in web browsers to play video, scan for viruses, and display new file types." Applications support plug-ins for many reasons. Some of the main reasons include: ▪ to enable third-party developers to create abilities which extend an application ▪ to support easily adding new features ▪ to reduce the size of an application ▪ to separate source code from an application because of incompatible software licenses. http://en.wikipedia.org/wiki/Plug-in_(computing) Foto: C. Nöhren / pixelio.de
  2. phpBB ▪ Free flat-forum bulletin board software ▪ Language: PHP

    ▪ Current Version: 3.0.11 ▪ Homepage: http://www.phpbb.com ▪ Modifications: 506 date 06.09.2012 Examples for phpBB 2 not 3
  3. install.txt (excerpt) ############################################################## ## Before Adding This MOD To Your

    Forum, You Should Back Up All Files Related To This MOD ############################################################## # #-----[ COPY ]------------------------------------------------ # copy /root/ajax.php to /ajax.php copy /root/includes/javascript/ajax_core.js to /includes/javascript/ajax_core.js copy /root/includes/javascript/ajax_forum.js to /includes/javascript/ajax_forum.js # #-----[ OPEN ]------------------------------------------------ # admin/page_header_admin.php # #-----[ FIND ]------------------------------------------------ # 'PAGE_TITLE' => $page_title, # #-----[ AFTER, ADD ]------------------------------------------ # 'PHPBB_ROOT_PATH' => $phpbb_root_path, 'PHPEX' => $phpEx, Don't Do This At Home
  4. WordPress ▪ Free blog software ▪ Language: PHP ▪ Current

    Version: 3.4.1 ▪ Homepage: http://www.wordpress.org ▪ Plugins: 21.190 date 06.09.2012
  5. Example plugin structure Plugin directory: /wp-content/plugins example-plugin <-- Plugin folder

    ├── classes │ ├── example-class1.php │ └── example-class2.php ├── example-plugin.php <-- Main plugin file ├── includes │ ├── css │ │ └── example.css │ └── images │ └── example.jpg ├── languages │ ├── de_DE.mo │ ├── de_DE.po │ ├── en_GB.mo │ └── en_GB.po └── readme.txt
  6. Actions "Actions are the hooks that the WordPress core launches

    at specific points during execution, or when specific events occur. Your plugin can specify that one or more of its PHP functions are executed at these points, using the Action API." http://codex.wordpress.org/Plugin_API
  7. example-plugin.php (excerpt) 1. <?php 2. // 3. // create action

    4. // 5. class MyEmailer { 6. function send($post_ID) { 7. $friends = '[email protected],[email protected]'; 8. mail($friends, 'My blog updated','I just put something on my blog: http://blog.example.com'); 9. return $post_ID; 10. } 11. } 12. 13. // 14. // register action 15. // 16. $myEmailObj = new MyEmailer(); 17. add_action('publish_post', array($myEmailObj, 'send')); 18. 19. // 20. // execute action 21. // 22. do_action('publish_post', $post_ID);
  8. Filters "Filters are the hooks that WordPress launches to modify

    text of various types before adding it to the database or sending it to the browser screen. Your plugin can specify that one or more of its PHP functions is executed to modify specific types of text at these times, using the Filter API." http://codex.wordpress.org/Plugin_API
  9. example-plugin.php (excerpt) 1. <?php 2. // 3. // create filter

    4. // 5. function filter_profanity($content) { 6. $profanities = array('badword', 'alsobad', '...'); 7. $content=str_ireplace($profanities,'{censored}',$content); 8. return $content; 9. } 10. 11. // 12. // register filter 13. // 14. add_filter('comment_text','filter_profanity'); 15. 16. // 17. // aplly filters 18. // 19. $comment_text = 'My badword comment'; 20. 21. $comment_text = apply_filters('comment_text', $comment_text); 22. 23. echo $comment_text; // 'My {censored} comment'
  10. says Zend Zend Framework 2 ▪ Open source PHP 5.3+

    framework ▪ Language: PHP ▪ Current Version: 2 ("stable" since 05.09.2012) ▪ Homepage: http://framework.zend.com ▪ Modules: 52 date 06.09.2012
  11. Example plugin structure Plugin directory: /modules example-module <-- Module folder

    ├── Module.php <-- Module class ├── autoload_classmap.php ├── autoload_function.php ├── autotoad_register.php ├── config ├── public │ ├── css │ ├── images │ └── js ├── src ├── tests │ ├── bootstrap.php │ └── phpunit.xml └── views └── <dir-named-after-module-namespace> └── <dir-named-after-a-controller> └── <.phtml files>
  12. Module.php (excerpt) 1. <?php 2. class Module 3. { 4.

    public function getAutoloaderConfig() 5. { 6. return array( 7. 'Zend\Loader\ClassMapAutoloader' => array( 8. __DIR__ . '/autoload_classmap.php', 9. ), 10. ); 11. } 12. 13. public function getConfig() 14. { 15. return include __DIR__ . '/config/module.config.php'; 16. } 17. 18. public function onBootstrap(Event $e) 19. { 20. // This method is called once the MVC bootstrapping is complete 21. $application = $e->getApplication(); 22. $services = $application->getServiceManager(); 23. } 24. }
  13. ServiceManager "The service locator pattern is a design pattern used

    in software development to encapsulate the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the "service locator" which on request returns the information necessary to perform a certain task." http://en.wikipedia.org/wiki/Service_locator_pattern
  14. module.config.php (excerpt) 1. <?php 2. // a module configuration, "module/SomeModule/config/module.config.php"

    3. return array( 4. 'service_manager' => array( 5. 'aliases' => array( 6. // Aliasing a FQCN to a service name 7. 'SomeModule\Model\User' => 'User', 8. // Aliasing a name to a known service name 9. 'AdminUser' => 'User', 10. ), 11. 'factories' => array( 12. // Valid values include names of classes implementing 13. // FactoryInterface, instances of classes implementing 14. // FactoryInterface, or any PHP callbacks 15. 'User' => 'SomeModule\Service\UserFactory', 16. 'UserForm' => function ($serviceManager) { 17. $form = new SomeModuleFormUser(); 18. // Retrieve a dependency from the service manager and inject it! 19. $form->setInputFilter($serviceManager->get('UserInputFilter')); 20. return $form; 21. }, 22. ), 23. 'invokables' => array( 24. // Values are valid class names to instantiate. 25. 'UserInputFiler' => 'SomeModule\InputFilter\User', 26. ), 27. ), 28. );
  15. Log.php (excerpt) 1. <?php 2. use ZendServiceManagerServiceManager; 3. use ZendServiceManagerServiceManagerAwareInterface;

    4. use ZendStdlibDispatchableInterface as Dispatchable; 5. use ZendStdlibRequestInterface as Request; 6. use ZendStdlibResponseInterface as Response; 7. 8. class BareController implements 9. Dispatchable, 10. ServiceManagerAwareInterface 11. { 12. protected $services; 13. 14. public function setServiceManager(ServiceManager $serviceManager) 15. { 16. $this->services = $serviceManager; 17. } 18. 19. public function dispatch(Request $request, Response $response = null) 20. { 21. // ... 22. 23. // Retrieve something from the service manager 24. $router = $this->services->get('Router'); 25. 26. // ... 27. } 28. }
  16. EventManager The EventManager is a component designed for the following

    use cases: ▪ Implementing simple subject/observer patterns. ▪ Implementing Aspect-Oriented designs. ▪ Implementing event-driven architectures. The basic architecture allows you to attach and detach listeners to named events, both on a per-instance basis as well as via shared collections; trigger events; and interrupt execution of listeners. http://framework.zend.com/manual/2.0/en/modules/zend.event-manager.event-manager.html
  17. Foo.php (excerpt) 1. <?php 2. use ZendEventManagerEventCollection; 3. use ZendEventManagerEventManager;

    4. use ZendEventManagerEventManagerAware; 5. 6. class Foo implements EventManagerAware 7. { 8. protected $events; 9. 10. public function setEventManager(EventCollection $events) 11. { 12. $this->events = $events; 13. } 14. 15. public function getEventManager() 16. { 17. if (null === $this->events) { 18. $this->setEventManager(new EventManager()); 19. } 20. return $this->events; 21. } 22. 23. public function bar($baz, $bat = null) 24. { 25. $params = compact('baz', 'bat'); 26. $this->getEventManager()->trigger(__FUNCTION__, $this, $params); 27. } 28. }
  18. Log.php (excerpt) 1. <?php 2. use ZendLogFactory as LogFactory; 3.

    4. $log = LogFactory($someConfig); 5. $foo = new Foo(); 6. $foo->getEventManager()->attach('bar', function ($e) use ($log) { 7. $event = $e->getName(); 8. $target = get_class($e->getTarget()); 9. $params = json_encode($e->getParams()); 10. 11. $log->info(sprintf( 12. '%s called on %s, using params %s', 13. $event, 14. $target, 15. $params 16. )); 17. }); 18. 19. // Results in log message: 20. $foo->bar('baz', 'bat'); 21. // reading: bar called on Foo, using params {"baz" : "baz", "bat" : "bat"}"
  19. Eclipse ▪ Open source development platform ▪ Language: Java ▪

    Current Version: 4.2 ▪ Homepage: http://www.eclipse.org ▪ Extensions: 1423 (Marketplace) date 06.09.2012
  20. Extension Points "If a plug-in defines an extension points it

    allows other plug-ins to add functionality based on the contract defined by the extension point. The defining plug-in is also responsible for evaluating contributions to the defined extension point. Therefore the defining plug-in contains coding to evaluate the extensions." http://www.vogella.com/articles/EclipseExtensionPoint/article.html#extensionpoints
  21. plugin.xml (excerpt) 1. <plugin id="com.bolour.sample.eclipse.listener.subject" name="Sample Listener Subject" version="1.0.0" provider-name="Bolour

    Computing" class="com.bolour.sample.eclipse.listener.subject.Subject"> 2. <requires> 3. <import plugin="org.eclipse.ui" /> 4. </requires> 5. <extension-point id="listeners" name="Listeners" schema="schema/listeners.exsd" /> 6. </plugin> schema/listeners.exsd (excerpt) 1. <schema targetNamespace="com.bolour.sample.eclipse.listener.subject"> 2. <element name="extension"> 3. <complexType> 4. <sequence> 5. <element ref="listener" minOccurs="0" maxOccurs="unbounded" /> 6. </sequence> 7. </complexType> 8. </element> 9. <element name="listener"> 10. <complexType> 11. <attribute name="class" type="java" use="required" implements="com.bolour.sample. eclipse.listener.subject.IListener"/> 12. </complexType> 13. </element> 14. </schema>
  22. IListener.java (excerpt) 1. public interface IListener { 2. public void

    listen(); 3. } ExtensionPoint.java (excerpt) 1. private final Vector getListeners() { 2. List listeners = new ArrayList(); 3. IPluginRegistry registry = Platform.getPluginRegistry(); 4. IExtensionPoint extensionPoint = registry.getExtensionPoint(LISTENERS_EXTENSION_POINT); 5. IExtension[] extensions = extensionPoint.getExtensions(); 6. 7. for (int i = 0; i < extensions.length; i++) { 8. IConfigurationElement[] elements = extensions[i].getConfigurationElements(); 9. 10. for (int j = 0; j < elements.length; j++) { 11. IConfigurationElement configurationElement = elements[j]; 12. IListener listener = (IListener) configurationElement.createExecutableExtension("class"); 13. listeners.addElement(listener); 14. } 15. } 16. 17. return listeners; 18. }
  23. Extensions "A plug-in (which provides an Extension) adds a contribution

    (extension) to an existing extension point. Extensions to an extension point are defined in the plug-ins via the plugin.xml file. Contributions can be code or data." http://www.vogella.com/articles/EclipseExtensionPoint/article.html#extensionpoints
  24. plugin.xml (excerpt) 1. <plugin 2. id="com.bolour.sample.eclipse.listener.firstlistener" 3. name="First Listener Sample"

    4. provider-name="Bolour Computing" 5. version="1.0.0"> 6. <extension 7. id="listener.firstlistener" 8. name="FirstListener" 9. point="com.bolour.sample.eclipse.listener.subject.listeners"> 10. <listener 11. class="com.bolour.sample.eclipse.listener.firstlistener.ListenerX"> 12. </listener> 13. <listener 14. class="com.bolour.sample.eclipse.listener.firstlistener.ListenerY"> 15. </listener> 16. </extension> 17. </plugin>
  25. ListenerX.java (excerpt) 1. public class ListenerX implements IListener { 2.

    /** 3. * Trivial listener class: print out an information message to standard output. 4. */ 5. public void listen() { 6. System.out.println(this.getClass().getName() + " notified"); 7. } 8. } ListenerY.java (excerpt) 1. public class ListenerY implements IListener { 2. /** 3. * Trivial listener class: print out an information message to standard output. 4. */ 5. public void listen() { 6. System.out.println(this.getClass().getName() + " notified"); 7. } 8. }