Welcome to DLIBRARY’s documentation!¶
Team: | 1409 DLIBRARY |
---|---|
Members: |
|
DLIBRARY is a simple book collection manager application. It helps users collect their book collection information in the database The book database can manage various author, publisher and dealer information. It gives admin user permission to change the list of authors, publishers and dealers as well as list of books. Admin user can also edit the user list and their info.
In this project we used a SQLite database with Apache’s Wicket Framework to build it. We created several collections to manage records in database.
Contents:
User Guide¶
DLIBRARY has a simple UI. Most of its functionality needs authentication.
This is the homepage:
Parts Implemented by Besim Ongun Kanat¶
User and Login System¶
New users can register themselves in Registration page
After registration users can easily login from navigation bar:
According to data taken from user it will show the one of the messages below:
![]() |
![]() |
My Collection option & user info will be visible after a successful login.
Administrator users have one extra link in the navbar that goes to User operations page
Administrators can add, edit and delete users
User’s Book Collection¶
In the book list user can add book to his/her collection via the link in Book List page
And remove them in the My Collection Page
Advanced Book Filtering¶
In the books page there is a filter box. Users can search a book by name, author, genre, publisher, ISBN, year and dealer or any combination of them
The results are shown in the results page:
Parts Implemented by Furkan Aksın¶
Genre, Summary and Keyword¶
Genres can be listed in Genres tab on Navigation Bar. Users can see all the genres in that list.
Admin can see Genres list with chekcboxes and Add and Delete Buttons.
Admin can add, delete or edit any genres.
Keywords are shown in Book Display Page.
Summaries are just placed in SQL Database. They are not shown on interface.
Parts Implemented by Mehmet Taner Ünal¶
Publishers¶
Publishers can be listed in Publishers tab on Navigation Bar. Users can see all the publishers on the list.
Only admin can see and use checkboxes, Add, Delete and Edit Buttons on Publisher List.
Add, Delete and Edit features can be used by Admin.
Book Information Page¶
Informations of the books can be seen by just clicking on them.
Book informations like author, publisher, ISBN, available dealers, genres, keywords can be seen on Book Info page.
Parts Implemented by Ozan Özyeğen¶
Dealer, Price and Rent Info¶
Dealers can be listed by clicking the Dealers tab on the Navigation Bar. Users can only see the Dealers List.
Admins can see Dealers List with the checkboxes and Add, Delete and Edit Buttons.
Admin can add, delete or edit any Dealer.
Parts Implemented by Müşerref Ebru Özaltın¶
Developer Guide¶
Git Workflow¶
In the coding stage we often used GIT’s branching model. It helped us to work parallel. We have created our own branches and as seen below there are many merges to master branch.

Parts Implemented by Besim Ongun Kanat¶
Initialization¶
The startup code initializes the database file for use by reading and executing statements that are in init.sql file Then it will create collections for general use. Our class extends a special type of Application from Wicket library called AuthenticatedWebApplication because we use user authentication.
public class WicketApplication extends AuthenticatedWebApplication
{
private IUserCollection userCollection;
private IAuthorCollection authorCollection;
private IPublisherCollection publisherCollection;
private IDealerCollection dealerCollection;
private IBookCollection bookCollection;
private IGenreCollection genreCollection;
private Connection database;
@Override
public void init()
{
super.init();
String homeDir = System.getProperty("user.home");
String dbPath = homeDir + File.separator + "dlibrary.sqlite";
File dbFile = new File(dbPath);
if (dbFile.exists())
dbFile.delete();
try
{
Class.forName("org.sqlite.JDBC");
}
catch (ClassNotFoundException exc)
{
throw new UnsupportedOperationException(exc.getMessage());
}
try
{
this.database = DriverManager.getConnection("jdbc:sqlite:" + dbPath);
}
catch (SQLException exc)
{
throw new UnsupportedOperationException(exc.getMessage());
}
// Auto Database Creation Code
ServletContext context = getServletContext();
InputStream stream = context.getResourceAsStream("/WEB-INF/init.sql");
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String line;
try
{
while ((line = reader.readLine()) != null)
{
Statement stmt = database.createStatement();
stmt.executeUpdate(line);
stmt.close();
}
}
catch (IOException exc)
{
throw new UnsupportedOperationException(exc.getMessage());
}
catch (SQLException exc)
{
throw new UnsupportedOperationException(exc.getMessage());
}
userCollection = new UserCollectionJDBC(database);
authorCollection = new AuthorCollectionJDBC(database);
publisherCollection = new PublisherCollectionJDBC(database);
dealerCollection = new DealerCollectionJDBC(database);
bookCollection = new BookColletionJDBC(database);
genreCollection = new GenreCollectionJDBC(database);
}
@Override
public Class<? extends WebPage> getHomePage()
{
return HomePage.class;
}
@Override
protected Class<? extends WebPage> getSignInPageClass()
{
return LoginPage.class;
}
@Override
protected Class<? extends AbstractAuthenticatedWebSession> getWebSessionClass()
{
return DLibraryLoginSession.class;
}
//GETTERS AND SETTERS
}
Abstract Collection¶
AbstractJDBCCollection is a simple helper abstract class its only purpose is preventing collections repeat the code of connection process again and again. The clases that extend AbstractJDBCCollection need to implement a constructor which takes an Connection type argument. The class will provide _db variable for subclasses.
/*
* Abstract class for creating collections with Database connection
* Written in order not to rewrite Connection code again and again.
*
* Group members should implement Collection classes extending this
* class.
*/
public abstract class AbstractJDBCCollection
{
protected Connection _db;
public AbstractJDBCCollection(Connection dbConnection)
{
try
{
if (!dbConnection.isClosed())
_db = dbConnection;
else
throw new UnsupportedOperationException("Connection that was sent is closed");
} catch (SQLException exc)
{
throw new UnsupportedOperationException(exc.getMessage());
}
}
}
Login Process¶
The login check is performed by DLibraryLoginSession class. It extends AuthenticatedWebSession from Wicket library. authenticate method is the key here. Wicket provides a level of abstraction here and we only need to create a method that returns true or false, almost all session operations are handeled by Wicket. The method calls the checkUserLogin method of IUserCollection interface, which is implemented by UserCollectionJDBC, then load user info to session.
public class DLibraryLoginSession extends AuthenticatedWebSession
{
private User loggedUser = null;
// .......... CONSTRUCTOR
@Override
public boolean authenticate(String username, String password)
{
WicketApplication app = (WicketApplication) getApplication();
if (app.getUserCollection().checkUserLogin(username, password))
{
loggedUser = app.getUserCollection().getUserByName(username);
return true;
}
else
{
return false;
}
}
// ....... GETTERS AND EMPTY-IMPLEMENTED METHODS
}
User Collection¶
The UserCollectionJDBC class that implements IUserCollection interface, provides simple user operations add, edit, delete, get a list of users and lookup a user with a particular name. checkUserLogin is a special method that checks wheter a particular username and password matches.
public interface IUserCollection
{
public List<User> getUserList();
public User getUserByName(String name);
public boolean checkUserLogin(String name, String password);
public void addUser(User user);
public void deleteUser(User user);
public void updateUser(User user, User newUserData);
}
Book filtering¶
The filtering operation in BookCollectionJDBC is done with intersecting different SQL queries. The queries and their keys stored in two arrays and they are added to one last query string and a prepared statement. Then the prepared statement is executed
public class BookColletionJDBC extends AbstractJDBCCollection implements IBookCollection
{
//OTHER CODES...
public List<Book> getFilteredBooks(BookFilterOptions filter)
{
List<String> queries = new ArrayList<String>();
List<Object> keys = new ArrayList<Object>();
if (filter.getTitle() != null)
{
queries.add("SELECT * FROM Books WHERE title LIKE ?");
String[] l = { "%" + filter.getTitle() + "%" };
keys.addAll(Arrays.asList(l));
}
if (filter.getAuthor() != null)
{
queries.add("SELECT * FROM Books WHERE id IN (SELECT book_id FROM Authorship WHERE author_id = ?)");
Integer[] l = { filter.getAuthor().getId() };
keys.addAll(Arrays.asList(l));
}
if (filter.getDealer() != null)
{
queries.add("SELECT * FROM Books WHERE id IN (SELECT book_id FROM Book_Dealers WHERE dealer_id = ?)");
Integer[] l = { filter.getDealer().getId() };
keys.addAll(Arrays.asList(l));
}
if (filter.getPublisher() != null)
{
queries.add("SELECT * FROM Books WHERE publisher_id = ?");
Integer[] l = { filter.getPublisher().getId() };
keys.addAll(Arrays.asList(l));
}
if (filter.getGenre() != null)
{
queries.add("SELECT * FROM Books WHERE publisher_id = (SELECT book_id FROM Book_Genres WHERE genre_id = ?)");
Integer[] l = { filter.getGenre().getId() };
keys.addAll(Arrays.asList(l));
}
if (filter.getFirstYear() != null)
{
queries.add("SELECT * FROM Books WHERE year >= ?");
Integer[] l = { Integer.parseInt(filter.getFirstYear()) };
keys.addAll(Arrays.asList(l));
}
if (filter.getLastYear() != null)
{
queries.add("SELECT * FROM Books WHERE year <= ?");
Integer[] l = { Integer.parseInt(filter.getLastYear()) };
keys.addAll(Arrays.asList(l));
}
if (filter.getIsbn() != null)
{
queries.add("SELECT * FROM Books WHERE isbn = ?");
String[] l = { filter.getIsbn() };
keys.addAll(Arrays.asList(l));
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < queries.size(); i++)
{
sb.append(queries.get(i));
if (i != queries.size() - 1)
sb.append(" INTERSECT ");
}
try
{
PreparedStatement statement = _db.prepareStatement(sb.toString());
for (int i = 0; i < keys.size(); i++)
{
statement.setObject(i + 1, keys.get(i));
}
return HandleListStatements(statement);
}
catch (SQLException exc)
{
throw new UnsupportedOperationException(exc.getMessage(), exc);
}
}
//OTHER CODES..
}
CSS and HTML Site Design¶
The CSS of DLIBRARY is totaly handwritten, simple and minimal. There are a few helper classes like .clearfix and layout classes like .center-big. The .well class Is a simple rounded-corner-box with a background that used many places in code. One significant visual addition is a custom list view that is achived by modifying a ul element look like a select element
.center-big
{
width: 50%;
margin-left: 25%;
}
.clearfix /* Clearfixing content */
{
overflow: hidden;
}
.well
{
overflow: hidden;
border-radius: 5px;
clear: both;
margin: 5px;
padding: 15px 5px 15px;
font-size: 18px;
}
.well.red
{
background-color: #ffb2b2;
color: #a60000;
}
.well.yellow
{
background-color: #fff792;
color: #E04300;
}
form.form ul
{
border: none;
border-radius: 7px;
background: #fff;
overflow: auto;
max-height: 100px;
width: 350px;
float:left;
display: block;
list-style: none;
padding: 10px;
margin-bottom: 10px;
}
Parts Implemented by Furkan Aksın¶
Genre Data Type¶
Genre Data Type is created with neccessary functions.
public class Genre implements Serializable
{
private int id;
private String name;
public final int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public final String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
Genre ListView¶
ListView object is created for listing Genres on the Genres tab.
ListView genreListView = new ListView("genre_list", genres)
{
protected void populateItem(ListItem item)
{
final Genre genre = (Genre) item.getModelObject();
item.add(new Label("name", genre.getName()));
Link editGenre = new Link("editLink")
{
@Override
public void onClick()
{
setResponsePage(new GenreAddEdit(genre, false));
}
};
Check checkBox = new Check("selected", item.getModel());
checkBox.setVisible(loginSession.isSignedIn() && loginSession.getLoggedUser().isAdmin());
editGenre.setVisible(loginSession.isSignedIn() && loginSession.getLoggedUser().isAdmin());
item.add(editGenre);
item.add(checkBox);
}
};
IGenreCollection¶
public interface IGenreCollection
{
public List<Genre> getGenreList();
public Genre getGenreByName(String name);
public void addGenre(Genre genre);
public void deleteGenre(Genre genre);
public void updateGenre(Genre genre, Genre newGenreData);
}
GenreCollectionJDBC¶
public List<Genre> getGenreList()
{
LinkedList<Genre> list = new LinkedList<Genre>();
try
{
Statement statement = _db.createStatement();
ResultSet results = statement.executeQuery("SELECT id, name FROM Genres");
while (results.next())
{
Genre current = new Genre();
current.setId(results.getInt("id"));
current.setName(results.getString("name"));
list.add(current);
}
results.close();
statement.close();
}
catch (SQLException exc)
{
throw new UnsupportedOperationException(exc.getMessage());
}
return list;
}
Parts Implemented by Mehmet Taner Ünal¶
Book Information Page¶
In the BookInfo.java file, required labels are created for BookInfo.html. So when the books are clicked, directly this page will be opened with the book’s informations. Informations are reached using book argument.
public class BookInfo extends TemplatePage
{
public BookInfo(Book book)
{
final DLibraryLoginSession loginSession = (DLibraryLoginSession) AuthenticatedWebSession.get();
WicketApplication app = (WicketApplication) getApplication();
this.add(new Label("isbn", book.getIsbn()));
this.add(new Label("year", book.getYear()));
this.add(new Label("publisher", book.getPublisher().getName()));
this.add(new Label("title", book.getTitle()));
ListView authorList = new ListView("authorList", book.getAuthors())
{
@Override
protected void populateItem(ListItem subitem)
{
subitem.add(new Label("authorName", ((Author) subitem.getModelObject()).getName()));
}
};
this.add(authorList);
ListView dealerList = new ListView("dealerList", book.getDealers())
{
@Override
protected void populateItem(ListItem subitem)
{
subitem.add(new Label("dealerName", ((Dealer) subitem.getModelObject()).getName()));
}
};
this.add(dealerList);
ListView genreList = new ListView("genreList", book.getGenres())
{
@Override
protected void populateItem(ListItem subitem)
{
subitem.add(new Label("genreName", ((Genre) subitem.getModelObject()).getName()));
}
};
this.add(genreList);
ListView keywordList = new ListView("keywordList", book.getKeywords())
{
@Override
protected void populateItem(ListItem subitem)
{
subitem.add(new Label("keywordName", ((Keyword) subitem.getModelObject()).getKeyword()));
}
};
this.add(keywordList);
}
}
Publisher Collection¶
The PublisherCollectionJDBC class that implements IPublisherCollection interface, provides simple publisher operations add, update, delete, get a list of publishers and lookup a publisher with a specific name.
public interface IPublisherCollection
{
public List<Publisher> getPublisherList();
public Publisher getPublisherByName(String name);
public void addPublisher(Publisher publisher);
public void deletePublisher(Publisher publisher);
public void updatePublisher(Publisher publisher, Publisher newPublisherData);
}
Recommendation Collection¶
The RecommendationCollectionJDBC class that implements IRecommendationCollection interface, provides simple operations add, update, delete, get a list of all recommendations and lookup a recommended book’s id with a specific book id. Recommendations part could not be completed, but can work fine with direct database inputs.
public interface IRecommendationCollection
{
public List<Recommendation> getRecommendationList();
public Recommendation getRecommendationById(int id);
public void addRecommendation(Recommendation recommendation);
public void deleteRecommendation(Recommendation recommendation);
public void updateRecommendation(Recommendation recommendation, Recommendation newRecommendationData);
}
Parts Implemented by Ozan Özyeğen¶
Dealers List¶
DealersList.java is created to show all the dealers and provide an interface to admins in a way that they can add, delete and edit dealers.
CheckGroup dealerCheckGroup = new CheckGroup("selected_dealers", selectedDealers);
ListView DealerListView = new ListView("dealer_list", dealers)
{
@Override
protected void populateItem(ListItem item)
{
final Dealer dealer = (Dealer) item.getModelObject();
item.add(new Label("name", dealer.getName()));
Link editDealer = new Link("editLink")
{
@Override
public void onClick()
{
setResponsePage(new DealerAddEdit(dealer, false));
}
};
Check checkBox = new Check("selected", item.getModel());
checkBox.setVisible(loginSession.isSignedIn() && loginSession.getLoggedUser().isAdmin());
editDealer.setVisible(loginSession.isSignedIn() && loginSession.getLoggedUser().isAdmin());
item.add(editDealer);
item.add(checkBox);
}
};
dealerCheckGroup.add(DealerListView);
Form deleteForm = new Form("deleteDealerForm")
{
@Override
protected void onSubmit()
{
for (Dealer current : selectedDealers)
{
dealerCollection.deleteDealer(current);
}
setResponsePage(new DealerList());
}
};
Label deleteButton = new Label("btnDeleteDealer", "Delete");
Link addButton = new Link("btnAddDealer")
{
@Override
public void onClick()
{
setResponsePage(new DealerAddEdit());
}
};
Visibility¶
Pages are designed in such a way that only admins can see the Add,Delete Button checkboxes and Edit Labels.
Example
checkBox.setVisible(loginSession.isSignedIn() && loginSession.getLoggedUser().isAdmin());
editDealer.setVisible(loginSession.isSignedIn() && loginSession.getLoggedUser().isAdmin());
addButton.setVisible(loginSession.isSignedIn() && loginSession.getLoggedUser().isAdmin());
deleteButton.setVisible(loginSession.isSignedIn() && loginSession.getLoggedUser().isAdmin());
IDealerCollection¶
public interface IDealerCollection
{
public List<Dealer> getDealerList();
public Dealer getDealerByName(String name);
public void addDealer(Dealer dealer);
public void deleteDealer(Dealer dealer);
public void updateDealer(Dealer dealer, Dealer newDealerData);
public List<PricedDealer> getPricedDealerList();
}
PricedDealer Datatype¶
public class PricedDealer extends Dealer implements Serializable
{
private double price;
public double getPrice()
{
return price;
}
public void setPrice(double price)
{
this.price = price;
}
}