Web-Shop-MDD

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


Diese Seite dokumentiert die Ergebnisse und den Fortschritt des Web-Shop-Projektes.

Beschreibung

Dieses Projekt ist im Sommersemester 2016 im Bereich der Modellgetriebene Softwareentwicklung in der Praxis entstanden. Auf dieser Seite werden die entstandenen Ergebnisse veröffentlicht. Es handelt sich hier um die Entwicklung einer Sprache und eines Generators mit Xtext, mit denen ein Web-Shop in ASP.NET generiert werden kann. Die generierte Anwendung soll responsiv sein und einen Web-Service bereitstellen.

Unterstützung

Wir bedanken uns als Team bei Dieudonne Timma Meyatchie für seine hilfreiche Unterstützung bei Fragen und Problemen die während der Entwicklung unseres Web-Shop-Generators aufgetreten sind.

Gruppe

Unsere Gruppe besteht aus 2 Personen:

  • Fidaim Jashari
  • Konstantin Müller

Projektablauf

Entwicklungsumgebung

Wir haben für unser Projekt als Entwicklungsumgebung Eclipse DSL Tools (Version Mars Release 4.5.0) verwendet.

Entwicklungsumgebung.png

Tag 1 (22.08.16)

Zuerst mussten wir eine Referenzanwendung finden. Als Referenzanwendung verwenden wir das Beispielprojekt von Erik Reitan, welches man unter folgendem Link [1] finden kann. Beim Ausführen des Projektes trat folgender Fehler auf: Die Datenbank, die beim Ausführen des Projektes erstellt wird konnte nicht gefunden werden, da der Pfad der erstellten Datei noch angegeben werden musste. Dafür kann im "Server Explorer" von Visual Studio mit einem Rechtsklick auf die Datenbank die Option "Modify Connection" gewählt werden. Dann kann unter "Attach a database file" der Pfad der erstellten Datenbank-Datei ausgewählt werden. Anschließend kann die Verbindung zu der Datenbank getestet werden. Der Fehler konnte somit behoben werden.

Fehler-Datenbank.png

Die folgenden Screenshots geben einen schnellen Überblick über die in ASP.NET erstellte Referenzanwendung. Wenn die Anwendung von Visual Studio ausgeführt wird, wird die folgende Homepage der Anwendung im Browser angezeigt:
Home.png

In der Anwedung kann ein neuer Benutzer registriert oder ein vorhandener Benutzer angemeldet werden. Über ein Menü können die Produktkategorien ausgewählt werden. Über den Link "Products" wird eine Liste aller verfügbaren Produkte angezeigt.

Produkte.png

Produkte die in den Warenkorb hinzugefügt wurden, können über den Link "Cart" aufgerufen werden.

Cart.png

Tag 2 (23.08.16)

Anhand der Referenz-Anwendung haben wir erstmal die Anwendungsanforderungen definiert.

Die Anwendungsanforderungen --- Unser Web-Shop enthält

  • Menü: Home, About, Contact, Products, Cart, Register, Login und
  • Untermenü: Cars, Planes, Trucks, Boats, Rockets. Jedes Menü enthält das Untermenü

Menü:

  • "Home" besteht aus einem Begrüßungstext und dem Untermenü.
  • "About" besteht aus einem Text, der die Anwendung beschreibt und dem Untermenü.
  • "Contact" besteht aus den Kontaktdaten und dem Untermenü.
  • "Products" besteht aus den angebotenen Produkten des Web-Shops und dem Untermenü. Jedes Produkt besteht wiederum aus drei Teilen: "Name" enthält die Beschreibung des Products, mit "Add to Cart" kann das Produkt zum Warenkorb hinzugefügt werden und "Price" enthält den Preis des Produktes.
  • "Cart" enthält die ausgewählten Produkte und das Untermenü. Jedes Produkt hat eine eigene Produktseite mit der Beschreibung und der Produktnummer.
  • "Register" besteht aus dem Untermenü und einem Formular (EMail, Passwort, ConfrimPasswort, RegisterButton)
  • "Login" besteht aus dem Untermenü und einem Formular (Email, Passwort, LoginButton)

Untermenü:
Das Untermenü enthält die Produkte, die in Kategorien (z.B. Cars, Planes, Trucks, usw.) aufgeteilt sind.
Nachdem wir unser Anforderungsmodell definiert haben, haben wir das Ecore-Modell dafür erstellt, das in der folgenden Abbildung zu sehen ist.

EDiagram.png

Der nächste Schritt war die Entwicklung der XTEXT Grammatik für unser Modell. Wir wollten die XTEXT Grammatik aus dem bestehenden Ecore-Modell generieren. Dabei tauchten jedoch unerwartete Fehler auf und wir haben uns dazu entschieden, die Grammatik selbst zu schreiben. In der folgenden Abbildung ist unser Ecore-Modell zu sehen.

EcoreModell.png

Unsere Grammatik sieht wie folgt aus:

Grammatik:

grammar org.xtext.example.webshop.WebShop with org.eclipse.xtext.common.Terminals

generate webShop "http://www.xtext.org/example/webshop/WebShop"

WebShop:
	'WebShop'
	'{'
		'Name' name=ID
		'Logopfad' logopfad=STRING
		'Faviconpfad' faviconpfad=STRING
		produkt+=Produkt ( "," produkt+=Produkt)*
		hauptmenue=Hauptmenue
		admin=Admin
	'}';
	
Admin:
	'Admin'
	'{'
		'Email' email=STRING
		'Passwort' passwort=STRING
	'}'
;

Produkt:
	'Produkt'
	'{'
		'Name' name=ID
		'Produktname' produktname=STRING
		'Preis' Preis=Double
		'KategorieID' kategorieid=INT
		'Bildpfad' bildpfad=STRING
		'Beschreibung' Beschreibung=STRING
	'}';

Hauptmenue:
	'Hauptmenue'
	'{'
		'Name' name=ID
		untermenue=Untermenue
		home=HomeSeite
		about=AboutSeite
		contact=ContactSeite
		products=ProductsSeite
		cartseite=CartSeite
		registerseite=RegisterSeite
		loginseite=LoginSeite
	'}';

HomeSeite:
	'HomeSeite'
	'{'
		'Begruessungstext' Begruessungstext=STRING
		'Ueberschrift' Ueberschrift=STRING
		'untermenue' untermenue=[Untermenue]
	'}';

AboutSeite:
	'AboutSeite'
	'{'
		'Anwendungsbeschreibung' Anwendungsbeschreibung=STRING
		'Ueberschrift' Ueberschrift=STRING
		'untermenue' untermenue=[Untermenue]
	'}';

ContactSeite:
	'ContactSeite'
	'{'
		'Name' Name=STRING
		'Strasse' Strasse=STRING
		'Ort' Ort=STRING
		'TelefonNr' Telefon=STRING
		'Email' Email+=STRING*
		'Ueberschrift' Ueberschrift=STRING
		'untermenue' untermenue=[Untermenue]
	'}';

ProductsSeite:
	'ProductsSeite'
	'{'
		'untermenue' untermenue=[Untermenue]
		'produkt' '(' produkt+=[Produkt] ( "," produkt+=[Produkt])* ')' 
	'}';

Untermenue:
	'Untermenue'
	'{'
		'Name' name=ID
		'produktkategorie' '{' produktkategorie+=Produktkategorie ( "," produktkategorie+=Produktkategorie)* '}' 
	'}';

CartSeite:
	'CartSeite'
	'{'
		'untermenue' untermenue=[Untermenue]
	'}';

RegisterSeite:
	'RegisterSeite'
	'{'
		'untermenue' untermenue=[Untermenue]
	'}';

LoginSeite:
	'LoginSeite'
	'{'
		'untermenue' untermenue=[Untermenue]
	'}';

Produktkategorie:
	'Produktkategorie'
	'{'
		'Name' name=ID
		'KategorieID' id=INT
		'produkt' '(' produkt+=[Produkt] ( "," produkt+=[Produkt])* ')' 
	'}';
	
Double:
	INT '.' INT
;


Als nächstes haben wir eine neue Eclipse-Instanz geöffnet, ein neues Projekt erstellt und darin ein Test-Modell basierend auf der Grammatik erstellt. Dieses Modell sieht wie folgt aus:
*x.webshop

WebShop
{
	Name TestShop
	Logopfad "C:/TestShop/logo.jpg"
	Faviconpfad ""
	Produkt
	{
		Name car1
		Produktname "Test Car"
		Preis 10.1
		KategorieID 1
		Bildpfad "C:/TestShop/car1.png"
		Beschreibung "Test"
	},
        Produkt
	{
		Name car2
		Produktname "Test Car2"
		Preis 10.1
		KategorieID 1
		Bildpfad "C:/TestShop/car2.png"
		Beschreibung "Test2"
	}
	Hauptmenue
	{
		Name haupt
		Untermenue
		{
			Name unter
			produktkategorie
			{
				Produktkategorie
				{
					Name Cars
					KategorieID 1
					produkt(car1, car2)
				}
			}
		}
		HomeSeite
		{
			Begruessungstext "Willkommen"
			Ueberschrift "Ueberschrift"
			untermenue unter
		}
		AboutSeite
		{
			Anwendungsbeschreibung "Anwendungsbeschreibung"
			Ueberschrift "Ueberschrift"
			untermenue unter
		}
		ContactSeite
		{
			Name "Hans Paul"
			Strasse "Teststrasse 2"
			Ort "35396 Giessen"
			TelefonNr "0641/12345"
			Email "test@test.com" "a@a.de" "b@b.net"
			Ueberschrift "Kontakt"
			untermenue unter
		}
		ProductsSeite
		{
			untermenue unter
			produkt(car1, car2)
		}
		CartSeite
		{
			untermenue unter
		}
		RegisterSeite
		{
			untermenue unter
		}
		LoginSeite
		{
			untermenue unter
		}
	}
	Admin
	{
		Email "test@test.de"
		Passwort "password"
	}
}



Der generierte DSL Editor sieht dann wie folgt aus:

DSLEditor.png

Tag 3 (24.08.16)

Am dritten Tag haben wir dann erstmal ein neues Projekt in ASP.NET erstellt, um herauszufinden, welche Dateien automatisch von Visual Studio erstellt werden. Wir haben zuerst nach einer Möglichkeit gesucht, um diese Dateien mit dem Generator von Visual Studio generieren zu lassen. Jedoch sind wir nicht fündig geworden und haben uns dann dazu entschieden, für jede einzelne Datei den Generator-Code selbst zu erstellen.
In der unten dargestellten Abbildung ist das neu erstellte Projekt und das Projekt unserer Referenz-Anwendung zu sehen.

Pr3.png

Die "WebShopGenerator.xtend"-Datei wurde ebenfalls erweitert. Den Code dafür werden wir am letzten Tag hinzufügen. Der folgende Code ist aus unserer "about.xtend"-Datei, die ein Template für die generierte About-Seite enthält.

package org.xtext.example.webshop.generator

import org.eclipse.xtext.generator.IFileSystemAccess2
import org.xtext.example.webshop.webShop.WebShop

class _AboutAspx {
	new(IFileSystemAccess2 fsa, WebShop e) {
		fsa.generateFile(e.name.toString() + "/" + e.name.toString() + "/About.aspx", e.compile)
	}
	
	def compile(WebShop w) '''
		<%@ Page Title="About" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="About.aspx.cs" Inherits="«w.name».About" %>
		
		<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
		    <h2><%: Title %>.</h2>
		    <h3>«w.hauptmenue.about.ueberschrift»</h3>
		    <p>«w.hauptmenue.about.anwendungsbeschreibung»</p>
		</asp:Content>
	'''
}

Tag 4 (25.08.16)

An Tag 3 hatten wir nur XTEND-Dateien für die Standard-Dateien, die beim Erstellen eines ASP.NET-Projektes generiert werden erstellt. Am vierten Tag wurden neue XTEND-Dateien, für die Dateien unseres Projektes erstellt. Als Beispiel folgt der Code unserer "Models_ProductDatabaseInitializerCs.xtend"-Datei, die eine Template für die C#-Datei enthält, mit der die Datenbank mit den im Modell angegebenen Daten erstellt.

package org.xtext.example.webshop.generator
import org.eclipse.xtext.generator.IFileSystemAccess2
import org.xtext.example.webshop.webShop.WebShop
class Models_ProductDatabaseInitializerCs {
	
	new (IFileSystemAccess2 fsa, WebShop e){
	fsa.generateFile(e.name.toString() + "/" + e.name.toString() +"/Models/ProductDatabaseInitializer.cs", e.compile)
}
	
	def compile(WebShop w) '''
	using System.Collections.Generic;
	using System.Data.Entity;
	
	namespace «w.name».Models
	{
	  public class ProductDatabaseInitializer : DropCreateDatabaseIfModelChanges<ProductContext>
	  {
	    protected override void Seed(ProductContext context)
	    {
	      GetCategories().ForEach(c => context.Categories.Add(c));
	      GetProducts().ForEach(p => context.Products.Add(p));
	    }
	
	    private static List<Category> GetCategories()
	    {
	    	var categories = new List<Category> {
	    	«FOR c:w.hauptmenue.untermenue.produktkategorie»
	    		new Category
	    		{
	    			CategoryID = «c.id»,
	    			CategoryName = "«c.name»"
	    		},
	    	«ENDFOR»
	    	};
	
	      return categories;
	    }
	
	    private static List<Product> GetProducts()
	    {
			var products = new List<Product> {
			«var i = 1»
			«FOR p:w.produkt»
			new Product
			{
				ProductID = «i++»,
				ProductName = "«p.produktname»",
				Description = "«p.beschreibung»", 
				ImagePath="«p.bildpfad.split("/").last»",
				UnitPrice = «p.preis»,
				CategoryID = «p.kategorieid»
			},
	      	«ENDFOR»
			};
	
	      return products;
	    }
	  }
	}
	'''
}

In der "GetCategories()"-Methode wird über alle im Modell angegebenen Produktkategorien iteriert. Eine Produktkategorie soll in der Datenbank eine ID und einen Namen haben.
In der "GetProducts()"-Methode wird über alle im Modell angegebenen Produkte iteriert. Ein Produkt hat in der Datenbank eine eindeutige ID, die hier mit Hilfe einer Variable angegeben wird, die in jeder Iteration hochgezählt wird. Zusätzlich haben Produkte noch einen Namen, eine Beschreibung, ein Bild, einen Preis und die KategorieID, zu der das Produkt zugeordnet werden soll. Für das Bild kann im Modell ein Pfad zu einer Datei angegeben werden. Das Bild wird dann im Generator mit der an Tag 5 vorgestellten Util-Klasse in das generierte ASP.NET-Projekt kopiert. Die "ProductDatabaseInitializer.cs"-Datei und somit auch die Daltenbank enthalten dann nur noch den Dateinamen, da alle Bilder in den Ordner "Images" des ASP.NET-Projekts kopiert werden.



Alle Dateien, die unverändert bleiben, haben wir in das Generator-Projekt in Eclipse kopiert. Diese Dateien werden beim Ausführen des Generators in das ASP.NET-Projekt kopiert. Auf dem folgenden Bild ist ein Beispiel zu sehen.
Pr4.png

Tag 5 (26.08.16)

Wir hatten vorher die unveränderten Dateien in das Generator-Projekt kopiert. Um den Pfad zu solchen Dateien zu bekommen haben wir die "Util.java"-Klasse erstellt.

package org.xtext.example.webshop.generator;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;

public class Util {
	
	public static String readFile(String path) {
		URL p = null;
		try {
			p = FileLocator.resolve(FileLocator.find(Platform.getBundle("org.xtext.example.webshop"), new Path("src/org/xtext/example/webshop/generator"), null));
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		try(BufferedReader r = Files.newBufferedReader(Paths.get(p.getPath().substring(1) + path), StandardCharsets.UTF_8)) {
			String line = null, result = "";
			while ((line = r.readLine()) != null) {
				result += line + "\n";
			}
			return result;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	public static InputStream readBytes(String path) {
		URL p = null;
		try {
			p = FileLocator.resolve(FileLocator.find(Platform.getBundle("org.xtext.example.webshop"), new Path("src/org/xtext/example/webshop/generator"), null));
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		return read(p.getPath().substring(1) + path);
	}
	
	public static InputStream read(String path) {
		try {
			return Files.newInputStream(Paths.get(path), StandardOpenOption.READ);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
}



Um Platform.getBundle aufrufen zu können, muss eine Variable im Build-Path des Projekts hinzugefügt werden, die den Pfad zur osgi.jar enthält:
BuildPath.png

Beim Generieren der Dateien unseres Projektes tauchten verschiedene Fehlern auf, wie bspw.:

  • Die Dateinamen waren Teilweise falsch
  • Für manche Dateien haben wir vergessen die Tempelates zu erstellen
  • Fehler bei der Template-Erstellung

Dadurch wurden manche Dateien nicht generiert.

Fehler1.png

Ein Visual Studio-Projekt enthält eine Projektdatei mit der Dateiendung ".csproj". Diese Datei enthält unter anderem die Dateinamen, die zum Projekt gehören und Referenzen zu Paketen, die für die Ausführung des Projekts benötigt werden. Es werden dabei auch die Versionsnummern dieser Pakete angegeben, wie in diesem Ausschnitt einer csproj-Datei zu sehen ist:

<Reference Include="EntityFramework">
        <HintPath>..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll</HintPath>
      </Reference>
      <Reference Include="EntityFramework.SqlServer">
        <HintPath>..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll</HintPath>
      </Reference>
      <Reference Include="Microsoft.AspNet.Identity.Core">
        <HintPath>..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
      </Reference>
      <Reference Include="Microsoft.AspNet.Identity.Owin">
        <HintPath>..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll</HintPath>
      </Reference>
      <Reference Include="Microsoft.AspNet.Identity.EntityFramework">
        <HintPath>..\packages\Microsoft.AspNet.Identity.EntityFramework.2.2.1\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll</HintPath>
</Reference>

Da unsere Referenzanwendung von 2014 ist, enthält die csproj-Datei ältere Versionsnummern für die Pakete. Das führte dazu, dass wir unser generiertes Projekt nicht ausführen konnten, weil die veralteten Pakete nicht gefunden werden konnten. Deswegen haben wir ein neues und aktuelles ASP.NET-Projekt erstellt und alle benötigten Dateien aus der Referenzanwendung in dieses neue Projekt kopiert. Somit sind alle Standard-Dateien auf dem aktuellsten Stand und die csproj-Datei enthält die aktuellsten Versionsnummern.


Web-Service

Da die Referenzanwendung keinen Web-Service enthielt, musste dieser erst noch entwickelt werden. Dazu wurde in Visual Studio eine .asmx-Datei:

<%@ WebService Language="C#" CodeBehind="ProductServices.asmx.cs" Class="TestShop.Logic.ProductServices" %>

und eine .asmx.cs-Datei erstellt:

using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web.Script.Serialization;
using System.Web.Services;
using TestShop.Models;

namespace TestShop.Logic
{
    /// <summary>
    /// Web services to query the database. All methods return JSON data.
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.Web.Script.Services.ScriptService]
    public class ProductServices : System.Web.Services.WebService
    {

        [WebMethod]
        public string GetProductsByName(string name)
        {
            ProductContext pc = new ProductContext();
            List<Product> l = pc.Products.Where(x => x.ProductName.Contains(name)).ToList();
            
            string[][] arr = new string[l.Count][];
            int i = 0;
            foreach(Product p in l)
            {
                arr[i] = new string[] { p.ProductID.ToString(), p.ProductName.ToString(), p.UnitPrice.ToString(), p.ImagePath.ToString(), p.Description.ToString(), p.CategoryID.ToString(), p.Category.CategoryName.ToString() };
                i++;
            }

            JavaScriptSerializer js = new JavaScriptSerializer();
            return js.Serialize(arr);
        }

        [WebMethod]
        public string GetCategoriesByName(string name)
        {
            ProductContext pc = new ProductContext();
            List<Category> l = pc.Categories.Where(x => x.CategoryName.Contains(name)).ToList();

            string[][] arr = new string[l.Count][];
            int i = 0, j = 1;
            string temp = "[";
            foreach (Category c in l)
            {
                foreach(Product p in c.Products)
                {
                    temp += p.toString();
                    if (j++ != c.Products.Count) temp += ",";
                }
                arr[i] = new string[] { c.CategoryID.ToString(), c.CategoryName.ToString(), (c.Description == null ? "" : c.Description.ToString()), (c.Products == null ? "" : temp + "]") };
                i++;
                temp = "[";
            }

            JavaScriptSerializer js = new JavaScriptSerializer();
            return js.Serialize(arr);
        }
    }
}

Die erste Methode gibt alle Produkte aus der Datenbank zurück, die im Produktnamen den eingegebenen String enthalten. Die zweite Methode gibt alle Kategorien mit ihren Produkten aus der Datenbank zurück, die im Kategorienamen den eingegebenen String enthalten. Beide Methoden geben die Daten im JSON-Format zurück. Als Beispiel wurde hier im generierten ASP.NET-Projekt aus dem Testmodell von Tag 2 der String "ca" angegeben und der Web-Service liefert dann folgendes:

<string>[["1","Test Car","10,1","car1.png","Test","1","Cars"],["2","Test Car2","10,1","car2.png","Test2","1","Cars"]]</string>

Das "string"-Tag wird mit ausgegeben, weil ASP.NET automatisch die Daten vom Web-Service im XML-Format zurückgibt und nicht im JSON-Format.

Beispiel-Modelle

Zum Schluss wurden noch zwei Beispiel-Modelle erstellt: Ein ComputerShop und ein HandyShop. Beide Modelle enthalten mehrere Kategorien und Produkte.

ComputerShop

Der ComputerShop enthält Prozessoren, Grafikkarten, Festplatten und Arbeitsspeicher:

WebShop
{
	Name ComputerShop
	Logopfad "C:/ComputerShop/logo.jpg"
	Faviconpfad "C:/ComputerShop/favicon.ico"
	
	//Prozessoren
	Produkt
	{
		Name proz1
		Produktname "Intel Core i7-6700K"
		Preis 338.0
		KategorieID 1
		Bildpfad "C:/ComputerShop/proz1.jpg"
		Beschreibung "Marke:	Intel, Artikelgewicht:	82 g, Produktabmessungen:	10 x 10 x 6 cm, Modellnummer:	BX80662I76700K, Prozessoranzahl:	4, Speicher-Art:	DDR3 SDRAM, Watt:	91 Watt"
	},
	Produkt
	{
		Name proz2
		Produktname "AMD FD8350FRHKBOX"
		Preis 166.90
		KategorieID 1
		Bildpfad "C:/ComputerShop/proz2.jpg"
		Beschreibung "Marke:	AMD, Modell/Serie:	8350, Artikelgewicht:	200 g, Produktabmessungen:	14 x 12,7 x 7,1 cm, Modellnummer:	FD8350FRHKBOX"
	},
	Produkt
	{
		Name proz3
		Produktname "AMD FX 4300"
		Preis 73.40
		KategorieID 1
		Bildpfad "C:/ComputerShop/proz3.jpg"
		Beschreibung "Marke:	AMD, Modell/Serie:	4300, Artikelgewicht:	322 g, Produktabmessungen:	14 x 12,7 x 7,1 cm, Modellnummer:	FD4300WMHKBOX, Prozessormarke:	Prozessorfamilie, Prozessorgeschwindigkeit:	3.8 GHz, Prozessorsockel: 	Socket AM3+, Prozessoranzahl:	4, Speicher-Art:	DDR3 SDRAM, Watt:	95 Watt"
	},
	
	//Grafikkarten
	Produkt
	{
		Name gra1
		Produktname "GIGABYTE GeForce GT 730"
		Preis 69.90
		KategorieID 2
		Bildpfad "C:/ComputerShop/gra1.jpg"
		Beschreibung "Chipsatz: GeForce GT 730 • Aktive Kuehlung: 80-mm-Luefter • Anschluesse: DVI-D (Dual-Link), HDMI, VGA, GPU-Takt: 902 MHz • Hardware-Schnittstelle: PCI-E 2.0 • Unterstuetzte Betriebssysteme: Windows XP/Vista/7/8/8.1/10 (je 32- und 64-Bit), Speichertakt: 5.000 MHz • Software-Schnittstellen: DirectX 12, OpenGL 4.4 • Maße: 177 x 120 x 30 mm, Speicher: 2 GB GDDR5, 64-Bit-Anbindung • Maximale Aufloesung (digital): 4096 x 2160 (4K) • Grafikkarte inkl. Treiber-CD und Anleitung, Bitte beachten Sie: Ihr PC sollte fuer den Betrieb dieser Grafikkarte ueber ein Netzteil mit mindestens 300 Watt Leistung verfuegen."
	},
	Produkt
	{
		Name gra2
		Produktname "Sapphire ATI Radeon HD5450"
		Preis 37.50
		KategorieID 2
		Bildpfad "C:/ComputerShop/gra2.jpg"
		Beschreibung "Schnittstellen Typ: PCI Express 2.1 x16, Art: Plug-in-Karte - Low Profile, Geraetetyp: Grafikadapter"
	},
	Produkt
	{
		Name gra3
		Produktname "Asus Nvidia GeForce GTX750TI-OC-2GD5"
		Preis 134.14
		KategorieID 2
		Bildpfad "C:/ComputerShop/gra3.jpg"
		Beschreibung "Stil: GTX750 Grafikkarte, Doppelte Luefter fuer doppelten Airflow bei nur einem Drittel Geraeuschemission, 1150 MHz Engine Clock fuer maximale Leistung, Premium Legierung an den Leistungskomponenten leiten Waerme um 15% schneller ab und verlaengern die Lebensdauer, Per GPU Tweak lassen sich Taktung, Spannung und Lueftergeschwindigkeiten einfach und komfortabel einstellen, Lieferumfang: Asus GTX750TI OC Nvidia GeForce Grafikkarte"
	},
	
	//Festplatten
	Produkt
	{
		Name fes1
		Produktname "Toshiba Canvio Basics 1 TB extern"
		Preis 53.78
		KategorieID 3
		Bildpfad "C:/ComputerShop/fes1.jpg"
		Beschreibung "Externe 2,5 Zoll Festplatte, 1 TB Kapazitaet, USB 3.0-Highspeed-Port, Lieferumfang: Toshiba Canvio Basics 1 TB Mobile Festplatte schwarz, USB 3.0-Kabel(Micro-B), Kurzanleitung, Benutzerhandbuch (auf der Festplatte vorinstalliert), Garantieunterlagen"
	},
	Produkt
	{
		Name fes2
		Produktname "WD Blue WD10EZEX 1 TB Intern"
		Preis 52.77
		KategorieID 3
		Bildpfad "C:/ComputerShop/fes2.jpg"
		Beschreibung "WD Desktop Blue WD10EZEX 1TB, SATA 6Gb/s 64MB Cache Internal, 8,9cm 3,5Zoll Desktop HDD 7200rpm Bulk"
	},
	Produkt
	{
		Name fes3
		Produktname "Western Digital 1TB Elements extern"
		Preis 59.62
		KategorieID 3
		Bildpfad "C:/ComputerShop/fes3.jpg"
		Beschreibung "Ultraschnelle Datentransfers mit USB 3.0, Enorme Speicherkapazitaet, Kostenlose Testversion der Software WD SmartWare Pro fuer automatische und Cloud Datensicherung, Fuer Festplatten mit einer maximalen Groeße von ca. 13,2 x 10,5 x 3,8 cm (5,19 x 4,13 x 1,49 Zoll), Kompaktes Gehaeuse zum Transport kleinerer tragbarer Festplatten"
	},
	
	//Arbeitsspeicher
	Produkt
	{
		Name arb1
		Produktname "HyperX Savage HX316C9SRK2"
		Preis 90.89
		KategorieID 4
		Bildpfad "C:/ComputerShop/arb1.jpg"
		Beschreibung "2x8GB Hyper X Savage, 1600MHz Geschwindigkeit, CAS-Latenz CL9, DDR3-RAM, Lieferumfang: Kingston HX316C9SRK2/16 Arbeitsspeicher 16GB (1600MHz, CL9) DDR3-RAM Kit"
	},
	Produkt
	{
		Name arb2
		Produktname "Ballistix Sport 8GB Kit DDR3"
		Preis 36.90
		KategorieID 4
		Bildpfad "C:/ComputerShop/arb2.jpg"
		Beschreibung "Arbeitsspeicher: 2 x 4GB, Technische Daten: DDR3 PC3-12800, Geschwindigkeit: bis zu 1600MHz; Spannung: 1.5V, Lieferumfang: Crucial BLS2CP4G3D1609DS1S00CEU Arbeitsspeicher, 2x4GB Arbeitsspeicher, 1600MHz Geschwindigkeit"
	},
	Produkt
	{
		Name arb3
		Produktname "HyperX Fury HX318C10FBK2"
		Preis 76.94
		KategorieID 4
		Bildpfad "C:/ComputerShop/arb3.jpg"
		Beschreibung "16 GB Arbeitsspeicher, 1866MHz Geschwindigkeit, CAS-Latenz CL10, DDR3-RAM, Lieferumfang: Kingston HX318C10FBK2/16 HyperX Fury Arbeitsspeicher 16GB (1866MHz, CL10, 2x 8GB) DDR3-RAM Kit schwarz"
	}
	
	Hauptmenue
	{
		Name haupt
		Untermenue
		{
			Name unter
			produktkategorie
			{
				Produktkategorie
				{
					Name Prozessoren
					KategorieID 1
					produkt(proz1, proz2, proz3)
				},
				Produktkategorie
				{
					Name Grafikkarten
					KategorieID 2
					produkt(gra1, gra2, gra3)
				},
				Produktkategorie
				{
					Name Festplatten
					KategorieID 3
					produkt(fes1, fes2, fes3)
				},
				Produktkategorie
				{
					Name Arbeitsspeicher
					KategorieID 4
					produkt(arb1, arb2, arb3)
				}
			}
		}
		HomeSeite
		{
			Begruessungstext "Kostenloser Versand - Top Kundenbewertungen - Markenkomponenten - 3 Jahre Garantie"
			Ueberschrift "Willkommen!"
			untermenue unter
		}
		AboutSeite
		{
			Anwendungsbeschreibung "Unser Anspruch und dauerhaftes Ziel ist es, Ihnen jederzeit PC-Hardware zum besten Preis-/Leistungsverhaeltnis anzubieten."
			Ueberschrift "Qualitaet und Innovation muss bezahlbar sein"
			untermenue unter
		}
		ContactSeite
		{
			Name "ComputerShop GmbH & Co. KG"
			Strasse "Teststrasse 2"
			Ort "35396 Giessen"
			TelefonNr "0641/12345"
			Email "test@test.com"
			Ueberschrift "Kontakt"
			untermenue unter
		}
		ProductsSeite
		{
			untermenue unter
			produkt(proz1, proz2, proz3, gra1, gra2, gra3, fes1, fes2, fes3, arb1, arb2, arb3)
		}
		CartSeite
		{
			untermenue unter
		}
		RegisterSeite
		{
			untermenue unter
		}
		LoginSeite
		{
			untermenue unter
		}
	}
	Admin
	{
		Email "test@test.de"
		Passwort "password"
	}
}

Die Produktseite des ComputerShops ist auf folgender Abbildung zu sehen: ComputershopProdukte.png

HandyShop

Der HandyShop enthält Smartphones und Zubehör:

WebShop
{
	Name HandyShop 
	Logopfad "C:/HandyShop/logo.png"
	Faviconpfad ""
	Produkt
	{
		Name SamsungGalaxyS7
		Produktname "Samsung Galaxy S7"
		Preis 700.1
		KategorieID 1
		Bildpfad "C:/HandyShop/galaxys7.png"
		Beschreibung "Samsung Galaxy S7 - 32GB"
	},
	Produkt
	{
		Name iPhone6
		Produktname "iPhone 6"
		Preis 600.1
		KategorieID 1
		Bildpfad "C:/HandyShop/iphone6silver.png"
		Beschreibung "iPhone 6 - 16GB (Simlockfrei)"
	},
	Produkt
	{
		Name iPhone5S
		Produktname "iPhone 5S"
		Preis 390.1
		KategorieID 1
		Bildpfad "C:/HandyShop/iphone5sgold.jpg"
		Beschreibung "iPhone 5S - 64GB (Simlockfrei)"
	},
	Produkt
	{
		Name iPhoneLadekabel
		Produktname "Ladekabel fuer iPhone"
		Preis 10.1
		KategorieID 2
		Bildpfad "C:/HandyShop/ladekabel.jpg"
		Beschreibung "Ladekabel fuer Original iPhone"
	},
	Produkt
	{
		Name SamsungKopfhoerer
		Produktname "Kopfhoerer fuer Samsung"
		Preis 10.1
		KategorieID 2
		Bildpfad "C:/HandyShop/kopfhoerer.jpg"
		Beschreibung "Kopfhoerer fuer Original Samsung"
	},
	Produkt
	{
		Name SamsungDockingStation
		Produktname "Docking Station fuer Samsung"
		Preis 59.1
		KategorieID 2
		Bildpfad "C:/HandyShop/SamsungDockingstation.jpg"
		Beschreibung "Docking Station fuer Original Samsung"
	}
	
	Hauptmenue
	{
		Name haupt
		Untermenue
		{
			Name unter
			produktkategorie
			{
				Produktkategorie
				{
					Name Smartphone
					KategorieID 1
					produkt(SamsungGalaxyS7, iPhone6, iPhone5S) 
				},
				Produktkategorie
				{
					Name Zubehoer
					KategorieID 2
					produkt(iPhoneLadekabel, SamsungKopfhoerer, SamsungDockingStation)
				}
			}
		}
		HomeSeite
		{
			Begruessungstext "Lernen Sie mit Handyshop einen kompetenten Partner fuer Mobilfunk kennen und testen Sie unseren Service mit einer bequemen Online Bestellung! Wir fuehren aktuelle Smartphones und Zubehoer der Hersteller Apple und Samsung im Online Shop."
			Ueberschrift "Willkommen"
			untermenue unter
		}
		AboutSeite
		{
			Anwendungsbeschreibung "Handyshop ist seit 2001 im Mobilfunkgeschaeft. Bei uns gelangen Sie ueber einen individuellen Handyvergleich, verschiedene Suchfunktionen und Produktkategorien schnell und bequem zum gewuenschten Top Angebot. In der Handytarife uebersicht werden alle angebotenen Tarife in uebersichtlicher Form gelistet und ermoeglichen einen direkten Tarifvergleich.Wer bereits weiß, welches Handy oder Smartphone gekauft werden soll, kann sich jeweils den besten Handyvertrag anzeigen lassen und ueber den Tarifvergleich mit anderen Angeboten, z.B. Handy Bundles, das guenstigste Angebot finden.(Text kopiert von Handyshop-24.com)."
			Ueberschrift "HandyShop"
			untermenue unter
		}
		ContactSeite
		{
			Name "Fidaim J."
			Strasse "Teststrasse 1"
			Ort "35396 Giessen"
			TelefonNr "0641/2345"
			Email "test@test.com" "a@a.de" "b@b.net"
			Ueberschrift "Kontakt"
			untermenue unter
		}
		ProductsSeite
		{
			untermenue unter
			produkt(SamsungGalaxyS7, iPhone6, iPhone5S, iPhoneLadekabel, SamsungKopfhoerer,SamsungDockingStation)
		}
		CartSeite
		{
			untermenue unter
		}
		RegisterSeite
		{
			untermenue unter
		}
		LoginSeite
		{
			untermenue unter
		}
	}
	Admin
	{
		Email "test@test.de"
		Passwort "password"
	}
}

Die Produktseite des HandyShops ist auf folgender Abbildung zu sehen:
Produkt.png