Beslutsstöd för prissättning till webbutik Projektrapport



Relevanta dokument
Det här dokumentet är till för att ge en översikt över ASP.NET MVC samt hur WCF Services används från.net applikationer.

Gränssnitt för FakeGranska. Lars Mattsson

Introduktion Schenker-BTL AB, Stab IT Beskrivning över informationsintegreringmed Schenker, metodbeskrivning version 1.

Programutvecklingsprojekt Projektgrupp Elvin. Detailed Design Document

Introduktion till integrering av Schenkers e-tjänster. Version 2.0

Slutrapport. APFy.me

Grafiska användargränssnitt i Java

TDDC30 Programmering i Java, Datastrukturer och Algoritmer Lektion 5. Laboration 4 Lådplanering Exempel på grafik, ett avancerat program Frågor

Grafiska användargränssnitt i Java

Vad är molnet? Vad är NAV i molnet? Vem passar NAV i molnet för? Fördelar med NAV i molnet Kom igång snabbt...

Mina listor. En Android-applikation. Rickard Karlsson Rickard Karlsson - rk222cu Linnéuniversitet rk222cu@student.lnu.

Model View Controller. Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

TUTORIAL: KLASSER & OBJEKT

Medieteknologi Webbprogrammering och databaser MEB725, 5p (7,5 ECTS) Klientprogrammering JavaScript Program på flera sidor

PROJEKTRAPPORT EDA095 NÄTVERKSPROGRAMMERI

725G61 - Laboration 7 Implementation av ett API. Johan Falkenjack

Projekt Rapport. RaidPlanner. Jeanette Karlsson UD10

Instruktioner för uppdatering från Ethiris 4.10 till 5.x

Projektrapport EDA095

Inlämningsarbete Case. Innehåll Bakgrund bedömning inlämningsarbete... 2 Inlämnade arbeten... 4

Webbtjänster med API er

Nyheter i. Solen ORBIT 6.7

Tjoho. Applikationsutvecklarens handledning. Maj 2003

Objektorienterad Programkonstruktion

Webbserverprogrammering

Classes och Interfaces, Objects och References, Initialization

Bakgrund och motivation. Definition av algoritmer Beskrivningssätt Algoritmanalys. Algoritmer. Lars Larsson VT Lars Larsson Algoritmer 1

Utveckling av ett grafiskt användargränssnitt

Vanliga frågor för VoiceXpress

Inlämningsuppgift : Finn. 2D1418 Språkteknologi. Christoffer Sabel E-post: csabel@kth.se 1

Frakt och webbutiksinställningar

TMP Consulting - tjänster för företag

PROGRAMMERINGSTEKNIK TIN212

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 11 Jonas Lindgren, Institutionen för Datavetenskap, LiU

SLUTRAPPORT RUNE TENNESMED WEBBSHOP

Klient/server. Översikt. Lektion 1: Webbtekniker från Microsoft. Webbteknik från Microsoft. Klient/server. Designmönster. Utrullning.

SQLs delar. Idag. Att utplåna en databas. Skapa en databas

INNEHÅLL. Konfigurering av SQL Server. Egenskaper Kommunikationsprotokoll

Kort om World Wide Web (webben)

Quick start manual. Smart-House Rev 1.1

Med koppling till EmiWeb

IT för personligt arbete F2

ADO.NET Murach Kapitel 17-20

Tillämpad programmering CASE 1: HTML. Ditt namn

WebbSMS från datorn. Innehållsförteckning

Quickstart manual. Rev SHTOOL Quickstart manual Smart-House

Samlingar, Gränssitt och Programkonstruktion! Förelasning 11!! TDA540 Objektorienterad Programmering!

Slutrapport för Internetfonden

TUTORIAL: SAMLING & KONSOLL

Laboration 2: Designmönster

Metoder för verifiering av användare i ELMS 1.1

Instruktioner för uppdatering från Ethiris 5.x till 6.0

FLEX Personalsystem. Uppdateringsanvisning

Teoretisk del. Facit Tentamen TDDC kl (6) 1. (6p) "Snabba frågor" Alla svar motiveras väl.

Manual HSB Webb brf

Federerad Roll Administration ÄR GROUPER EN MEDSPELARE? OVE OLANDER MITTUNIVERSITETET

Arv. Fundamental objekt-orienterad teknik. arv i Java modifieraren protected Lägga till och modifiera metoder med hjälp av arv Klass hierarkier

TDDE44 Programmering, grundkurs

Proj-Iteration1. Arkitektur alt. 1

Web Services. Cognitude 1

Creo Customization. Lars Björs

Telia Touchpoint mobil växellösning

Introduktion till MySQL

FrontPage Express. Ämne: Datorkunskap (Internet) Handledare: Thomas Granhäll

Laboration 2: Designmönster

Christer Scheja TAC AB

Webbtillgänglighet. Webbtillgänglighet. World Wide Web Consortium. Web Accessibility Initiative, WAI WCAG 2.0 WCAG 1.0

Webbtjänster med API er

Olika slags datornätverk. Föreläsning 5 Internet ARPANET, Internet började med ARPANET

Guide för Innehållsleverantörer

LectureMopp - Projekt i Nätverksprogrammering

Teoretisk del. Facit Tentamen TDDC (6)

SLUTRAPPORT: TEXAS HOLDEM 4 FRIENDS

Objektorienterad Programkonstruktion. Föreläsning 6 23 nov 2015

Objektorienterad programmering i Java I. Uppgifter: 2 Beräknad tid: 5-8 timmar (OBS! Endast ett labbtillfälle) Att läsa: kapitel 5 6

TDDC30 Programmering i Java, Datastrukturer och Algoritmer Lektion 5. Laboration 4 Lådplanering Exempel på layout, ett GUI-baserat program Frågor

Classes och Interfaces, Objects och References Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

Att bygga enkla webbsidor

Webbservrar, severskript & webbproduktion

Microsoft Operations Manager 2005

Distribuerade affärssystem

Manuell installation av SQL Server 2008 R2 Express för SSF Timing

Låt oss ta hand om din utveckling, medan du själv utvecklar ditt företag

Android översikt. TDDD80 Mobila och sociala applikationer

Komponenter med COM (och COM+/VC++ 7.0)

Grundläggande programmering, STS 1, VT Sven Sandberg. Föreläsning 18

Collector en Android-app för att samla saker. Kim Grönqvist (kg222dk) Slutrapport

Det är principer och idéer som är viktiga. Skriv så att du övertygar rättaren om att du har förstått dessa även om detaljer kan vara felaktiga.

Mer OOP. Variation i typ. Medlen repetition. Generiska klasser. Gränssnitt - Interface. Mer om klasser Några exempel UML

Systemutvecklare SU14, Malmö

V2.6 VERSIONSINFORMATION

iphone/ipad Snabbguide för anställda på HB

Objektorienterad Programkonstruktion. Föreläsning 9 30 nov 2016

Omsorgen Användarhandledning

Laboration 2: Ett kommunikationssystem

Grafiska användargränssnitt i Java

L04.1 Marodören. Inledning. Mål. Genomförande. Uppgift 1 Hello World. Moment I

Nätverksprogrammering, EDA095

Priskamp. En prisjämförelsesite Björn Larsson

1. ActiveGPS 2.00 by TJ

Transkript:

Beslutsstöd för prissättning till webbutik Projektrapport 22 september 2011 This paper is about the development of an application that collects and processes market pricing data. This is used by an online store to gain an overview of the market they operate in. The paper begins with a brief outline of the plan for development and continues with a detailed description of the final product. The application was developed in Java and heavily utilize threading, especially for downloading data from the Internet. It is built on a clientserver architecture that communicates with a text-based protocol. Overall the project is considered a success, even though some things, such as the memory footprint, could have been improved. Examensarbetare: David Ersson - dersson@kth.se Examinator: Fredrik Lundevall - flu@kth.se Skolan för informations- och kommunikationsteknik Kungliga tekniska högskolan Kista 1

Innehåll Innehåll Denna rapport handlar om hur en applikation utvecklades för att samla prisinformation om en given marknad och sedan tillgängliggöra den på ett strukturerat sätt. Målet med detta är att en webbutik ska få en översikt över hur de förhåller sig till sina konkurrenter. Rapporten börjar med en kort beskrivning av hur planen för utvecklingen såg ut innan utveckling påbörjades. Den fortsätter sedan med en ganska detaljerad beskrivning av hur slutprodukten blev. Applikationen utvecklades i Java och drar till stor del nytta av trådning för en öka prestandan. Det gäller speciellt när det handlar om uppgifter som involverar kommunikation med källor på internet. Applikationen bygger på en klient-server-struktur som kommunicerar via ett textbaserat protokoll. Slutprodukten ses som lyckad även om vissa saker, så som dess minnesförbrukning, skulle kunna förbättras. Innehåll I. Förstudie 4 1. Inledning 4 2. Programmodell 5 2.1. Datalagret.................................... 5 2.2. Logiklagret................................... 6 2.3. Presentationslagret............................... 6 3. Tekniska problem 6 3.1. Programmeringsspråk............................. 6 3.2. Inhämtande av data.............................. 7 3.2.1. Datahämtning via webbtjänst..................... 7 3.2.2. Datahämtning via web scraping.................... 7 4. Liknande projekt 8 4.1. 80legs...................................... 8 4.2. Mozenda..................................... 9 II. Genomförande 10 5. Containrar 10 5.1. ReferenceProduct................................ 10 5.2. CompetitorProduct............................... 11 5.3. ProductPrice.................................. 11 2

Innehåll Innehåll 6. Datalagret 11 6.1. AdapterHandler................................. 12 6.2. Adapter..................................... 12 6.3. ReferenceAdapter................................ 12 6.4. CompetitorAdapter............................... 13 7. Logiklagret 14 7.1. DataHandler.................................. 14 7.2. Server...................................... 15 7.3. ClientHandler.................................. 15 7.3.1. Protokoll................................ 15 7.3.2. Funktioner............................... 15 8. Presentationslagret 17 8.1. ClientCommander............................... 17 8.2. NetworkThread................................. 18 8.3. GUI....................................... 18 8.3.1. Layout.................................. 19 III. Diskussion och slutord 20 9. Förbättringspotential 20 9.1. Arbetsminne.................................. 20 9.2. Styrklasserna.................................. 20 9.3. Prestanda.................................... 20 9.4. Konfigurationsfil................................ 21 10.Slutord 22 3

1 INLEDNING Del I. Förstudie 1. Inledning I en rapport från Posten som kom i april 2010 1 kan man läsa att omsättningen för distanshandel fördubblats de senaste fem åren. I rapportens förord säger Per Mossberg, kommunikationsredaktör på Posten Norden AB, att För nutidens konsumenter är distanshandel främst synonymt med att hitta och köpa det man söker på nätet snabbt, enkelt och prisvärt. Det är därför viktigt att man som nätbutik på dagens marknad har konkurrenskraftiga priser. Ingen kommer köpa något från en dyr leverantör om samma produkt levereras av en billigare leverantör med jämförbar standard. Detta projekt handlar om att jämföra en given onlinebutiks priser med alla konkurrerande butikers priser. Det kommer i denna rapport antas att alla konkurrenter också är onlinebutiker, men det finns inget som säger att det måste vara så. Dock är en förutsättning att deras priser finns online. Beställaren av detta projekt har gett mig i uppdrag att eliminera deras behov av att manuellt söka igenom konkurrenters hemsidor efter deras priser. De vill istället ha en lösning där de får sådan informationen serverad på ett strukturerat sätt automatiskt. Med detta hoppas de förutom att minska arbetsbördan också minska risken för att mindre vanliga produkter glöms bort. Ett automatiskt system skulle kunna behandla alla produkter i deras utbud, medan en människa måste begränsa sig till de vanligaste produkterna för att inte få en omöjlig uppgift. Den givna butiken kommer refereras till som beställarens butik och de konkurrerande butikerna som konkurrenter. 1 http://www.posten.se/img/cmt/pdf/distanshandeln_idag_2010.pdf - 2011-04-05 - Distanshandeln idag 2010 4

2 PROGRAMMODELL 2. Programmodell Figur 1: Logisk modell - Pricer är arbetsnamnet på projektet För att lösa beställarens problem är planen att skapa en applikation enligt modellen i figur 1 (en mer komplett modell av den färdiga produkten finns som appendix till denna rapport). Tanken är att för varje produkt som beställaren har i sitt sortiment kontrolleras priset hos andra som också säljer den. Denna data kan beställaren sedan hämta ut på en strukturerad form och se hur de ligger i förhållande till marknaden för var och en av alla de produkter de säljer. Modellen är inspirerad av Model View Controller (MVC) 2 och Three-tier 3. Datalagret och logiklagret är logiska lager i samma applikation, som i sin tur agerar server mot presentationslagret. 2.1. Datalagret Datalagret har som uppgift att samla in data från olika källor. Det finns två olika sorters källor; datakällor och referenskällor. Datalagret har till uppgift att hämta prisinformation om alla produkter som referenskällan tillhandahåller (alltså de produkter som beställaren säljer) från datakällorna. För att ha så dynamiskt stöd för datakällor som möjligt har varje datakälla en adapter som beskriver hur just den datakällan ska läsas in. Det gör också att det är relativt 2 http://www.oracle.com/technetwork/articles/javase/index-142890.html - 2011-04-01 - Java SE Application Design With MVC 3 http://msdn.microsoft.com/en-us/library/ff647546.aspx - 2011-04-05 - Three-Tiered Distribution 5

2.2 Logiklagret 3 TEKNISKA PROBLEM enkelt att lägga till nya datakällor eller uppdatera befintliga om behov skulle uppstå. Efter inläsning skickas datan (formaterad) till logiklagret för vidare behandling. 2.2. Logiklagret Logiklagret håller en lista med referensprodukter, matade från referenskällan i datalagret. Den listan innehåller även information om konkurrenternas priser, matade från datakällorna i datalagret. På så vis kan man enkelt se hur referenspriset ligger i förhållande till konkurrenterna. För att enkelt kunna se vilka konkurrenter som är billigast pekas de ut av specifika referenser i respektive produktobjekt. För att kunna automatisera procedurer baserat på inläst data finns det även krokar där man kan ansluta objekt för detta. När ett givet läge uppstår kallas respektive objekts aktiveringsfunktion. För exempel se algoritm 1. Algoritm 1 Exempel på automatisk funktion (pseudokod) i f ( r e f e r e n s p r i s > b i l l i g a s t e _ k o n k u r r e n t s _ p r i s ) { i f ( b i l l i g a s t e _ k o n k u r r e n t s _ p r i s > i n k o p s p r i s minsta_vinstmarginal ) { s e t E g e t P r i s ( b i l l i g a s t e _ k o n k u r r e n t s _ p r i s ) ; } } 2.3. Presentationslagret Presentationslagret agerar gränssnitt åt användaren. Det är ett fristående program som ansluter mot logiklagret via nätverk för att hämta den data som användaren valt att få presenteras för sig. Denna data presenteras sedan på ett sätt som gör det enkelt för användaren att förstå den. 3. Tekniska problem Det finns ett antal problem relaterat med detta projekt. Detta avsnitt kommer att behandla de större av dem och hur jag har tänkt lösa dem. 3.1. Programmeringsspråk Jag har valt att genomföra detta projekt i Java då det är ett välkänt språk som många hanterar, vilket underlättar underhåll och eventuell vidareutveckling. Det är också platformsoberoende så minimalt med jobb kommer behöva läggas på att porta produkten om beställaren skulle välja att byta plattform. Java har kritiserats för att generera relativt långsamma program 4. Nyare tester visar dock att Java är ungefär lika bra som sina 4 http://www.spinellis.gr/blog/20050210/ - 2011-04-04 - The Efficiency of Java and C++ 6

3.2 Inhämtande av data 3 TEKNISKA PROBLEM konkurrenter (C++, C#) 5 och även om C slår dem alla med god marginal i samtliga av testerna så måste man komma ihåg att det till exempel i allmänhet tar mycket längre tid att utveckla i C. 3.2. Inhämtande av data En av grundförutsättningarna för detta projekt är att det finns någon data att jämföra med. Den måste på något sätt både förvärvas och hållas uppdaterad. Föråldrad data är ointressant då prisbilden kan förändras snabbt 6. För att åstadkomma detta finns två huvudsakliga metoder; 3.2.1. Datahämtning via webbtjänst Webbtjänster används för att förenkla interaktion och kommunikation mellan tjänsten och mjukvara. En vanlig hemsida till exempel är (eller borde i alla fall vara) skapad för att presentera data för en människa som besöker den, men när man hämtar data via mjukvara för processering är man inte intresserad av saker som färg eller formatering. Man är istället bara ute efter den faktiska datan så för att slippa skicka onödig information kan en webbtjänst 7 presentera ett API 8 med funktioner för att endast skicka datan, oftast på en känd form såsom XML 9 eller JSON 10. Webbtjänster anses vara en del av webb 2.0 11. Fördelarna med att hämta data från en webbtjänst gentemot den äldre tekniken web scraping är överväldigande. Om det finns en webbtjänst som tillhandahåller datan man är ute efter så är det den man bör använda. 3.2.2. Datahämtning via web scraping Web scraping (även känt under liknande namn så som web farming, screen scraping, web harvesting eller på kort form endast scraping ), är ett generellt namn för att samla in data genom att läsa av till exempel hemsidor maskinellt och sedan filtrera ut den data man är intresserad av 12. Det är inte en optimal lösning, men om det inte tillhandahålls något API så kan det vara den enda lösningen. Eftersom scraping baseras 5 http://www.cherrystonesoftware.com/doc/algorithmicperformance.pdf - 2011-04-04 - Algorithmic Performance Comparison Between C, C++, Java and C# Programming Languages 6 http://www.prisjakt.nu/bok.php?pu=1077180-2011-04-04 - Prisutveckling för Host 7 http://www.w3.org/tr/ws-arch/#whatis - 2011-04-04 - Web Services Architecture 8 Application Programming Interface - kan översättas till mjukvarugränssnitt och är en uppsättning funktioner som är tillgängliga att använda utanför mjukvaran som tillhandahåller dem 9 http://www.w3.org/xml/ - 2011-04-07 - Extensible Markup Language 10 http://www.json.org/ - 2011-04-07 - Introducing JSON 11 http://oreilly.com/web2/archive/what-is-web-20.html - 2011-04-04 - What Is Web 2.0 12 http://www.csd.uoc.gr/~hy565/newpage/docs/pdfs/papers/process_aggregation_web-services.pdf - 2011-04-05 - Process Aggregation Using Web Services - Citat: Screen scraping and web farming [5] techniques were developed where the aggregator accessed the source site as if it were a user and parsed the resulting Hyper Text Markup Language (HTML) to extract the information being aggregated. 7

4 LIKNANDE PROJEKT på filtrering av data tänkt för människor så är risken stor att applikationen som använder det slutar fungera om sidan ändras, även om datan finns kvar. För en människa är skillnaden liten om till exempel layouten ändras, men det kan vara förödande för ett scraping-filter. Den enklaste formen av scraping är att manuellt söka reda på informationen man är intresserad av och sedan kopiera och klistra in den där man vill ha den. Den metoden är uppenbarligen inte särskilt effektivt. 13 Det finns också en moralisk aspekt av scraping. Eftersom man hämtar data automatiserat så riskerar man dels att belasta hemsidan relativt tungt under tiden man gör det och dels ser man aldrig reklamen eller klickar på länkarna så inkomster baserade på länk-klick uteblir för hemsidans ägare 14. Det är dock inte olagligt som så (om man inte ingått i ett avtal som säger annat för att få tillgång till informationen) utan det beror mer på vad man gör med informationen sedan. Det kan även argumenteras för att reklamaspekten är av mindre betydelse då många idag använder reklamblockering i sina webbläsare 15. Detta projekt kommer använda sig av en större svensk webbsida för prisjämförelser som datakälla till att börja med. Även om det kommer utebli reklamintäkter för dem så vill jag hävda att effekten av detta projekt är densamma som om någon hade suttit manuellt och slagit upp alla priser, då denna person ändå inte skulle vara intresserad av reklamen. Skillnaden är att nu går det att styra när belastningen ska ske. 4. Liknande projekt Jag har inte lyckats hitta något bra akademiskt gångbart material om scraping. Detta tror jag beror på att det är en väldigt bred och ospecifik term som dessutom är relativt simpel att förstå, men specifik att implementera 16. På internet kan man dock hitta projekt som använder sig av web scraping för att få fram information. Nedan följer en kort analys av två av dem. 4.1. 80legs Tjänsten 80legs 17 tillhandahåller en onlinetjänst för att enkelt skapa egna så kallade 80apps, vilket motsvarar det som i modellen ovan kallas adaptrar. Dessa kör man sedan via deras servrar och får resultatet tillbaka. De har även vanligt förekommande aktiviteter som färdiga paket. Bland de färdiga paket som finns att tillgå finns bland annat reguljära uttryck (eng. regular expressions) 18, ett system för att matcha text som är smidigt när man vill hämta ut given information ur en massa med text. 13 I resten av detta dokument kommer scraping referera till den automatiserade formen, dels då det är den sortens scraping som menas om inget annat anges, och dels för att det underlättar semantiken. 14 http://www.sentor.se/anti-scraping.html - 2011-04-05 - Anti-scraping 15 https://addons.mozilla.org/en-us/statistics/addon/1865-2011-04-05 - Adblock Plus Statistics 16 Detta är examensarbetarens kvalificerade gissning 17 http://80legs.com/ - 2011-04-26 - Custom Web Crawlers, Powerful Web Crawling, and Data Extraction 18 http://www.regular-expressions.info/ - 2011-04-26 - Regular-Expressions.info - Regex Tutorial, Examples and Reference 8

4.2 Mozenda 4 LIKNANDE PROJEKT Med hjälp av 80legs skulle man kunna skriva en väldigt effektiv adapter, men det går inte att ersätta hela datalagret då datalagret levererar datan till logiklagret på en strukturerad form. Det betyder att man hur som helst skulle behöva ett lager för att stukturera datan. 4.2. Mozenda Mozenda liknar på många sätt 80legs. Man skapar sina egna agenter som man via ett intuitivt webbgränssnitt instruerar hur de ska läsa av sina mål. Den avlästa datan kan sedan till exempel laddas upp på en server eller skickas till valfri e-postadress. Även här är agenter samma sak som adaptrar i modellen ovan. Många stora företag använder sig av denna tjänst enligt deras egen hemsida 19, däribland Microsoft, IBM och hotels.com. Efter endast en snabb överblick verkar det som att det skulle vara möjligt att ersätta i stort hela datalagret med denna tjänst. Dock finns problemet att denna tjänst kostar en hel del att använda, särskilt om man har för avsikt att ladda väldigt många sidor 20. Utan att ha testat Mozenda så ser den dock mycket bra ut på papper. Den skulle förmodligen kunna användas som en adapter vid behov. 19 http://www.mozenda.com/ - 2011-04-26 - Data Extraction, Web Screen Scraping Tool, Mozenda Scraper 20 http://www.mozenda.com/pricing - 2011-04-26 - Pricing plan 9

5 CONTAINRAR Del II. Genomförande Innan genomgången av programmets uppbyggnad så är det på sin plats med en del förtydlingar. De produkter och källor man jämför med är referenser, men kan också refereras till som beställarens. Detta kan i förväg låta fullständigt uppenbart men kan ändå vara bra att hålla i minnet. Det finns också en del fall av svengelska då koden är skriven på engelska, men rapporten på svenska. För en komplett modell se slutet på denna rapport. Först kommer de klasser som används som containrar (databehållare) att beskrivas. De är skapade för att på ett logiskt sätt innehålla all nödvändig information om det de representerar. Efter det kommer lagren i figur 1 beskrivas i ordning, uppifrån och ner. 5. Containrar För att hålla ordning och struktur på informationen som samlas in har det skapats ett antal objekt för att lagra den. Dessa containerobjekt hör inte till något specifikt lager i figur 1 utan används för att förmedla och lagra information mellan dem. De skapas i datalagret (avsnitt 6) och lagras sedan i logiklagret (avsnitt 7). 5.1. ReferenceProduct Detta är en representation av en produkt som beställaren har i sitt sortiment. I den finns information om produktens namn, produktnummer och beställarens utpris på den. Det finns också en lista med CompetitorProduct:s (se 5.2) och metoder för att hämta information om produkten. ReferenceProduct är upplagd på så sätt att man är tillåten att ha flera referenser på samma produkt (antag att beställaren har flera olika butiker som säljer samma produkt men med olika priser). Man måste därför ange från vilken källa man lägger till ett referenspris. Referenser kan inte läggas in som konkurrenter. Flera butiker som alla är referenser kommer alltså inte att konkurrera med varandra. Försöker man göra det kommer den metoden returnera direkt, utan att faktiskt ha gjort något. Exempel: Antag att en viss produkt säljs av de egna butikerna A och B för 10 och 5, och av konkurrent C för 8. Man skulle då för A få veta att C är billigaste konkurrent med 2 billigare, och för B skulle man få att C är billigaste konkurrent med -3 billigare. En utskriven referensprodukt har formatet produktens namn;produktnummer;beställarens pris på produkten;billigaste konkurrents namn;billigaste konkurrents pris på produkten;hur mycket billigare billigaste konkurrent är 10

5.2 CompetitorProduct 6 DATALAGRET Figur 2: Flödesschema för Pricer. 5.2. CompetitorProduct CompetitorProduct håller en representation av en konkurrents pris för en given produkt. Syftet med dessa är att lägga till dem till en referensprodukt (5.1). Varje instans av en CompetitorProduct innehåller namnet på konkurrenten den representerar, dess pris på produkten och när informationen senast är uppdaterad. Den innehåller dock inte själva någon information om vilken produkt den handlar om, så den måste kopplas till en referensprodukt för att ha någon betydelse. 5.3. ProductPrice ProductPrice används av ReferenceProduct(5.1) för att hålla isär olika referenser. Den innehåller endast namn på referensen och dess pris. Till skillnad från CompetitorProduct(5.2) så saknar denna tid för senaste uppdatering då detta förväntas vara senaste uppdateringen. 6. Datalagret Datalagret i figur 1 utgörs av en adapterhanterare och adaptrar. En adapter är en klass som kommunicerar med omvärlden för insamlande av information. De kallas adaptrar då de omvandlar extern information till Pricers gemensamma interna format (se avsnitt 5). 11

6.1 AdapterHandler 6 DATALAGRET Adaptrarna är uppdelade i två grupper, referensadaptrar (ReferenceAdapter) och konkurrentadaptrar (CompetitorAdapter). Referensadaptrarna matar referensprodukter (5.1) till logiklagret (avsnitt 7) som i sin tur begär en uppdatering av var och en av de inkommande produkterna. Uppdateringar behandlas av konkurrentadaptrarna som frågar sin källa om vad andra leverantörer (konkurrenter) har för priser på given produkt och rapporterar tillbaka till datalagret i form av konkurrentprodukter (5.2). Figur 2 visar hur flödet går från uppstart till dess att försök att hämta data om alla produkter genomförts. 6.1. AdapterHandler AdapterHandler håller reda på alla adaptrar som kopplas till systemet. Dess huvudsakliga funktion är att sprida förfrågningar från DataHandler (7.1) till alla adaptrar som ska ha dem. AdapterHandler erbjuder metoder för att lägga till fler adaptrar (både referensadaptrar och konkurrentadaptrar), hämta information om en produkt (baserat på produktnummer) från alla konkurrentadaptrar, visa vilka referenskällor som är kopplade till systemet och funktioner för att starta en ny uppdatering. Till skillnad från modellen i avsnitt 2 är det i slutprodukten tillåtet att ha ett obegränsat antal referensadaptrar då behov av fler än en fanns hos beställaren. Spridningen av metodanrop görs i samtliga fall med (uppenbarligen något anpassat för situationen): f o r ( CompetitorAdapter<T> a : t h i s. competitoradapters ) { a. r e q u e s t P r o d u c t I n f o ( productid ) ; } Looptypen kallas for-each och är ett smidigt sätta att iterera över en datasamling utan att behöva bry sig om dess storlek. Den kan läsas ut som för varje CompetitorAdapter i listan competitoradapters, kalla på requestproductinfo med inparameter productid. 6.2. Adapter Adapter är en liten abstrakt klass som både ReferenceAdapter och CompetitorAdapter ärver från. Den försäkrar att alla adaptrar tillhandahåller metoderna status() och stop(). Adapter implementerar Runnable vilket gör att den kan köras som en egen tråd. Det får också till följd att de klasser som ärver från Adapter kan köras som egna trådar. Mer om det i respektive adaptertyp. 6.3. ReferenceAdapter En refernesadapter är en adaptrar som implementerar ReferenceAdapter. Den läser in beställarens produkter i systemet. ReferenceAdapter är en abstrakt klass som bara tillhandahåller basfunktionaliteten och lämnar det sen till implementation att stå för detaljerna om hur inläsningen ska genomföras. Varje referensadapter (alltså implementation av ReferenceAdapter) måste kalla på ReferenceAdapter:s konstruktor med ett namn på adaptern och ett mål. Målet är var 12

6.4 CompetitorAdapter 6 DATALAGRET data ska hämtas från och representeras med en String. Anledningen till att det är en String och inte något annat är att man inte ska vara begränsad till att målet ska vara till exempel en URL eller en fil. Namnet bör vara samma namn som eventuellt kan rapporteras som konkurrent av en CompetitorAdapter (6.4). Referensprodukten kontrollerar nämligen om konkurrenten som läggs till egentligen är en referens, och i så fall läggs den inte in som konkurrent. En referensadapter är uppdelad i tre trådar. En tråd som producerar data, en som behandlar datan och en som (eventuellt) övervakar de två första trådarnas förehavanden. Den första tråden producerar data genom att läsa av sin källa (till exempel genom att ladda ner en fil från en URL) och placera inläst rådata i en kö, element för element. Datan som läses in via den externa källan refereras till som rådata då den kan komma i vilken form som helst (till exempel som en textsträng). Då nerladdning är en operation som kräver interaktion med en extern part sköts det i en egen tråd så störningsmomentet för den externa parten blir så minimalt som möjligt. Tråd nummer två konsumerar rådata från tidigare nämnd kö och omvandlar den till referensprodukter (5.1). Den skapade referensprodukten läggs till DataHandler:s (7.1) samling referensprodukter via DataHandler:s metod addreferenceproduct(...). När man startar en referensadapter startas både den producerande tråden och den konsumerande tråden via metodkall till respektive getproducer och getconsumer. De båda metoderna är abstrakta i ReferenceProduct så en implementation måste tillhandahålla dessa och de ska returnera varsin Runnable. Den tredje tråden är en statustråd. Eftersom ReferenceProduct ärver från Adapter (6.2) körs även själva ReferenceAdapter i en egen tråd. Det finns dock inga krav på att denna tråd ska göra något. Efter att producent- och kunsumenttråden startats kallas den abstrakta metoden monitor() och det är där eventuell övervakningsfunktionalitet implementeras. Metoden kallas dock bara en gång, så om man vill ha något som kör kontinuerligt måste man lägga det som en loop i implementation av monitor(). Vill man inte implementera någon särskild övervakning implementerar man bara en tom monitor(). 6.4. CompetitorAdapter CompetitorAdapter är en abstrakt klass för de adaptrar som ska läsa av konkurrenters produktinformation. Den har funktionalitet för att tråda upp hämtningen av konkurrentinformation och interaktion med logiklagret färdigimplementerat. Det som måste implementeras när man skapar en konkurrentadapter (alltså en adapter som ärver från denna klass) är den funktion som faktiskt hämtar datan, getproductinfo(t productinfo). Den tar in ett produktnummer (till exempel ISBN för böcker) och ska returnera en lista med CompetitorProduct:s. Trådningen i CompetitorAdapter sköts av en ExecutorService 21 av typen Executors.newCachedThreadPool() 22. En cached thread pool har egenskapen att när man ger 21 http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/executorservice.html - 2011-05-30 - Interface ExecutorService 22 http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/executors.html - 2011-05-30 13

7 LOGIKLAGRET den uppdrag kommer den starta nya trådar efter behov. Detta gör att den har lite längre uppstartstid än till exempel en fixed thread pool (som även den finns i Executors), som har egenskapen att den alltid har ett fixt antal trådar som ligger och väntar på jobb. Det man dock vinner med cached thread pool är att när det inte finns något jobb att göra ligger det inte trådar och väntar, vilket kan ses som en fördel i denna applikation då den bara ska köra uppdateringar en mindre del av sin körtid. Nya trådar startas allt eftersom de redan körande trådarna inte hinner med att tömma arbetskön. Detta kontrolleras av CompetitorAdapter:s egen tråd. För att skydda mot att det skapas massvis med trådar som öppnar varsin nätanslutning finns det en semafor. En semafor är ungefär som en korg med bollar i, och varje gång man vill ha tillstånd att exekvera så måste man lyckas ta en boll. Finns det ingen boll kvar i korgen måste man vänta till så är fallet. Semaforen är statisk, så alla trådar plockar bollar från samma korg, även om de inte hör till samma konkurrentadapter. Den är också en orättvis semafor, så det är slumpen som avgör i vilken ordning väntande trådar får plocka bollar. Detta kan orsaka en temporär svältning av vissa konkurrentadaptrar, men påverkar inte slutresultatet då alla trådar kommer få exekvera förr eller senare. Som standard får konkurrentadaptrarna starta max 40 arbetstrådar totalt. 7. Logiklagret Logiklagret är det som organiserar den insamlade datan och tillåter presentation av den för användare. DataHandler (7.1) sköter själva organisationen och hanteringen av produkter, och Server(7.2) tar hand om uppstart och lyssnande efter användare. 7.1. DataHandler Det är DataHandler som agerar central nod i datahanteringen. Referensadaptrarna lägger till nya referensprodukter till referensproduktslistan via DataHandler:s addreferenceproduct(...), som i sin tur lägger till den nya referensproduktens produktnummer till alla konkurrentadaptrars arbetsköer (via AdapterHandler). När en konkurrentadapter behandlat produkten rapporterar den tillbaka en lista med CompetitorProduct:s (5.2) till AdapterHandler som lägger in alla konkurrentprodukter var för sig till rätt referensprodukt via metoden addcompetitorproduct(...). Alla referensprodukter hålls i en java.util.concurrent.concurrenthashmap 23. Det är en standardkomponent i Java sedan 1.5 som abstraherar bort behovet av att synkronisera en HashMap åt programmeraren. En HashMap i sin tur används för att koppla ett värde till en unik nyckel. Som nyckel används produktnumret och som värde används ReferenceProduct-objektet. - Class Executors 23 http://java.sun.com/javase/6/docs/api/java/util/concurrent/concurrenthashmap.html - 2011-05-25 - Oracles API för CHM 14

7.2 Server 7 LOGIKLAGRET 7.2. Server Applikationen är som nämns i avsnitt 2 uppdelad i två delar; dels ett backend som utgörs av logiklagret och datalagret, och dels ett frontend som ger användarvänlig tillgång till backendet. Mer om frontendet i avsnitt 8 på sidan 17. Server är en liten klass som tar hand om uppstarten av serverdelen av Pricer. Den behandlar först eventuella inparametrar och startar sedan upp en DataHandler (7.1) med avseende på givna inparametrar (eller standardvärden om inga inparametrar givits). Därefter lägger den sig för att lyssna efter anslutningar från klienter. När en klient ansluter startar den en ny tråd med en instans av ClientHandler (7.3) och lyssnar sedan vidare efter nya klienter. 7.3. ClientHandler När servern (7.2) tar emot en anslutning startar den en ny tråd med en instans av klienthanteraren ClientHandler i en egen tråd. Det är sedan den tråden som tar hand om att prata med den anslutna klienten. När en klient skickar ett kommando kommer klienthanteraren tolka det och returnera ett svar (för mer information om protokollet, se 7.3.1). Beroende på vilken sorts begäran det är kommer antingen ett fast svar ges (till exempel kommer stop alltid ge goodbye som svar) eller så genereras svaret dynamiskt. Dynamiska svar genereras efter bästa förmåga genom att iterera över datamassan som efterfrågas. Det handlar antingen om DataHandler:s (7.1) productmap eller om failedmap, vilka båda är (som tidigare nämnts) av typen ConcurrentHashMap. När man itererar över en sådan garanteras man inte att få en fullständig bild. Det man garanteras att få är en bild som den sett ut någon gång mellan starten och slutet på iterationen. Detta är dock inte riktigt ett problem om man vet om det eftersom man inte bör begära listning under en uppdatering, och när en uppdatering väl är klar är också innehållet i HashMap:en statisk (tills dess att en ny uppdatering startas). 7.3.1. Protokoll Protokollet som används för att prata kommunicera mellan server och klient är textbaserat. Detta gör att det är väldigt enkelt att testa servern utan att faktiskt ha en färdigskriven klient för man kan ansluta med ett vanligt program för rå textöverföring över nätverk (så som netcat 24 eller telnet 25 ). 7.3.2. Funktioner hello Svarar med ett Hello there. Används för att kontrollera att anslutningen mellan klient och server fungerar (en ping-funktion). 24 http://nc110.sourceforge.net/ - 2011-05-26 - Netcat: the TCP/IP swiss army knife 25 http://www.faqs.org/rfcs/rfc854.html - 2011-05-26 - RFC 854 - Telnet Protocol Specification 15

7.3 ClientHandler 7 LOGIKLAGRET addid#produktnummer;produktnamn;referenspris;butiksnamn#produktnummer... Lägger manuellt till referensprodukter. Det går teoretiskt att lägga till hur många produkter som helst på samma rad. Dock får namnen inte innehålla varken nummertecken (#) eller semikolon (;). Detta är en känd brist, men då namnet endast är till för användarens bekvämlighet (produktnummer används för sökningar) så kändes det inte relevant att lägga tid på att fixa detta just nu. update Startar en uppdatering. Denna sorts uppdatering kontrollerar endast konkurrenternas priser. Den egna produktkatalogen (referensprodukterna) uppdateras inte. Önskas det får man kalla på forceupdate. forceupdate Stoppar en eventuellt pågående uppdatering, tömmer listorna med referensprodukter (productmap och failedmap, se 7.1 för mer information om dem) och startar en ny nerladdning av referensadaptrarnas mål. Detta har samma resultat som en omstart av servern, men utan att faktiskt behöva starta om den. getid#produktnummer Returnerar en utskriven referensprodukt med givet produktnummer om en sådan finns, annars null. Se 5.1 om hur en referensprodukt skrivs ut som en sträng. getall Returnerar alla referensprodukter, separerat med ny rad. Se 5.1 om hur en referensprodukt skrivs ut som en sträng. getcsv#referensnamn Returnerar en CSV-formaterad lista med alla referensprodukter som levereras av referensnamn. Inleds med en titelrad och avslutas med en tom rad. Denna funktion påminner till stor del om getall, men skiljer sig med att man i getall får alla referensnamn och deras priser medan getcsv kan man få bara ett. Det går att få samtliga referensnamn om man inte lämnar något när man kallar på getcsv (alltså att man kallar på endast getcsv ). Då skriver den ut titelraden och sedan kallar den internt på getall. getfail På samma sätt som getall returnerar en lista på alla referensprodukter returnerar denna en lista med alla referensprodukter som ingen av konkurrentadaptrarna kunde hitta. Dessa finns inte med i listan man får från getall. En union av getall och getfail resulterar i en union av de produkter som lagts till av referensadaptrarna. status Returnerar information om vad servern har för sig för tillfället samt statistik så som hur många referensprodukter det finns för tillfället, hur många blivande referensprodukter som laddats ner av de respektive referensadaptrarna och hur många som fortfarande väntar på att konverteras till referensprodukter. Nedan är ett exempel på hur svaret från status kan se ut: 16

8 PRESENTATIONSLAGRET Started: Thu May 26 13:11:56 CEST 2011 Currently have 19260 reference products and have failed to get information about 49 products. The adapters: Kunds-butik1: 15958 uniqe data elements added to workqueue, still adding. 261 waiting to be processed Kunds-butik2: 19388 uniqe data elements added to workqueue, still adding. 127 waiting to be processed Konkurrentkälla1: 476 work units handled this update round. names Returnerar de olika referensnamn som är representerade bland referenserna, separerade med semikolon (;). identify Saknar vettig funktion idag. Den finns här för att förbereda för den dag inloggning och kryptering eventuellt ska implementeras. stop Stänger av servern. quit Stänger anslutningen mellan server och klient utan att påverka servern. Svarar med ett goodbye. 8. Presentationslagret Presentationslagret är det lager som möjliggör presentation av data för användaren. Detta är Pricers frontend, det vill säga den del som är synlig utifrån. 8.1. ClientCommander ClientCommander är ett interface som beskriver vilka funktioner som finns tillgängliga för en klient till Pricer. Den går hand i hand med NetworkThread (8.2), och en klass som vill använda sig av NetworkThread för kommunikation med servern måste implementera ClientCommander. De klasser som implementerar ClientCommander måste tillhandahålla metoden getnextcommand() som NetworkThread använder sig av för att hämta kommandon från dem. De får dock en synkroniserad kö via ClientCommander för det. ClientCommander säger också att det ska finnas metoder för återkoppling efter att operationer utförts. Återkopplingsmetoder namnges på forment callback[operation]. Till exempel så kommer NetworkThread efter att ha genomfört en statusförfrågan skicka svaret till metoden callbackstatus, och sen är det upp till implementationen att använda informationen. Denna uppdelning mellan ClientCommander och en klass som implementerar den, till exempel GUI (8.3), är gjord för att det ska vara enkelt att skapa nya användargränssnitt utan att behöva skapa en ny nätverkshanterare. Antag till exempel att man vill skapa ett program som automatiskt genomför en fast uppsättning operationer för användande i script eller liknande. 17

8.2 NetworkThread 8 PRESENTATIONSLAGRET Figur 3: Det grafiska gränssnittet 8.2. NetworkThread NetworkThread tar hand om klientens kommunikation med servern genom att agera som en brygga mellan en implementation av ClientCommander och servern. Den tillhandahåller metoder som skickar korrekt formaterade strängar enligt protokollet beskrivet i 7.3.1. Svaret tas sedan emot och skickas till tillhörande återkopplingsmetod. Olika återkopplingsmetoder tar olika sorters inparametrar. Om svaret förväntas vara en kort textsträng används String, men om svaret förväntas vara en större textmassa används istället den upprättade anslutningen som inparameter och det är upp till implementationen av ClientCommander att läsa av den. Till exempel skrivs svaret på status ut i GUI:et (8.3) medan svaret på getcsv skrivs direkt till en av användaren specificerad fil. Mer om det nedan. 8.3. GUI I figur 3 visas en bild på det grafiska användargränssnittet (kort. GUI, för Graphical User Interface ). Det är denna del av Pricer som användare interagerar med. Härifrån kan man på ett användarvänligt sätt utföra de (flesta) funktioner som finns listade i 7.3.2, till exempel hämta filen med data om konkurrenter. GUI:et i sig kör inte i någon egen explicit tråd utan nöjer sig med den tråd man får som standard via grafikbiblioteket Swing. För att GUI:et alltid ska vara responsivt körs inga tidskrävande funktioner direkt därifrån. GUI implementerar ClientCommander och har därför en kö som nätverkshanteraren övervakar. Där lägger de knappar som startar tyngre funktioner kommandon till nätverkshanteraren (8.2) som utför dem i ordningen de läggs till i kön. När en operation är klar kallar nätverkshanteraren på tillhörande återkopplingsmetod som behandlar resultatet av operationen på lämpligt vis. Resultatet av att kalla på 18

8.3 GUI 8 PRESENTATIONSLAGRET status kommer till exempel uppdatera innehållet i gränssnittets statusflik (via callbackstatus(...)), men om man kallar på getcsv#kunds-butik1 kommer svaret skrivas till filen som angetts i textfältet (via callbackgetcsv(...). Kontroller om huruvida filen är skrivbar sker i knappens funktionslyssnare innan operationen läggs till i kön eftersom getcsv ofta är en tung operation som inte bör genomföras i onödan. 8.3.1. Layout En viktig del i skapandet av grafiska gränssnitt är att få önskat innehåll att befinna sig på rätt plats. Det går antingen att använda sig av verktyg som låter utvecklaren mer eller mindre rita upp sitt gränssnitt eller så kan man göra det för hand. Båda har sina för och nackdelar, men en analys av det ligger utanför denna rapport. Gränssnittet till Pricer är skrivet för hand då något tillfredsställande verktyg för att bygga det inte hittats. För att komponenter ska hamna på rätt plats använder man sig av en (eller flera) så kallad LayoutManager 26. Till detta gränssnitt används en Layout- Manager som heter MiGLayout 27. Den är ännu inte en standardkomponent i Java, men dess skapare jobbar för att den ska bli det i Java 1.7. MiGLayout är en mycket kraftfull LayoutManager som tar bort behovet av att nästla JPanels, något som annars brukar vara nödvändigt för att få gränssnitt att se ut som önskat. Det lämnas till läsaren att själv undersöka detaljer om MiGLayout då det ligger utanför rapportens omfång, men det kan varmt rekommenderas för att enkelt skapa snygga gränssnitt för hand. 26 http://download.oracle.com/javase/tutorial/uiswing/layout/index.html - 2011-05-31 - Lesson: Laying Out Components Within a Container 27 http://www.migcalendar.com/miglayout/ - 2011-05-25 - MiGLayout - The Java Layout Manager for Swing, SWT and JavaFX 19

Del III. Diskussion och slutord 9. Förbättringspotential 9 FÖRBÄTTRINGSPOTENTIAL Efter att ha genomfört projektet anser jag att lösningen i det stora hela blev bra. Det finns dock ett antal saker jag skulle göra annorlunda om jag gjorde om projektet igen. Här följer de största problemen och potentiella lösningar på dem. 9.1. Arbetsminne Pricer äter arbetsminne. Efter att första uppdateringen är klar dra den ungefär 2,5GB. Detta kommer sig av att Java i sig är resurshungrigt tillsammans med att det är väldigt mycket data som indexeras. Jag borde ha jobbat hårdare på att hålla minnesanvändningen nere, men jag försvarar mig med att jag fick felaktig information om mängden produkter som skulle indexeras. Från början fick jag veta att det handlade om ca 100 000 produkter som skulle indexeras, en uppgift som även min bärbara dator klarade av bra. Det visade sig dock senare att det fanns ca 600 000 produkter till som skulle indexeras. Detta gjorde att minnesförbrukningen vid en körning rusade. Den nuvarande lösningen på problemet är helt enkelt att köra på en större och snabbare server. Inte en optimal lösning, men den fungerar i brist på bättre. För att förbättra minnesanvändningen skulle jag rekommendera att skriva ner inläst data till en fil eller databas. Man skulle också kunna skriva om strukturen på ett sätt som nyttjar färre objekt. Just nu innehåller varje referensprodukt en HashMap med ProductPrice (5.3) och konkurrentdata (5.2) lagras i både en HashMap och en TreeSet. Notera att det är samma objekt med konkurrentdata som pekas ut av båda samlingarna. Det var nödvändigt att göra så för att både ha konkurrentdata sorterat på pris men ändå försäkra sig om att inga dubbletter uppstår. Det är förmodligen där man ska börja optimeringen. 9.2. Styrklasserna Efter att implementationen är färdig känner jag att det blev lite väl många styrklasser. Framför allt hade AdapterHandler helt kunnat sammanfogas med DataHandler för att minska antalet metodkall när man söker vilket ger bättre prestanda och minskad komplexitet. Även Server hade nog kunnat sammanfogats med DataHandler, men i det fallet är det lättare att försvara en uppdelning då Server har en unik uppgift. 9.3. Prestanda Som nämns i 6.4 på sidan 13 så används 40 trådar för hämtning av konkurrentdata. Denna siffra är framtagen med hjälp av ett inte särskilt vetenskaplig test. En körning startades och när systemet kommit igång klockade jag hur många arbetsenheter (där 20