Assignment 3
Domain Analysis and System Design, 1st Iteration
apt-got
http://www.apt-got.com/
Jamie Fitz-Gerald jamiefitzgerald@umail.ucsb.edu
Jonas Jägerhök jonas_jagerhok@umail.ucsb.edu
Tobias Hertkorn t_hertkorn@umail.ucsb.edu
Project outline
Packages from the Debian-Distribution are obtained from public http-mirrors. To save bandwidth our program will function like a drop-in, stand-alone proxy for the internal network. But in addition it will store already requested packages locally. Packages that are not yet stored locally are fetched upon client-request from the parent server transparently.
Vision
Problem Statement
To write a program that improves the performance of the Linux Debian package update and install application named apt-get.
Key high-level goals
System features
Other requirements and constraints
Use case
Provide file
Main Actor:
Client wants to have a specific file. Requests it via internet (http-protocol).
Supporting Actor:
Remote Debian Server holds all available files in a directory structure. Files can be accessed via internet (http-protocol).
Basic Flow (or main success scenario):
Extensions (or alternative flow):
*a. At any time – System fails.
1. apt-got signals error.
2. Send “Internal Server error” to Client.
2a. No connection to Client
1. Do nothing.
3-6a. file already stored in local cache.
1. apt-got sends local file to Client.
3-6b. No connection to server
1. apt-got sends “file not found” to Client.
4-6c. File not Found
1. Remote Debian Server sends “file not found” to apt-got.
2. apt-got sends “file not found” to Client.
6d. No connection to client
1. Do nothing
Use case diagram
System sequence diagram
Activity Diagram
System Operation contracts
| Operation |
requestFile( fileName: String ) |
| Cross Reference |
Request File |
| Preconditions |
Connection to client is established |
| Postconditions |
A http request header from the client was received and the requested file was identified Response received |
| Operation |
lookForFile( fileName: String ) |
| Cross Reference |
Request File |
| Preconditions |
A valid filename was received from client |
| Postconditions |
Response received |
| Operation |
retrieveFileFromServer( fileName: String ) |
| Cross Reference |
Request File |
| Preconditions |
Connection to remote server is established |
| Postconditions |
Response received Connection to remote server closed |
| Operation |
storeFile( file: File ) |
| Cross Reference |
Request File |
| Preconditions |
File Found Enough disk space available |
| Postconditions |
File Object created with information about the retrieved file File saved locally |
| Operation |
sendFile( file: File ) |
| Cross Reference |
Request File |
| Preconditions |
Connection to client is established A file or a message was received from the control |
| Postconditions |
File or other message was sent to the client Connection to client closed |
Static Class and Package Diagrams
Class Specifications/Source Code
/** Java class "HttpRequestHeader.java"
* Purpose
* (c) Apt-Got Group, Tobias Hertkorn,
* Jonas Jägerhök
* Jamie Fitz-Gerald
*/
package com.debianmirror.http;
import java.lang.String;
import java.net.URI;
import java.util.*;
/**
* HttpRequestHeader parses a given String and breaks
* it into Key-Value pairs.
* It contains get-methods for the most common used keys
*/
public class HttpRequestHeader {
///////////////////////////////////////
// attributes
/**
* uRI represents the requested file URI
* found in the header
*/
private URI uRI;
///////////////////////////////////////
// operations
/**
* Returns the value of the key URI in the
* Header
*
* @return the URI related to this request
*/
public URI getURI() {
return this.uRI;
} // end getURI
/**
* Parses a given string for value key pairs.
* Stores the important values in local key variables
*
* @param header is a String representing the whole header
*/
private void createHeader(String header) {
// your code here
} // end createHeader
} // end HttpRequestHeader
/** Java class "MirrorControl.java"
* Purpose
* (c) Apt-Got Group, Tobias Hertkorn,
* Jonas Jägerhök
* Jamie Fitz-Gerald
*/
package com.debianmirror.mirror.control;
import com.debianmirror.mirror.data.MirrorFile;
import com.debianmirror.mirror.model.MirrorModule;
import java.net.URI;
import java.util.*;
/**
* Represents the interface to the mirror part of the project
* it contains a list of all configured mirror modules and will
* decide which module to use for the given URI
*/
class MirrorControl {
///////////////////////////////////////
// associations
/**
* The list of all configured mirrormodules
*/
public Collection mirrorModule = new ArrayList(); // of type MirrorModule
///////////////////////////////////////
// operations
/**
* Returns the MirrorFile associated with the given URI
*
* @return the MirrorFile represented by the uRI
* @param uRI the URI to the requested file
*/
public MirrorFile getMirrorFile(URI uRI) {
// your code here
return null;
} // end getMirrorFile
} // end MirrorControl
/** Java class "MirrorConf.java"
* Purpose
* (c) Apt-Got Group, Tobias Hertkorn,
* Jonas Jägerhök
* Jamie Fitz-Gerald
*/
package com.debianmirror.mirror.data;
import java.lang.String;
import java.net.URL;
import java.util.*;
/**
* Represents all configuration data needed to run the mirror
*/
public class MirrorConf {
///////////////////////////////////////
// attributes
/**
* Represents the URL to the root dir of the RemoteDebainServer archive
*/
private URL remoteHostURL;
/**
* Represents the local path to the root of the cache
*/
private String cachePath;
} // end MirrorConf
/** Java class "MirrorFile.java"
* Purpose
* (c) Apt-Got Group, Tobias Hertkorn,
* Jonas Jägerhök
* Jamie Fitz-Gerald
*/
package com.debianmirror.mirror.data;
import java.io.InputStream;
import java.lang.String;
import java.util.*;
import java.util.Date;
/**
* The MirrorFile represents a File that is ether locally mirrored or
* is currently requested from the RemoteDebianServer.
*/
public class MirrorFile {
///////////////////////////////////////
// attributes
/**
* Represents the last modified value of the File
*/
private Date lastModified;
/**
* Represents the lenght of the file
*/
private int length;
/**
* Represents the mime type of the file
*/
private String mimeType;
/**
* Represents the actual InputStream that can be used
* to read the data of the file
*/
private InputStream inputSream;
///////////////////////////////////////
// associations
/**
* contains all information needed to translate the fileName to a local store path
* and a remote request URL
*/
private MirrorConf mirrorConf;
///////////////////////////////////////
// operations
/**
* Translates the given fileName into a local store path
* if the file is not found there it creates the remote request URL
* and requests the file from the RemoteDebianServer
*
* @param fileName the file name representing the requested file
* @return the MirrorFile associated with the given file name
*/
public MirrorFile createMirrorFile(String fileName) {
// your code here
return null;
} // end createMirrorFile
/**
* Returns the InputStream of this File
*
*
* @return an InputStream of this File
*/
public InputStream getInputStream() {
// your code here
return null;
} // end getinputStream
} // end MirrorFile
/** Java class "MirrorFilePool.java"
* Purpose
* (c) Apt-Got Group, Tobias Hertkorn,
* Jonas Jägerhök
* Jamie Fitz-Gerald
*/
package com.debianmirror.mirror.data;
import java.lang.String;
import java.util.*;
/**
* Represents all files known to the mirrormodule
*/
public class MirrorFilePool {
///////////////////////////////////////
// associations
/**
* Stores the currently used MirrorFiles
*/
private Collection mirrorFile = new TreeSet(); // of type MirrorFile
///////////////////////////////////////
// operations
/**
* Will search the mirrorFile collection for the file.
* if non is found it initiates a new MirrorFile object
* represented by this fileName
*
* @param fileName what file to search for
* @return the MirrorFile
*/
public MirrorFile getMirrorFile(String fileName) {
// your code here
return null;
} // end getMirrorFile
} // end MirrorFilePool
/** Java class "MirrorModule.java"
* Purpose
* (c) Apt-Got Group, Tobias Hertkorn,
* Jonas Jägerhök
* Jamie Fitz-Gerald
*/
package com.debianmirror.mirror.model;
import com.debianmirror.mirror.data.MirrorConf;
import com.debianmirror.mirror.data.MirrorFile;
import com.debianmirror.mirror.data.MirrorFilePool;
import java.net.URI;
import java.util.*;
/**
* The MirrorModule represents one configured module
* The basic idea is to have one module per RemoteDebianServer.
* This will get extended, so that all known mirrors of this RemoteDebianServer
* will be represented by this module
*/
public class MirrorModule {
///////////////////////////////////////
// associations
/**
* contains the configuration of this mirrorModule
*/
private MirrorConf mirrorConf;
/**
* represents the FilePool used to request the MirrorFile from
*/
public MirrorFilePool mirrorFilePool;
///////////////////////////////////////
// operations
/**
* Asks the FilePool for the MirrorFile represented by the URI
*
*
* @param uRI The variable contains the information about which file was requested
* @return the MirrorFile that was requested.
*/
public MirrorFile getMirrorFile(URI uRI) {
// your code here
return null;
} // end getMirrorFile
} // end MirrorModule
/** Java class "AptGotHttpListener.java"
* Purpose
* (c) Apt-Got Group, Tobias Hertkorn,
* Jonas Jägerhök
* Jamie Fitz-Gerald
*/
package com.debianmirror.server.http;
import java.net.ServerSocket;
import java.util.*;
/**
* AptGotHttpListener will listen on the assigned
* listeningPort for incoming client requests.
* These client requests will be dispatched to
* the AptGotHttpWorkerFactory.
* After that it will return to listen for the next
* request.
*/
public class AptGotHttpListener {
///////////////////////////////////////
// attributes
/**
* Represents the port on which the AptGotHttpListener will
* listen for client connections.
* Needed to create the ServerSocket
*/
private int listeningPort;
/**
* Represents the ServerSocket. The Listener will use the
* accept() method to listen on it in blocking mode.
*/
private ServerSocket serverSocket;
/**
* The Listener (and therefor the Server) will run, as long
* as this variable is set to true.
*/
private boolean keepRunning;
///////////////////////////////////////
// associations
/**
* The listener dispatches the socket to the AptGotHttpWorkerFactory
*/
private AptGotHttpWorkerFactory aptGotHttpWorkerFactory;
} // end AptGotHttpListener
/** Java class "AptGotHttpWorker.java"
* Purpose
* (c) Apt-Got Group, Tobias Hertkorn,
* Jonas Jägerhök
* Jamie Fitz-Gerald
*/
package com.debianmirror.server.http;
import com.debianmirror.http.HttpRequestHeader;
import com.debianmirror.mirror.control.MirrorControl;
import java.lang.String;
import java.net.Socket;
import java.util.*;
/**
* The AptGotHttpWorker is responsible for talking to the client.
* This includes receiving the request header and sending the file
* or any given error back to the client
*/
public class AptGotHttpWorker {
///////////////////////////////////////
// attributes
/**
* The Socket represents the connection to the client.
* As long as there is no work assigned this variable must
* be equal to null
*/
private Socket s = null;
///////////////////////////////////////
// associations
/**
* The HttpRequestHeader will contain all information associated
* with the client connection. Is equal to null when there is no
* work assigned
*/
private HttpRequestHeader httpRequestHeader;
/**
* The MirrorControl represents the layer below this worker
* The worker will request the file from MirrorControl.
*/
public MirrorControl mirrorControl;
///////////////////////////////////////
// operations
/**
* creates a new HttpRequestHeader by giving it the given
* header String
*
* @return a new HttpRequestHeader representing the given header
* @param header a String containing all unparsed header information
*/
private HttpRequestHeader createHeader(String header) {
// your code here
return null;
} // end createHeader
} // end AptGotHttpWorker
/** Java class "AptGotHttpWorkerFactory.java"
* Purpose
* (c) Apt-Got Group, Tobias Hertkorn,
* Jonas Jägerhök
* Jamie Fitz-Gerald
*/
package com.debianmirror.server.http;
import java.net.Socket;
import java.util.*;
/**
* This factory produces or reuses one Worker per
* request and assigns a socket to this Worker
*
* @author Tobias Hertkorn
*/
public class AptGotHttpWorkerFactory {
///////////////////////////////////////
// associations
/**
* Contains a list of available idle workers
*
*/
private Collection idleWorkerList = new ArrayList(); // of type AptGotHttpWorker
///////////////////////////////////////
// operations
/**
* AptGotHttpWorkerFactory receives a socket by the use
* of this method. This Socket will be handed to the
* Worker assigned for this connection
*
* @param s
*/
public void setSocket(Socket s) {
// your code here
} // end setSocket
/**
* Will create a new AptGotHttpWorker and assignes the Socket to it
* so it will start working on this socket right away.
*
* @return a new AptGotHttpWorker with the Socket s already assigned
* @param s The socket to be assigned to the new
*/
private AptGotHttpWorker createWorker(Socket s) {
// your code here
return null;
} // end createWorker
} // end AptGotHttpWorkerFactory
Interaction Diagrams
Additional Informations
Class/Package Responsibility
View
//provide frontend
com.debianmirror.StandAloneAptGot
Main method
Starts the stand alone server
com.debianmirror.StandAloneAptGotConf
Parses the StandAloneAptGot.props file for
- info about the class name of the mirror configuration data
- the listenerPort
- the nrOfWorkers
com.debianmirror.server.http.AptGotHttpServer
Starts the HttpListener
com.debianmirror.server.http.HttpListener
Listens for http requests on assigned port
Hands new connections to AptGotHttpWorkerFactory
com.debianmirror.server.http.AptGotHttpWorkerFactory
Initializes new AptGotHttpWorker
Keeps a list of running AptGotHttpWorker
Assigns the connection to an AptGotHttpWorker
com.debianmirror.server.http.AptGotHttpWorker
Parses the request header by the use of HttpRequestHeader
Requests file from Control
Create the response header by the use of HttpResponseHeader
Sends response header by the use of HttpResponseHeader
Sends file data if applicable
Control
//decide which module handles the request
com.debianmirror.mirror.control.MirrorControl
Is interface for View to communicate with Control
com.debianmirror.mirror.control.MirrorControlImpl
Implements MirrorControl
Requests list of configured MirrorModule from MirrorControlConf
Holds a list of all the configured MirrorModule
Breaks down file URL string so it can dispatch it to the right MirrorModule
Requests file from that MirrorModule
Gives file or error to AptGotHttpWorker
Model
//all the logic for the file handling
com.debianmirror.mirror.model.MirrorModule
Is interface for Control to communicate with Model
com.debianmirror.mirror.model.debian.DebianMirrorModule
Implements MirrorModule
Initializes FilePool
Gets file URL from Control
Decide if Debian package/regular file or Debian package list
1.) Debian package/regular file
Translates links
Generate
- relative location to find/store file with information stored in DebianMirrorModuleConf
- list of locations to download file if not found locally with information stored in DebianMirrorModuleConf
Requests file by passing these information on to FilePool
Gives file or error to MirrorControlImpl
2.) Debian package list
for now – handle as if regular Debian package
later: Generate/update package list if appropriate
Data
//data storage and data maintenance (especially what to purge and what to re-request)
com.debianmirror.mirror.data.MirrorFilePool
Is interface to Control to communicate to Data
com.debianmirror.mirror.data.debian.DebianMirrorFilePool
Has a WeakHashMap of MirrorFiles
Decides what and when to purge (not what to re-request)
Translate relative storage path into an absolute path
com.debianmirror.mirror.data.MirrorFile
Interface for Pool
com.debianmirror.mirror.data.SimpleMirrorFile
takes absolute storage path and remote mirror list
requests file from mirrors if not locally stored or modified on server
stores new file locally
holds FileInputStream (must be synchronized on! So we can switch association from URLConnection to FileInputStream. How do we handle concurrent reads on the InputStream? How does it react… Always use read(byte[] b, int off, int len)!!!)
holds fileLength
holds mimeType
creates a unique hash for hash map. Must create different hash for different files (not only filenames) and same hash for same file!!!
com.debianmirror.mirror.data.DebianMirrorConf
implements MirrorControlConf and DebianMirrorModuleConf
holds information