-
Notifications
You must be signed in to change notification settings - Fork 57
Laskari 5
Ohjausta tehtävien tekoon ke 15.4. klo 10-12 (UMT), pe 17.4. klo 12-14 (UMT) ja pe 17.4. klo 16-18 (doge) B221
- palautusta varten tarvitaan yksityinen repositorio, jolla collaboratorina käyttäjä mluukkai
- kannattaa käyttää samaa repoa kuin edellisten viikkojen tehtävissä
- palautusrepositorion nimi ilmoitetaan tehtävien lopussa olevalla palautuslomakkeella
Maven-projekti konfiguroidaan projektin juuressa olevassa pom.xml-tiedostossa.
Tutkitaan hieman viime viikon tehtävissä 7-11 käytetyn projektin eli repositorion https://github.com/mluukkai/ohtu2015 hakemistossa viikko4/LoginWeb2 olevan projektin pom.xml:in sisältöä.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>LoginWeb2</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>LoginWeb2</name>
<properties>
<spring.version>3.0.5.RELEASE</spring.version>
<easyb.version>1.5</easyb.version>
<slf4j.version>1.6.1</slf4j.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>JBoss Repo</id>
<url>https://repository.jboss.org/nexus/content/repositories/releases</url>
<name>JBoss Repo</name>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.easyb</groupId>
<artifactId>easyb-core</artifactId>
<version>${easyb.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit-dep</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.13.0</version>
<scope>compile</scope>
</dependency>
<!-- loggaus -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- servletit -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
<classifier/>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
<classifier/>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
<classifier/>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- validointi -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.1.0.Final</version>
<classifier/>
<exclusions>
<exclusion>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
<classifier/>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.6</version>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>7.4.2.v20110526</version>
<configuration>
<stopKey>foo</stopKey>
<stopPort>9999</stopPort>
<webAppConfig>
<contextPath>/</contextPath>
</webAppConfig>
</configuration>
<executions>
<execution>
<id>start-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<scanIntervalSeconds>0</scanIntervalSeconds>
<daemon>true</daemon>
</configuration>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.easyb</groupId>
<artifactId>maven-easyb-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<storyType>html</storyType>
<storyReport>${basedir}/target/easyb/easyb-report.html
</storyReport>
</configuration>
</plugin>
</plugins>
</build>
</project>
Alussa määritellään projektin tiedot (nimi, versio.)
Kohdassa properties määritellään mm. alempana käytettäviä vakioita
Maven osaa ladata riippuvuuksia (eli käytännössä jar-tiedostoja) automaattisesti oletusrepositorioista. Kaikki riippuvuudet eivät kuitenkaan löydy oletusrepositorioista ja tälläisiä tilanteita varten osaan repositories voi määritellä vaihtoehtoisia repositorioita joista maven voi etsiä riippuvuuksia.
Riippuvuudet määritellään osassa dependencies
- alussa olevien riippuvuuksien (mm. easyb, junit) scope on test, tämä tarkoittaa että ne ovat käytössä vain testeissä
- selenium-riippuvuuden scope on compile, tällöin selenium on käytössä testeissä ja normaalissa koodissa
- jos ohjelmassa tarvitaan jar:eja, tulee niitä vastaavat maven-riippuvuudet kirjata dependencies-osaan, riippuvuuksia voi etsiä mm. seuraavista: http://search.maven.org tai http://mvnrepository.com/
Osassa build määritellään kääntämiseen liittyvien pluginien toimintaa
- kääntämisessä määritellään käytettävän javan versiota 1.6, tämä tapahtuu maven-compiler-plugin:ia konfiguroimalla
- jos tätä konfiguraatiota ei tehdä käyttää compiler-plugin oletusarvoista javan versiota. maven 3:ssa se on 1.6 mutta maven 2.*:ssa versio 1.3
- jetty-pluginiin liittyy enemmänkin konfiguraatioita
- kohdan executions-alla määritellään, että jetty (eli sovelluksen käyttämä maven-projektiin integroitu web-palvelin) käynnistetään vaiheessa pre-integration-test ja sammutetaan vaiheessa post-integration-test, tämä saa aikaan sen, että kun ajetaan integraatiotestejä, eli suoritetaan komento
mvn integration-test
, on jetty päällä testien ajamisen aikana
- kohdan executions-alla määritellään, että jetty (eli sovelluksen käyttämä maven-projektiin integroitu web-palvelin) käynnistetään vaiheessa pre-integration-test ja sammutetaan vaiheessa post-integration-test, tämä saa aikaan sen, että kun ajetaan integraatiotestejä, eli suoritetaan komento
- easyb-pluginin määritellään ajavan testit integration-test-vaiheessa
Hae repositorion https://github.com/mluukkai/ohtu2015 hakemistossa viikko5/TyhjaProjekti lähes tyhjän maven-projektin runko.
- mukana on kohta tarvitsemasi luokka Submission
Tehdään ohjelma jonka avulla voit lukea kurssilla palauttamiesi tehtävien statistiikan osoitteesta http://ohtustats-2015.herokuapp.com/
Omat palautukset palauttava sivu on http://ohtustats-2015.herokuapp.com/students/012345678/submissions, missä vaihda 012345678 omaksi opiskelijanumeroksesi. Palvelin palauttaa tietosi json-muodossa
Tavoitteena on tehdä ohjelma, joka ottaa komentoriviparametrina opiskelijanumeron ja tulostaa palautettujen tehtävien statistiikan ihmisystävällisessä muodossa.
Ohjelmassa tarvitaan muutamaa kirjastoa:
- HTTP-pyynnön tekemiseen http://hc.apache.org/httpcomponents-client-4.4.x/
- InputStreamin merkkijonoksi muuttamiseen http://commons.apache.org/io/
- json-muotoisen merkkijonon muuttaminen olioksi http://code.google.com/p/google-gson/
Liitä projektisi pom.xml:n seuraavat riippuvuudet
- commons-httpclient, Commons IO, gson
- löydät riippuvuuksien tiedot seuraavista http://search.maven.org tai http://mvnrepository.com/
- Ainakin seuraavat versiot on todettu yhteensopiviksi ja toimivaksi projektin koodin kanssa: commons-httpclient 3.1, Commons IO 2.0, gson 2.1
Ota mallia edellisen tehtävän projektista ja määrittele maven-compiler-plugin käyttämään javan versiota 1.6
Voit ottaa projektisi pohjaksi seuraavan tiedoston:
import com.google.gson.Gson;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.IOUtils;
public class Main {
public static void main(String[] args) throws IOException {
String studentNr = "012345678";
if ( args.length>0) {
studentNr = args[0];
}
String url = "http://ohtustats-2015.herokuapp.com/students/"+studentNr+"/submissions";
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
client.executeMethod(method);
InputStream stream = method.getResponseBodyAsStream();
String bodyText = IOUtils.toString(stream);
System.out.println("json-muotoinen data:");
System.out.println( bodyText );
Gson mapper = new Gson();
Submission[] subs = mapper.fromJson(bodyText, Submission[].class);
System.out.println("Oliot:");
for (Submission submission : subs) {
System.out.println(submission);
}
}
}
HUOM: jos teet koodia NetBeansilla, kirjastoja ei ehkä tunnisteta ennenkiun teet clean and buildin ja NB lataa ne mavenin repositoriosta koneellesi.
Tehtäväpohjassa on valmiina luokan Submission
koodin runko. Gson-kirjaston avulla json-muotoisesta datasta saadaan taulukollinen Submission
-olioita, joissa jokainen olio vastaa yhden viikon palautusta. Tee luokkaan oliomuuttuja (sekä tarvittaessa getteri ja setteri) jokaiselle json-datassa olevalle kentälle, jota ohjelmasi tarvitsee. Kentät a1, a2 jne vastaavat viikolla tehtyjä yksittäisiä tehtäviä.
Tee kuitenkin ohjelmastasi tulostusasultaan miellyttävämpi, esim. seuraavaan tyyliin:
opiskelijanumero 012345678 viikko 1: tehtyjä tehtäviä yhteensä: 9, aikaa kului 3 tuntia, tehdyt tehtävät: 1 2 3 4 5 6 7 9 11 viikko 2: tehtyjä tehtäviä yhteensä: 6, aikaa kului 4 tuntia, tehdyt tehtävät: 1 2 3 6 7 8 yhteensä: 15 tehtävää 7 tuntia
- tehdään äskeisen tehtävän projektista jar-tiedosto komennolla
mvn install
- suoritetaan ohjelma komennolla
java -cp tiedostonNimi.jar ohtu.Main
- mutta ohjelma ei toimikaan, tulostuu:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/httpclient/HttpMethod
Caused by: java.lang.ClassNotFoundException: org.apache.commons.httpclient.HttpMethod
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: ohtu.Main. Program will exit.
Mistä on kyse?
- ohjelman riippuvuuksia eli projekteja commons-httpclient, Commons IO ja gson vastaavat jar-tiedostot eivät ole käytettävissä, joten ohjelma ei toimi
- saamme generoitua ohjelmasta jar-tiedoston joka sisältää myös riippuvuudet mavenin assembly-pluginin avulla
- lisää pom.xml:n plugineihin seuraava:
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
komennolla mvn assembly:assembly
syntyy koko ohjelman sisältävä "standalone"-jar-tiedosto:
$ java -cp TyhjaProjekti2-1.0-jar-with-dependencies.jar ohtu.Main 012345678 opiskelijanumero 012345678 viikko 1: tehtyjä tehtäviä yhteensä: 9, aikaa kului 3 tuntia, tehdyt tehtävät: 1 2 3 4 5 6 7 9 11 viikko 2: tehtyjä tehtäviä yhteensä: 6, aikaa kului 4 tuntia, tehdyt tehtävät: 1 2 3 6 7 8 yhteensä: 15 tehtävää 7 tuntia
Riippuvuudet sisältävä jar-voidaan myös tehdä käyttämällä mavenin shade-pluginia Shade-pluginin avulla saadaan itseasiassa aikaan "helppokäyttöisempi" jar, joka voidaan käynnistää määrittelemättä main-metodin sisältävää luokkaa.
Määrittele shade-pluginille mainClassin sijainti lisäämällä pom.xml:ääsi seuraava:
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>ohtu.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Saat luotua jar:in komennolla mvn package
, ja ohjelman suoritus tapahtuu komennolla java -jar tiedostonnimi.jar
Lue http://git-scm.com/book/en/Git-Tools-Stashing kohtaan Un-applying a Stash asti.
Oletetaan että olet repositoriossa, jossa on ainakin kaksi branchia: master ja joku toinen (kutsutaan sitä tässä nimellä toinen).
- ollessasi master-branchissa tee muutoksia, joita lisäät staging-alueelle ja joitain muutoksia joita et vielä "äddää"
- pomosi käskee sinua välittömästi tekemään pari muutosta branchiin toinen. Et kuitenkaan halua vielä comittoida masterissa olevia muutoksia
- jos siirryt branchiin toinen tekemättä comittia, tulee hirveä sotku, sillä muutokset pysyvät muutoksina toisessakin branchissa
- stashays pelastaa tästä tilanteesta, eli stashaa masterissa olevat muutoset
- kokeile ennen ja jälkeen stash-komennon komentoa
git status
- kokeile ennen ja jälkeen stash-komennon komentoa
- siirry branchiin toinen, tee sinne joku muutos jonka committaat
- palaa jälleen masteriin
- palauta stashatyt muutokset komennolla
git stash apply
- varmista että muutokset palasivat
- kuten huomaat, staging-alueelle jo lisätty muutos ei palaa staging-alueelle, vaan joudut lisäämään sen uudelleen
- jos edellisessä komento olisi annettu muodossa
git stash apply --index
, olisi tilanne palautunut täysin ennalleen
- viikon 4 tehtävässä 6 palasimme jo menneisyyteen checkouttaamalla tagillä merkittyyn kohtaan
- katsotaan nyt miten voimme palauttaa jonkun menneisyydessä olevan tilanteen uudelleen voimaan
- tee tiedosto xxx, lisää ja committaa se
- poista tiedosto ja committaa
- tee jotain muutoksia johonkin tiedostoon ja committaa
- historiasi näyttää seuraavalta
(1) - (2) - (3)
- Nykyhetki eli HEAD on (3). Commitissa (1) tiedosto xxx on olemassa, nykyhetkellä ja (2):ssa xxx:ää ei ole.
- huom: komennolla
gitk
voit tutkia historiaa
- huom: komennolla
- haluamme palauttaa tiedoston
- selvitä sen commitin id, jossa tiedosto vielä on olemassa, tämä onnistuu gitk:lla tai
git log
-komennolla - anna komento
git checkout 3290b03cea08af987ee7ea57bb98a4886b97efe0 -- xxx
missä pitkä merkkijono on siis kyseisen commitin id- varmista että tiedosto on ilmestynyt staging-alueelle komennolla
git status
- varmista että tiedosto on ilmestynyt staging-alueelle komennolla
- tee commit
- xxx on palannut!
- HUOM: koko id:tä ei komennossa tarvitse antaa, riittää antaa alusta niin monta merkkiä, että niiden perusteella id voidaan päätellä yksikäsitteisesti repositoriosi historiassa
- huomaamme, että juuri tehty commit oli virhe, kumotaan se sanomalla
git revert HEAD --no-edit
- HEAD siis viittaa siihen committiin minkä kohdalla nyt ollaan
- syntyy uusi commit, jossa edellisessä tehdyt muutokset on kumottu
- ilman optiota no-edit pääset editoimaan kumoamiseen liittyvään commitiin tulevaa viestiä
- huom: sanomalla
git checkout HEAD^
pääsemme takaisin kumottuun tilanteeseen, eli mitään ei ole lopullisesti kadotettu
- vastaavalla tavalla voidaan revertata mikä tahansa commit eli:
git revert kumottavancommitinid
- tee repoosi branchi nimeltä haara ja tee masteriin ja haaraan committeja siten että saat aikaan seuraavankaltaisen tilanteen:
/------master -- \---haara
- eli sekä master että haara ovat edenneet muutamien commitien verran haarautumisen tapahduttua
- huom: komennolla
gitk --all
näet kaikki haarat, kokeile!
- huom: komennolla
- yhtäkkiä huomaat, että master:iin tekemäsi asiat eivät olekaan kovin hyviä ja haara:ssa on paljon parempaa tavaraa, haluaisitkin että haara:sta tulisi uusi master
- tämä onnistuu kun menet masteriin ja annat komennon
git reset --hard haara
- varmista että komento toimii oikein
- vanhan master-haarankaan tavarat eivät katoa mihinkään, jos niihin jostain syystä vielä halutaan palata
Lue http://git-scm.com/book/en/Git-Branching-Rebasing
Aikaansaa seuraavankaltainen tilanne
------- master \ \--- haara
"rebeissaa" haara masteriin, eli aikaansaa seuraava tilanne:
------- master \ \--- haara
Varmista komennolla gitk --all
että tilanne on haluttu.
"mergeä" master vielä haaraan:
------- \ master \--- haara
Lopputuloksena pitäisi siis olla lineaarinen historia ja master sekä haara samassa. Varmista jälleen komennolla gitk --all
että kaikki on kunnossa.
Poista branch haara. Etsi googlaamalla komento jolla saat tuhottua branchin.
Tämä oli kurssin viimeinen git-tehtävä. Muista pitää git-rutiiniasi yllä päivittäin/viikoittain. Jos olet tehnyt kurssin kaikki git-tehtävät, tulet saamaan kurssisuorituksen myös Versionhallinta-kurssista (1 op). Jos git-tehtäviä on jäänyt tekemättä, ota yhteyttä välittömästi jos haluat saada Ohtun lisäksi myös Versionhallinaopintopisteen.
tehtävien kirjaus:
- Kirjaa tekemäsi tehtävät tänne
- huom: tehtävien palautuksen deadline on su 19.4. klo 23.59
palaute tehtävistä:
- Lisää viikon 1 tehtävässä 11 forkaamasi repositorion omalla nimelläsi olevaan hakemistoon tiedosto nimeltä viikko5
- tee viime viikon tehtävän tapaan pull-request
- anna tehtävistä palautetta avautuvaan lomakkeeseen
- huom: jos teeh tehtävät alkuviikosta, voi olla, että edellistä pull-requestiasi ei ole vielä ehditty hyväksyä ja et pääse vielä tekemään uutta requestia