Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
robbyn committed Sep 12, 2014
1 parent 693b7e8 commit 68a945a
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 18 deletions.
116 changes: 115 additions & 1 deletion src/org/tastefuljava/gianadda/catalog/CatalogSession.java
@@ -1,19 +1,27 @@
package org.tastefuljava.gianadda.catalog;

import java.io.Closeable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.ibatis.session.SqlSession;
import org.tastefuljava.gianadda.domain.CurrentMapper;
import org.tastefuljava.gianadda.domain.Folder;
import org.tastefuljava.gianadda.domain.Mapper;
import org.tastefuljava.gianadda.domain.Picture;

public class CatalogSession implements Closeable {
private final SqlSession session;
private final WeakCache<Integer,Picture> picCache = new WeakCache<>();
private final WeakCache<Integer,Folder> folderCache = new WeakCache<>();

CatalogSession(SqlSession session) {
boolean ok = false;
this.session = session;
try {
Mapper map = session.getMapper(Mapper.class);
CurrentMapper.set(map);
CurrentMapper.set(new Wrapper(map));
ok = true;
} finally {
if (!ok) {
Expand All @@ -31,4 +39,110 @@ public void close() {
CurrentMapper.set(null);
session.close();
}

private class Wrapper implements Mapper {
private final Mapper delegate;

private Wrapper(Mapper delegate) {
this.delegate = delegate;
}

@Override
public Picture getPictureById(int id) {
Picture pic = picCache.get(id);
if (pic != null) {
return pic;
}
pic = delegate.getPictureById(id);
if (pic != null) {
picCache.put(id, pic);
}
return pic;
}

@Override
public Picture getPictureByName(int folderId, String name) {
Picture pic = delegate.getPictureByName(folderId, name);
return pic == null ? null : picCache.getOrPut(pic.getId(), pic);
}

@Override
public List<Picture> getFolderPictures(int folderId) {
List<Picture> result = new ArrayList<>();
for (Picture pic: delegate.getFolderPictures(folderId)) {
result.add(picCache.getOrPut(pic.getId(), pic));
}
return result;
}

@Override
public void insertPicture(Picture pic) {
delegate.insertPicture(pic);
picCache.put(pic.getId(), pic);
}

@Override
public void updatePicture(Picture pic) {
delegate.updatePicture(pic);
}

@Override
public void deletePicture(int id) {
delegate.deletePicture(id);
picCache.remove(id);
}

@Override
public Folder getFolderById(int id) {
Folder folder = folderCache.get(id);
if (folder != null) {
return folder;
}
folder = delegate.getFolderById(id);
if (folder != null) {
folderCache.put(id, folder);
}
return folder;
}

@Override
public Folder getFolderByName(int folderId, String name) {
Folder folder = delegate.getFolderByName(folderId, name);
return folder == null
? null : folderCache.getOrPut(folder.getId(), folder);
}

@Override
public Folder getRootFolder(String name) {
Folder folder = delegate.getRootFolder(name);
return folder == null
? null : folderCache.getOrPut(folder.getId(), folder);
}

@Override
public List<Folder> getSubfolders(int folderId) {
List<Folder> result = new ArrayList<>();
for (Folder folder: delegate.getSubfolders(folderId)) {
result.add(folderCache.getOrPut(folder.getId(), folder));
}
return result;
}

@Override
public void insertFolder(Folder folder) {
delegate.insertFolder(folder);
folderCache.put(folder.getId(), folder);
}

@Override
public void updateFolder(Folder folder) {
delegate.updateFolder(folder);
}

@Override
public void deleteFolder(int id) {
delegate.deleteFolder(id);
folderCache.remove(id);
}
}
}
69 changes: 69 additions & 0 deletions src/org/tastefuljava/gianadda/catalog/WeakCache.java
@@ -0,0 +1,69 @@
package org.tastefuljava.gianadda.catalog;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class WeakCache<K,T> {
private static final Logger LOG
= Logger.getLogger(WeakCache.class.getName());

private final Map<K,Ref> map = new HashMap<>();
private ReferenceQueue<T> refQueue = new ReferenceQueue<>();

public void put(K key, T obj) {
cleanup();
map.put(key, new Ref(key, obj));
}

public T get(K key) {
cleanup();
Ref ref = map.get(key);
return ref == null ? null : ref.get();
}

public T getOrPut(K key, T obj) {
cleanup();
Ref ref = map.get(key);
T result = ref == null ? null : ref.get();
if (result != null) {
return result;
}
map.put(key, new Ref(key, obj));
return obj;
}

public T remove(K key) {
cleanup();
Ref ref = map.remove(key);
return ref == null ? null : ref.get();
}

public void clear() {
map.clear();
refQueue = new ReferenceQueue<>();
}

private void cleanup() {
while (refQueue.poll() != null) {
try {
Ref ref = (Ref)refQueue.remove(1);
map.remove(ref.key);
} catch (IllegalArgumentException | InterruptedException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
}

private class Ref extends WeakReference<T> {
private final K key;

public Ref(K key, T obj) {
super(obj, refQueue);
this.key = key;
}
}
}
93 changes: 83 additions & 10 deletions src/org/tastefuljava/gianadda/domain/Folder.java
@@ -1,14 +1,20 @@
package org.tastefuljava.gianadda.domain;

import java.util.Set;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.tastefuljava.gianadda.util.Util;

public class Folder {
private int id;
private Integer parentId;
private Folder parent;
private String name;
private String title;
private String description;
private Map<String,Picture> pictures;
private Map<String,Folder> folders;

public static Folder getRoot(String name) {
return CurrentMapper.get().getRootFolder(name);
Expand All @@ -19,11 +25,13 @@ public int getId() {
}

public Folder getParent() {
return parentId == null ? null : CurrentMapper.get().getFolderById(id);
requireParent();
return parent;
}

public void setParent(Folder parent) {
this.parentId = parent == null ? null : parent.getId();
this.parent = parent;
}

public String getName() {
Expand Down Expand Up @@ -52,51 +60,116 @@ public void setDescription(String description) {

public void insert() {
CurrentMapper.get().insertFolder(this);
requireParent();
if (parent != null) {
parent.folderInserted(this);
}
}

public void update() {
CurrentMapper.get().updateFolder(this);
requireParent();
if (parent != null) {
parent.folderUpdated(this);
}
}

public void delete() {
CurrentMapper.get().deleteFolder(id);
requireParent();
if (parent != null) {
parent.folderDeleted(this);
}
}

public boolean isRoot() {
return parentId == null;
}

public int getLevel() {
Folder parent = getParent();
requireParent();
return parent == null ? 0 : parent.getLevel()+1;
}

public String getPath() {
Folder parent = getParent();
requireParent();
return parent == null || parent.isRoot()
? name : parent.getPath() + "/" + name;
}

public String getUrlPath() {
Folder parent = getParent();
requireParent();
String esc = Util.urlEncode(name);
return parent == null || parent.isRoot()
? esc : parent.getUrlPath() + "/" + esc;
}

public Picture getPicture(String name) {
return CurrentMapper.get().getPictureByName(id, name);
requirePictures();
return pictures.get(name);
}

public Set<Picture> getPictures() {
return CurrentMapper.get().getFolderPictures(id);
public List<Picture> getPictures() {
requirePictures();
return new ArrayList<>(pictures.values());
}

public Folder getSubfolder(String name) {
return CurrentMapper.get().getFolderByName(id, name);
}

public Set<Folder> getSubfolders() {
return CurrentMapper.get().getSubfolders(id);
public List<Folder> getSubfolders() {
requireFolders();
return new ArrayList<>(folders.values());
}

private void requireParent() {
if (parent == null && parentId != null) {
parent = CurrentMapper.get().getFolderById(parentId);
}
}

private void requirePictures() {
if (pictures == null) {
pictures = new TreeMap<>();
for (Picture pic: CurrentMapper.get().getFolderPictures(id)) {
pictures.put(pic.getName(), pic);
}
}
}

void pictureInserted(Picture pic) {
requirePictures();
pictures.put(pic.getName(), pic);
}

void pictureUpdated(Picture pic) {
}

void pictureDeleted(Picture pic) {
requirePictures();
pictures.remove(pic.getName());
}

private void requireFolders() {
if (folders == null) {
folders = new TreeMap<>();
for (Folder child: CurrentMapper.get().getSubfolders(id)) {
folders.put(child.getName(), child);
}
}
}

private void folderInserted(Folder child) {
requireFolders();
folders.put(child.getName(), child);
}

private void folderUpdated(Folder child) {
}

private void folderDeleted(Folder child) {
requireFolders();
folders.remove(child.getName());
}
}
6 changes: 3 additions & 3 deletions src/org/tastefuljava/gianadda/domain/Mapper.java
@@ -1,13 +1,13 @@
package org.tastefuljava.gianadda.domain;

import java.util.Set;
import java.util.List;
import org.apache.ibatis.annotations.Param;

public interface Mapper {
Picture getPictureById(int id);
Picture getPictureByName(@Param("folderId") int folderId,
@Param("name") String name);
Set<Picture> getFolderPictures(int folderId);
List<Picture> getFolderPictures(int folderId);
void insertPicture(Picture pic);
void updatePicture(Picture pic);
void deletePicture(int id);
Expand All @@ -16,7 +16,7 @@ Picture getPictureByName(@Param("folderId") int folderId,
Folder getFolderByName(@Param("folderId") int folderId,
@Param("name") String name);
Folder getRootFolder(String name);
Set<Folder> getSubfolders(int folderId);
List<Folder> getSubfolders(int folderId);
void insertFolder(Folder folder);
void updateFolder(Folder folder);
void deleteFolder(int id);
Expand Down

0 comments on commit 68a945a

Please sign in to comment.