Browser-Extension-Plugin

Aus THM-Wiki
Wechseln zu: Navigation, Suche
Kurs
Kursname Modellgetriebene Softwareentwicklung in der Praxis SS 16
Kurstyp Praktikum
Dozent Priefer
Semester SS 16
Studiengang Master Informatik
Link http://homepages.thm.de/~dprf53/lehre.html



Beschreibung

Im Laufe des Modules „Modelgetriebene Softwareentwicklung in der Praxis“ im Sommersemester 2016 sollte ein Abschlussprojekt angefertigt werden. Wir haben uns für einen Browser-Extension-Generator entschieden, welcher ein Grundgerüst für drei verschiedene Browser Erweiterungen (Mozilla Firefox, Microsoft Edge, Google Chrome) generiert.

Gruppe

Die Gruppe besteht aus den folgenden drei Studenten:

  • Timo Martin
  • Artjom Büchert
  • Patrick Puzik

Entwicklungsumgebung und Tools

Eclipse

Bei der hier verwendeten Entwicklungsumgebung wurde Eclipse Neon gewählt, da wir im Laufe der Vorlesung diese schon eingerichtet wurde.

Eclipse screenshot.jpg

Git

Für die Versionsverwaltung wurde Git gewählt, damit jedes Gruppenmitglied seinen eigenen Branch erstellen konnte, um selbstständig und unabhängig arbeiten zu können.

BEG git repo.png

Xtext

Um die Regeln für die domänenspezifische Sprache festzulegen, wurde das Open-Source-Framework „Xtext“ gewählt. Xtext bietet außerdem eine Generierung für ein Metamodell und eine Editor-View mit Syntax-Highlitghting.

Projektablauf

Um eine klare Struktur in den Projektablauf zu bringen, wurden kleinere Ziele erstellt, welche nacheinander abgearbeitet wurden.

Tag 1 (22.08.16)

Anfangs haben wir nach einer Referenz-Anwendung für unser Projekt gesucht, sind dabei aber nur teilweise fündig geworden. Wir konnten keine Anwendung ausmachen die unseren Anforderungen entsprach. Stattdessen fanden wir seperate Generatoren für jeden einzelnen Browser. Nachdem wir diese dann gesichtet haben entschieden wir uns einen Anwendung from Scratch zu erstellen. Um dies zu bewerkstelligen mussten wir uns mit der Struktur eines Browserplugins vertraut machen welche in der folgenden Abbildung zu sehen ist.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Um mit unserem Projekt starten zu können mussten wir in Erfahrung bringen welche Mindestanforderungen nötig sind um eine Extension zu erstellen. Bei dieser Recherche kam heraus, dass nur eine Manifest Datei im JSON Format nötig ist, um solch eine Extension zu installieren. Die folgende Tabelle zeigt, welche Manifest Informationen nötig sind, um eine Extension im jeweiligen Browser zu installieren.

Manifest_Attribute Mozilla Firefox Google Chrome Microsoft Edge
name
description
version
author
manifest_version

Solch eine Extension, welche aus nur einer Manifest Datei besteht, enthält allerdings keine Anzeige und keine Funktionen.

Tag 2 (23.08.16)

Nachdem die Struktur und die Mindestanforderungen einer Browser-Extension ermittelt wurden war das anschließende Ziel nun ,die Regeln der DSL in Zukunft so einfach wie möglich zu erweitern, da viele Manifest Informationen zur Verfügung stehen. Ein weiteres Problem war, dass es viele Manifest Informationen in einem Browser existieren, aber in den anderen Browsern nicht. Wir haben uns dabei entschieden nur die Informationen zu implementieren, welche in allen drei Browsern gleich sind. Die erste Version der Regelmodellierung enthielt wie oben beschrieben nur die nötigen Informationen um eine Extension zu installieren und sah dabei so aus:

grammar de.xtext.thm.mdd.Beg with org.eclipse.xtext.common.Terminals

generate beg "http://www.xtext.de/thm/mdd/Beg"

Model: 
	extension = Extension;

Extension:
	required  = Required
	optional += Optional*
;

Required:
	'name'        '=' name        = STRING
	'version'     '=' version     = STRING
	'author'      '=' author      = STRING
	'description' '=' description = STRING
;

Der hier verwendete Entwurf zeigt, dass es in der Regel „Extension“ nur ein Feld existiert, welche alle benötigen Informationen in eine Manifest Datei implementiert, um eine Extension zu installieren.


Generator

Der Generator soll letztendlich die eingegebene Projektstruktur und Dateien generieren. Das folgende Bild zeigt ein Klassendiagramm, wie er implementiert wurde.

BEG uml.png

Die Oberklasse „BrowserExtension“ dient hier zur Generierung der Metainformationen für jeden Browser, da wir wie oben erwähnt nur Informationen implementieren, welche für alle drei Browser existieren. Die Unterklassen „ChromeExtension“, „EdgeExtension“ und „FirefoxExstension“ generieren die Ordnerstruktur und alle anderen Dateien, welche in der Manifestdatei definiert wurden. Das folgende Codebeispiel zeigt einen der drei erstellten Generatoren.

package de.xtext.thm.mdd.generator.extensions

import de.xtext.thm.mdd.beg.Extension
import org.eclipse.xtext.generator.IFileSystemAccess2

public class ChromeExtension extends BrowserExtension {

	new(Extension ext, IFileSystemAccess2 fsa) {
		super(ext,fsa);
	}
	
	public override void generateExtension(){
		fsa.generateFile("chrome/manifest.json",generateManifest);
		
	}

	override def generateManifest() '''
		
		{
			"manifest_version": 2,
			"name": «ext.name»,
			"description": «ext.desc»,
			"version": «ext.version»,
			
		}
		
	'''
}


Abstrakte Klasse

Da die Extensions der verschiedenen Browser auch über einige Gemeinsamkeiten verfügen, wurde eine abstrakte Klasse implementiert um Redundanzen vorzubeugen.

package de.xtext.thm.mdd.generator.extensions

import org.eclipse.xtext.generator.IFileSystemAccess2
import de.xtext.thm.mdd.beg.Extension
abstract class BrowserExtension {
	
	protected Extension ext;
	protected IFileSystemAccess2 fsa;
	
	new (Extension ext, IFileSystemAccess2 fsa){
		this.ext = ext;
		this.fsa = fsa;
	}
	
	abstract def void generateExtension();
	
	protected def generateManifest()''''''
	
}

Tag 3 (24.08.16)

Das folgende Bild zeigt eine Erweiterung der Sprachregeln. Da die Mindestanforderungen im "Required" Feld definiert wurde, können nun optionale Eigenschaften wie z.B. BrowserActions oder Icons implementiert bzw. eingefügt werden.

grammar de.xtext.thm.mdd.Beg with org.eclipse.xtext.common.Terminals

generate beg "http://www.xtext.de/thm/mdd/Beg"

Model: 
	extension=Extension;

Extension:
	required=Required
	optional+=Optional*
;

Required:
	'name' '=' name=STRING
	'version' '=' version=STRING
	'author' '=' author=STRING
	'description' '=' description=STRING
;

Optional:
	Action|Icons
;

Icons:
	'icons' '{'
		'size' size=STRING
		'filename' filename=STRING
	'}'
;


Action:
	(BrowserAction | PageAction)
;

BrowserAction:
	'browser_action' '{'
	icons+=Icon+
	('title' title=STRING)?
	(popup=Popup)?
	'}'
;

PageAction:
	'page_action' '{'
	icons+=Icon+
	('title'title=STRING)?
	(popup=Popup)?
	'}'
;

Icon:
	'icon' '{'
	'size' size=STRING
	'filename' filename=STRING
	'}'	
;

Popup:
	'popup' filename=STRING
;

Tag 4 (25.08.16)

Da wir einige Dateipfade haben und diese eine bestimmten Dateityp haben müssen, haben wir eine Validierung für die eingegebenen Dateipfade erstellt. Damit in dem Modeleditor sofort eine Fehlermeldung auftaucht.

Validatorquellcode.png

Im Editor wird dann eine Fehlermeldung angezeigt, falls der Dateityp nicht der Vorgabe entspricht.

ValidatorTooltip.png

Spracherweitetung:


grammar de.xtext.thm.mdd.Beg with org.eclipse.xtext.common.Terminals

generate beg "http://www.xtext.de/thm/mdd/Beg"

Model: 
	extension=Extension;

Extension:
	required=Required
	optional+=Optional*
;

Required:
	'name' '=' name=STRING
	'version' '=' version=STRING
	'author' '=' author=STRING
	'description' '=' description=STRING
;

Optional:
	Action|Icons|Background|ContentScript|Permissions
;

Icons:
	'icons' '{'
		icons+=Icon+
	'}'
;

Icon:
	'size' size=STRING
	'filename' filename=STRING
;

Action:
	(BrowserAction | PageAction)
;

BrowserAction:
	'browser_action' '{'
	icons+=ActionIcons+
	('title' title=STRING)?
	(popup=Popup)?
	'}'
;

PageAction:
	'page_action' '{'
	icons+=ActionIcons+
	('title'title=STRING)?
	(popup=Popup)?
	'}'
;

ActionIcons:
	'icon' '{'
	'size' size=STRING
	'filename' filename=STRING
	'}'	
;

Popup:
	'popup' filename=STRING
;

Background:
	'persistent' persistent?=
	'background' 'script' (script+=STRING)+ | ('page' page=STRING)
;

ContentScript:
	'content_script' contents+=Content+
;

Content:
	 ('matches' (matches+=STRING+)) ('scripts' (script+=STRING+))? ('stylesheets' (stylesheet+=STRING+))?
;

Permissions:
	'permissions' '{'
		permission+=Permission+
	'}'
;

Permission:
	Host_permission | API_permission
;

Host_permission:
	url = STRING
;

API_permission: 
	api_permission = api
;

enum api:
	activeTab = "activeTab" |
	alarms = "alarms" |
	bookmarks = "bookmarks" |
	contextMenus = "contextMenu"|
	cookies = "cookies"|
	downloads = "downloads" |
	downloads_open = "downloads.open" |
	idle = "idle"|
	notifications = "noifications" |
	storage = "storage"|
	tabs = "tabs"|
	webNavigation = "webNavigation"|
	webRequest = "webRequest"|
	webRequestBlocking = "webRequestBlocking"
;

Extensions brauchen für bestimmte Funktionen, bestimmte Rechte. Diese müssen vorher in der Manifest angegeben werden. Diese wurden in die Sprache integriert. Beispiel Extension: Demo ext details permissions.png

Tag 5 (26.08.16)

Dieses Bild zeigt eine weitere Erweiterung der Sprachregeln. Zum einen wurde eine "Feature-Regel" hinzugefügt, welche es ermöglicht, verschiedene Templates in die Extension zu laden, wie z.B. Feedback oder Donations. Desweiteren dient die Regel "DemoExtension" zum Fertigen einer fertigen Extension, die zur Präsentation des Modules benutzt wird.

grammar de.xtext.thm.mdd.Beg with org.eclipse.xtext.common.Terminals

generate beg "http://www.xtext.de/thm/mdd/Beg"

Model: 
	extension=Extension;

Extension:
	required=Required
	optional+=Optional*
	features+=Features*
	demo=DemoExtension?
;

Required:
	'name' '=' name=STRING
	'version' '=' version=STRING
	'author' '=' author=STRING
	'description' '=' description=STRING
;

Optional:
	Action|Icons|Background|ContentScript|Permissions
;

Icons:
	'icons' '{'
		icons+=Icon+
	'}'
;

Icon:
	'size' size=STRING
	'filename' filename=STRING
;

Action:
	(BrowserAction | PageAction)
;

BrowserAction:
	'browser_action' '{'
	icons+=ActionIcons+
	('title' title=STRING)?
	(popup=Popup)?
	'}'
;

PageAction:
	'page_action' '{'
	icons+=ActionIcons+
	('title'title=STRING)?
	(popup=Popup)?
	'}'
;

ActionIcons:
	'icon' '{'
	'size' size=STRING
	'filename' filename=STRING
	'}'	
;

Popup:
	'popup' filename=STRING
;

Background: 
	'persistent' persistent?=
	'background' 'script' (script+=STRING)+ | ('page' page=STRING)
;

ContentScript:
	'content_script' '{' contents+=Content+ '}'
;

Content:
	 ('matches' (matches+=STRING+)) ('scripts' (script+=STRING+))? ('stylesheets' (stylesheet+=STRING+))?
;

Permissions:
	'permissions' '{'
		permission+=Permission+
	'}'
;

Permission:
	Host_permission | API_permission
;

Host_permission:
	url = STRING
;

API_permission: 
	api_permission = api
;

enum api:
	activeTab = "activeTab" |
	alarms = "alarms" |
	bookmarks = "bookmarks" |
	contextMenus = "contextMenu"|
	cookies = "cookies"|
	downloads = "downloads" |
	idle = "idle"|
	notifications = "notifications" |
	storage = "storage"|
	tabs = "tabs"|
	webNavigation = "webNavigation"|
	webRequest = "webRequest"|
	webRequestBlocking = "webRequestBlocking"
;

Features:
	Components | Implementation
;

Components:
'addFeatures' '{' features+=extFeature+ '}'
;

Implementation:
	'addFunction' '{' impl=STRING '}'
;

enum extFeature:
	donations = "donations" |
	feedback = "feedback" | 
	contact = 'contact'
;

DemoExtension:
	'Analyser' '{'
	'name' name=STRING
	'description' desc=STRING
	'version' version=STRING
	'icon' icon=STRING
	'}'
;

Ein Beispiel defnition einer Extension:

Demo extension model definition.png

Aus der oberen Definition wird die foldenge Dateistruktur erstellt:

Demo ext generated file structure.png

Fazit

Die Veranstaltung "Modellgetriebene Softwareentwicklung in der Praxis" hat viele neue Aspekte, Tools und Probleme bei der Entwicklung von Software aufgezeigt. Durch die erstellung Domainspezifischer Sprachen musste man sich mit dem Projekt und der Problemstellung ganz anders auseinandersetzen als man es sonst von der klassischen Softwareentwicklung gewohnt ist. Nach der Einarbeitung stellt man aber schnell fest, wo die Probleme, aber auch die Möglichkeiten der Modellgetriebenen SW Entwicklung liegen. Eine Sprache zu definieren, die eine bestimmte Anwendung so beschreibt, dass alle Funktionen abgedeckt werden können, war eine neue Herausforderung. In unserem Projekt konnte keine einheitliche Sprache gefunden werden die eine "Generische Browser Extension" beschreibt, die nicht nur Templates bereitstellt. Durch die unterschiedlichen Funktionalitäten der Browser und der Mächtigkeit der jeweiligen API, war es nicht möglich auf Modelebene eine sinnvolle Sprache zu entwickeln. Die meiste Arbeit wurde im dem Generator gemacht und die jeweiligen unterschiede der Browser APIs angepasst. Das Model wurde dazu wenig genutzt.

Auf der anderen Seite stellt der Generator eine (halb) zentrale Stelle für die Entwicklung der Extensions da. Nur halb Zentral, weil die jeweiligen Extensions einen eigenen Generator brauchen und nur bestimmte Teile in einen gemeinsamen Generator ausgelagert werden können.

Der MDD Ansatz ist aber nicht komplett ungeeignet für die Extension Entwicklung. Wenn man die Modelierung und Generierung der Extensions auf Komponenten beschränkt, kann man Grundfunktionalitäten für alle Browser generieren und sich so die Arbeit vereinfachen/beschleunigen. Bsp.: Basiskomponenten einer Extension: Ein Kontaktformular, eine Donationseite, ein Feedbackbogen, Aboutseiten etc. Diese Komponenten können gut mittels MDD erstellt werden und in allen Extensions verwendet werden. Diese müssen allerdings immer etwas per Hand/im Generator angepasst werden, damit diese gleich oder ähnlich in jedem Browser aussehen/verhalten.

Das Gesamtfazit für unser Projekt ist, dass MDD nur bedingt Vorteile zur "normalen" Entwicklung bringt. Da die gleiche Funktionalität der Extensions auf verschiedenen Browsers nur teilweise garantiert werden kann. Zur Erstellung von Templates oder Basiskomponenten eignet sich MDD allerdings ganz gut, falls man es schon kann und nicht neu lernen muss.

Beispiel

Popup:

Demo ext analyzer popup.png

Nach "Klick-Event:"

Demo ext analyzer opened.png