import static com.google.common.base.Preconditions.checkNotNull;
import java.net.MalformedURLException;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.data.Sone.ShowCustomAvatars;
import net.pterodactylus.sone.data.Sone.SoneStatus;
+import net.pterodactylus.sone.data.SoneImpl;
import net.pterodactylus.sone.data.TemporaryImage;
import net.pterodactylus.sone.database.Database;
import net.pterodactylus.sone.database.DatabaseException;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
-import com.google.common.collect.Collections2;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.eventbus.EventBus;
/** Trusted identities, sorted by own identities. */
private final Multimap<OwnIdentity, Identity> trustedIdentities = Multimaps.synchronizedSetMultimap(HashMultimap.<OwnIdentity, Identity>create());
- /** All known albums. */
- private final Map<String, Album> albums = new HashMap<String, Album>();
-
- /** All known images. */
- private final Map<String, Image> images = new HashMap<String, Image>();
-
/** All temporary images. */
private final Map<String, TemporaryImage> temporaryImages = new HashMap<String, TemporaryImage>();
@Override
public Collection<Sone> getSones() {
synchronized (sones) {
- return Collections.unmodifiableCollection(sones.values());
+ return ImmutableSet.copyOf(sones.values());
}
}
@Override
public Collection<Sone> getLocalSones() {
synchronized (sones) {
- return Collections2.filter(sones.values(), new Predicate<Sone>() {
+ return FluentIterable.from(sones.values()).filter(new Predicate<Sone>() {
@Override
public boolean apply(Sone sone) {
return sone.isLocal();
}
- });
+ }).toSet();
}
}
synchronized (sones) {
Sone sone = sones.get(id);
if ((sone == null) && create) {
- sone = new Sone(id, true);
+ sone = new SoneImpl(id, true);
sones.put(id, sone);
}
if ((sone != null) && !sone.isLocal()) {
- sone = new Sone(id, true);
+ sone = new SoneImpl(id, true);
sones.put(id, sone);
}
return sone;
@Override
public Collection<Sone> getRemoteSones() {
synchronized (sones) {
- return Collections2.filter(sones.values(), new Predicate<Sone>() {
+ return FluentIterable.from(sones.values()).filter(new Predicate<Sone>() {
@Override
public boolean apply(Sone sone) {
return !sone.isLocal();
}
- });
+ }).toSet();
}
}
synchronized (sones) {
Sone sone = sones.get(id);
if ((sone == null) && create && (id != null) && (id.length() == 43)) {
- sone = new Sone(id, false);
+ sone = new SoneImpl(id, false);
sones.put(id, sone);
}
return sone;
synchronized (bookmarkedPosts) {
for (String bookmarkedPostId : bookmarkedPosts) {
Optional<Post> post = getPost(bookmarkedPostId);
- if (!post.isPresent()) {
+ if (post.isPresent()) {
posts.add(post.get());
}
}
return posts;
}
- /**
- * Returns the album with the given ID, creating a new album if no album
- * with the given ID can be found.
- *
- * @param albumId
- * The ID of the album
- * @return The album with the given ID
- */
- public Album getAlbum(String albumId) {
- return getAlbum(albumId, true);
+ public Optional<Album> getAlbum(String albumId) {
+ return database.getAlbum(albumId);
}
- /**
- * Returns the album with the given ID, optionally creating a new album if
- * an album with the given ID can not be found.
- *
- * @param albumId
- * The ID of the album
- * @param create
- * {@code true} to create a new album if none exists for the
- * given ID
- * @return The album with the given ID, or {@code null} if no album with the
- * given ID exists and {@code create} is {@code false}
- */
- public Album getAlbum(String albumId, boolean create) {
- synchronized (albums) {
- Album album = albums.get(albumId);
- if (create && (album == null)) {
- album = new Album(albumId);
- albums.put(albumId, album);
- }
- return album;
- }
- }
-
- /**
- * Returns the image with the given ID, creating it if necessary.
- *
- * @param imageId
- * The ID of the image
- * @return The image with the given ID
- */
- public Image getImage(String imageId) {
- return getImage(imageId, true);
- }
-
- /**
- * Returns the image with the given ID, optionally creating it if it does
- * not exist.
- *
- * @param imageId
- * The ID of the image
- * @param create
- * {@code true} to create an image if none exists with the given
- * ID
- * @return The image with the given ID, or {@code null} if none exists and
- * none was created
- */
- public Image getImage(String imageId, boolean create) {
- synchronized (images) {
- Image image = images.get(imageId);
- if (create && (image == null)) {
- image = new Image(imageId);
- images.put(imageId, image);
- }
- return image;
- }
+ public Optional<Image> getImage(String imageId) {
+ return database.getImage(imageId);
}
/**
logger.log(Level.WARNING, "Given OwnIdentity is null!");
return null;
}
+ logger.info(String.format("Adding Sone from OwnIdentity: %s", ownIdentity));
synchronized (sones) {
final Sone sone;
try {
}
}
database.storePostReplies(sone, sone.getReplies());
- synchronized (albums) {
- synchronized (images) {
- for (Album album : storedSone.get().getAlbums()) {
- albums.remove(album.getId());
- for (Image image : album.getImages()) {
- images.remove(image.getId());
- }
- }
- for (Album album : sone.getAlbums()) {
- albums.put(album.getId(), album);
- for (Image image : album.getImages()) {
- images.put(image.getId(), image);
- }
- }
+ for (Album album : storedSone.get().getRootAlbum().getAlbums()) {
+ database.removeAlbum(album);
+ for (Image image : album.getImages()) {
+ database.removeImage(image);
+ }
+ }
+ for (Album album : sone.getRootAlbum().getAlbums()) {
+ database.storeAlbum(album);
+ for (Image image : album.getImages()) {
+ database.storeImage(image);
}
}
synchronized (sones) {
sone.setOptions(storedSone.get().getOptions());
+ sone.setKnown(storedSone.get().isKnown());
+ sone.setStatus((sone.getTime() == 0) ? SoneStatus.unknown : SoneStatus.idle);
+ if (sone.isLocal()) {
+ soneInserters.get(storedSone.get()).setSone(sone);
+ touchConfiguration();
+ }
sones.put(sone.getId(), sone);
}
}
logger.log(Level.FINE, String.format("Tried to load non-local Sone: %s", sone));
return;
}
+ logger.info(String.format("Loading local Sone: %s", sone));
/* initialize options. */
sone.getOptions().addBooleanOption("AutoFollow", new DefaultOption<Boolean>(false));
}
/* load albums. */
- List<Album> topLevelAlbums = new ArrayList<Album>();
+ Map<String, Album> albums = Maps.newHashMap();
int albumCounter = 0;
while (true) {
String albumPrefix = sonePrefix + "/Albums/" + albumCounter++;
logger.log(Level.WARNING, "Invalid album found, aborting load!");
return;
}
- Album album = getAlbum(albumId).setSone(sone).setTitle(albumTitle).setDescription(albumDescription).setAlbumImage(albumImageId);
+ Album parentAlbum = sone.getRootAlbum();
if (albumParentId != null) {
- Album parentAlbum = getAlbum(albumParentId, false);
- if (parentAlbum == null) {
- logger.log(Level.WARNING, String.format("Invalid parent album ID: %s", albumParentId));
- return;
- }
- parentAlbum.addAlbum(album);
- } else {
- if (!topLevelAlbums.contains(album)) {
- topLevelAlbums.add(album);
- }
+ parentAlbum = albums.get(albumParentId);
}
+ Album album = parentAlbum.newAlbumBuilder().withId(albumId).build().modify().setTitle(albumTitle).setDescription(albumDescription).setAlbumImage(albumImageId).update();
+ albums.put(album.getId(), album);
}
/* load images. */
logger.log(Level.WARNING, "Invalid image found, aborting load!");
return;
}
- Album album = getAlbum(albumId, false);
+ Album album = albums.get(albumId);
if (album == null) {
logger.log(Level.WARNING, "Invalid album image encountered, aborting load!");
return;
}
- Image image = getImage(imageId).setSone(sone).setCreationTime(creationTime).setKey(key);
- image.setTitle(title).setDescription(description).setWidth(width).setHeight(height);
- album.addImage(image);
+ album.newImageBuilder().withId(imageId).created(creationTime).at(key).sized(width, height).build().modify().setTitle(title).setDescription(description).update();
}
/* load avatar. */
String avatarId = configuration.getStringValue(sonePrefix + "/Profile/Avatar").getValue(null);
if (avatarId != null) {
- profile.setAvatar(getImage(avatarId, false));
+ profile.setAvatar(getImage(avatarId).orNull());
}
/* load options. */
for (String friendId : friends) {
followSone(sone, friendId);
}
- sone.setAlbums(topLevelAlbums);
+ for (Album album : sone.getRootAlbum().getAlbums()) {
+ sone.getRootAlbum().removeAlbum(album);
+ }
soneInserters.get(sone).setLastInsertFingerprint(lastInsertFingerprint);
}
synchronized (knownSones) {
for (PostReply reply : replies) {
reply.setKnown(true);
}
+
+ logger.info(String.format("Sone loaded successfully: %s", sone));
}
/**
}
/**
- * Creates a new top-level album for the given Sone.
- *
- * @param sone
- * The Sone to create the album for
- * @return The new album
- */
- public Album createAlbum(Sone sone) {
- return createAlbum(sone, null);
- }
-
- /**
- * Creates a new album for the given Sone.
- *
- * @param sone
- * The Sone to create the album for
- * @param parent
- * The parent of the album (may be {@code null} to create a
- * top-level album)
- * @return The new album
- */
- public Album createAlbum(Sone sone, Album parent) {
- Album album = new Album();
- synchronized (albums) {
- albums.put(album.getId(), album);
- }
- album.setSone(sone);
- if (parent != null) {
- parent.addAlbum(album);
- } else {
- sone.addAlbum(album);
- }
- return album;
- }
-
- /**
* Deletes the given album. The owner of the album has to be a local Sone,
* and the album has to be {@link Album#isEmpty() empty} to be deleted.
*
if (!album.isEmpty()) {
return;
}
- if (album.getParent() == null) {
- album.getSone().removeAlbum(album);
- } else {
- album.getParent().removeAlbum(album);
- }
- synchronized (albums) {
- albums.remove(album.getId());
- }
+ album.getParent().removeAlbum(album);
+ database.removeAlbum(album);
touchConfiguration();
}
checkNotNull(temporaryImage, "temporaryImage must not be null");
checkArgument(sone.isLocal(), "sone must be a local Sone");
checkArgument(sone.equals(album.getSone()), "album must belong to the given Sone");
- Image image = new Image(temporaryImage.getId()).setSone(sone).setCreationTime(System.currentTimeMillis());
- album.addImage(image);
- synchronized (images) {
- images.put(image.getId(), image);
- }
+ Image image = album.newImageBuilder().withId(temporaryImage.getId()).createdNow().sized(temporaryImage.getWidth(), temporaryImage.getHeight()).build();
+ database.storeImage(image);
imageInserter.insertImage(temporaryImage, image);
return image;
}
checkArgument(image.getSone().isLocal(), "image must belong to a local Sone");
deleteTemporaryImage(image.getId());
image.getAlbum().removeImage(image);
- synchronized (images) {
- images.remove(image.getId());
- }
+ database.removeImage(image);
touchConfiguration();
}
* The encoded data of the image
* @return The temporary image
*/
- public TemporaryImage createTemporaryImage(String mimeType, byte[] imageData) {
- TemporaryImage temporaryImage = new TemporaryImage();
- temporaryImage.setMimeType(mimeType).setImageData(imageData);
+ public TemporaryImage createTemporaryImage(String mimeType, byte[] imageData, int width, int height) {
+ TemporaryImage temporaryImage = new TemporaryImage(mimeType, imageData, width, height);
synchronized (temporaryImages) {
temporaryImages.put(temporaryImage.getId(), temporaryImage);
}
synchronized (temporaryImages) {
temporaryImages.remove(imageId);
}
- Image image = getImage(imageId, false);
- if (image != null) {
- imageInserter.cancelImageInsert(image);
+ Optional<Image> image = getImage(imageId);
+ if (image.isPresent()) {
+ imageInserter.cancelImageInsert(image.get());
}
}
configuration.getStringValue(sonePrefix + "/Friends/" + friendCounter + "/ID").setValue(null);
/* save albums. first, collect in a flat structure, top-level first. */
- List<Album> albums = FluentIterable.from(sone.getAlbums()).transformAndConcat(Album.FLATTENER).toList();
+ List<Album> albums = FluentIterable.from(sone.getRootAlbum().getAlbums()).transformAndConcat(Album.FLATTENER).toList();
int albumCounter = 0;
for (Album album : albums) {
configuration.getStringValue(albumPrefix + "/ID").setValue(album.getId());
configuration.getStringValue(albumPrefix + "/Title").setValue(album.getTitle());
configuration.getStringValue(albumPrefix + "/Description").setValue(album.getDescription());
- configuration.getStringValue(albumPrefix + "/Parent").setValue(album.getParent() == null ? null : album.getParent().getId());
+ configuration.getStringValue(albumPrefix + "/Parent").setValue(album.getParent().equals(sone.getRootAlbum()) ? null : album.getParent().getId());
configuration.getStringValue(albumPrefix + "/AlbumImage").setValue(album.getAlbumImage() == null ? null : album.getAlbumImage().getId());
}
configuration.getStringValue(sonePrefix + "/Albums/" + albumCounter + "/ID").setValue(null);
@SuppressWarnings("synthetic-access")
public void run() {
Sone sone = getRemoteSone(identity.getId(), false);
+ if (sone.isLocal()) {
+ return;
+ }
sone.setIdentity(identity);
sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), sone.getLatestEdition()));
soneDownloader.addSone(sone);
@Subscribe
public void imageInsertFinished(ImageInsertFinishedEvent imageInsertFinishedEvent) {
logger.log(Level.WARNING, String.format("Image insert finished for %s: %s", imageInsertFinishedEvent.image(), imageInsertFinishedEvent.resultingUri()));
- imageInsertFinishedEvent.image().setKey(imageInsertFinishedEvent.resultingUri().toString());
+ imageInsertFinishedEvent.image().modify().setKey(imageInsertFinishedEvent.resultingUri().toString()).update();
deleteTemporaryImage(imageInsertFinishedEvent.image().getId());
touchConfiguration();
}