/*
* Copyright (C) 2012 maartenl
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package mmud.rest.services;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import mmud.Attributes;
import mmud.database.entities.characters.User;
import mmud.database.entities.game.Guild;
import mmud.database.entities.game.Guildrank;
import mmud.database.entities.game.GuildrankPK;
import mmud.exceptions.MudException;
import mmud.exceptions.MudWebException;
import mmud.rest.webentities.PrivateGuild;
import mmud.rest.webentities.PrivatePerson;
import mmud.rest.webentities.PrivateRank;
/**
* Takes care of the guilds. All the REST services in this bean, can be subdivided
* into two categories:<ul><li>persons who are a member of the guild, can view information of the guild</li>
* <li>guildmasters (who are also member of the guild) can change/delete/add information to the guild</li></ul>
* TODO: need to add different access rights.
*
* @author maartenl
*/
@DeclareRoles(
{
"player", "guildmaster", "guildmember"
})
@RolesAllowed("player")
@Stateless
@LocalBean
@Path("/private/{name}/guild")
public class GuildBean
{
@PersistenceContext(unitName = "karchangamePU")
private EntityManager em;
@EJB
private PrivateBean privateBean;
@EJB
private PersonBean personBean;
/**
* Returns the entity manager of JPA. This is defined in
* build/web/WEB-INF/classes/META-INF/persistence.xml.
*
* @return EntityManager
*/
protected EntityManager getEntityManager()
{
return em;
}
private static final Logger itsLog = Logger.getLogger(GuildBean.class.getName());
/**
* Retrieves the guild by name. Returns null if not found.
*
* @param name the name of the guild.
* @return a guild or null.
*/
public Guild getGuild(String name)
{
return getEntityManager().find(Guild.class, name);
}
/**
* returns a list of persons that wish to
* become a member of a guild.
*
* @return list of guild hopefuls.
* @param aGuild
* the guild
* @throws MudException
* if something goes wrong.
*/
public List<User> getGuildHopefuls(Guild aGuild)
{
Query query = getEntityManager().createNamedQuery("Guild.findGuildHopefuls");
query.setParameter("guildname", aGuild.getName());
query.setParameter("attributename", Attributes.GUILDWISH);
query.setParameter("valuetype", "string");
return query.getResultList();
}
/**
* Get the guild of the user.
*
* @param name the name of the user
* @return the guild
*/
@GET
@RolesAllowed("guildmember")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public PrivateGuild getGuildInfo(@PathParam("name") String name)
{
itsLog.finer("entering getGuild");
Guild guild = authenticate(name);
PrivateGuild privateGuild = new PrivateGuild();
privateGuild.guildurl = guild.getHomepage();
privateGuild.title = guild.getTitle();
privateGuild.image = guild.getImage();
privateGuild.name = guild.getName();
privateGuild.colour = guild.getColour();
privateGuild.logonmessage = guild.getLogonmessage();
if (guild.getBoss() == null)
{
itsLog.log(Level.INFO, "guilds: no boss found for guild {0}", guild.getName());
} else
{
privateGuild.bossname = guild.getBoss().getName();
}
privateGuild.guilddescription = guild.getDescription();
privateGuild.creation = guild.getCreation();
return privateGuild;
}
/**
* Updates the guild.
*
* @param name the name of the user
* @param cinfo the guild object containing the new stuff to update.
* @return Response.ok if everything is okay.
* @throws WebApplicationException UNAUTHORIZED, if the authorisation
* failed. BAD_REQUEST if an unexpected exception crops up.
*/
@PUT
@RolesAllowed("guildmaster")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public Response updateGuild(@PathParam("name") String name, PrivateGuild cinfo)
{
itsLog.finer("entering updateGuild");
User person = authenticateGuildMaster(name);
Guild guild = person.getGuild();
if (!cinfo.bossname.equals(person.getName()))
{
User newGuildMaster = personBean.getUser(cinfo.bossname);
if (newGuildMaster == null)
{
throw new MudWebException(name, "New boss " + cinfo.bossname + " not found.", Response.Status.NOT_FOUND);
}
guild.setBoss(newGuildMaster);
}
guild.setDescription(cinfo.guilddescription);
guild.setHomepage(cinfo.guildurl);
guild.setImage(cinfo.image);
guild.setLogonmessage(cinfo.logonmessage);
guild.setColour(cinfo.colour);
guild.setTitle(cinfo.title);
return Response.ok().build();
}
/**
* Creates a new guild.
*
* @param name the name of the user
* @param cinfo the guild object containing the new stuff to create.
* @return Response.ok if everything is okay.
* @throws WebApplicationException UNAUTHORIZED, if the authorisation
* failed. BAD_REQUEST if an unexpected exception crops up.
*/
@POST
@RolesAllowed("player")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public Response createGuild(@PathParam("name") String name, PrivateGuild cinfo)
{
itsLog.finer("entering createGuild");
User person = privateBean.authenticate(name);
if (person.getGuild() != null)
{
throw new MudWebException(name, "You are already a member of a guild and therefore cannot start a guild.", Response.Status.UNAUTHORIZED);
}
Guild guild = new Guild();
guild.setDescription(cinfo.guilddescription);
guild.setHomepage(cinfo.guildurl);
guild.setImage(cinfo.image);
guild.setLogonmessage(cinfo.logonmessage);
guild.setTitle(cinfo.title);
guild.setBoss(person);
guild.setName(cinfo.name);
guild.setActive(Boolean.TRUE);
guild.setColour(cinfo.colour);
guild.setDaysguilddeath(10);
guild.setMaxguilddeath(10);
guild.setMinguildmembers(20);
try
{
getEntityManager().persist(guild);
} catch (ConstraintViolationException ex)
{
StringBuilder buffer = new StringBuilder("ConstraintViolationException:");
for (ConstraintViolation<?> violation : ex.getConstraintViolations())
{
buffer.append(violation);
}
itsLog.warning(buffer.toString());
throw ex;
}
person.setGuild(guild);
return Response.ok().build();
}
/**
* Deletes the guild.
*
* @param name the name of the user
* @return Response.ok if everything is okay.
* @throws WebApplicationException UNAUTHORIZED, if the authorisation
* failed. BAD_REQUEST if an unexpected exception crops up.
*/
@DELETE
@RolesAllowed("guildmaster")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public Response deleteGuild(@PathParam("name") String name)
{
itsLog.finer("entering deleteGuild");
User person = authenticateGuildMaster(name);
Guild guild = person.getGuild();
for (User guildmember : guild.getMembers())
{
guildmember.setGuild(null);
}
SortedSet<User> emptySet = new TreeSet<>();
guild.setMembers(emptySet);
for (Guildrank rank : guild.getGuildrankCollection())
{
getEntityManager().remove(rank);
}
SortedSet<Guildrank> emptyRanks = new TreeSet<>();
guild.setGuildrankCollection(emptyRanks);
getEntityManager().remove(guild);
return Response.ok().build();
}
/**
* Get all members of the guild of the user.
*
* @param name the name of the user
* @return list of guildmembers
*/
@GET
@Path("members")
@RolesAllowed("guildmember")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public List<PrivatePerson> getMembers(@PathParam("name") String name)
{
itsLog.finer("entering getGuildMembers");
Guild guild = authenticate(name);
Collection<User> members = guild.getMembers();
List<PrivatePerson> result = new ArrayList<>();
for (User person : members)
{
PrivatePerson privatePerson = new PrivatePerson();
privatePerson.name = person.getName();
if (person.getGuildrank() != null)
{
privatePerson.guildrank = person.getGuildrank().getTitle();
}
result.add(privatePerson);
}
Collections.sort(result, new Comparator<PrivatePerson>()
{
@Override
public int compare(PrivatePerson o1, PrivatePerson o2)
{
return o1.name.compareTo(o2.name);
}
});
return result;
}
/**
* Get the member of the guild of the user.
*
* @param membername the name of the guild member
* @param name the name of the user
* @return member
*/
@GET
@Path("members/{membername}")
@RolesAllowed("guildmember")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public PrivatePerson getMember(@PathParam("name") String name,
@PathParam("membername") String membername)
{
itsLog.finer("entering getMember");
Guild guild = authenticate(name);
User member = guild.getMember(membername);
if (member == null)
{
throw new MudWebException(name, membername + " is either not a user or not a member of this guild.", Response.Status.NOT_FOUND);
}
PrivatePerson privatePerson = new PrivatePerson();
privatePerson.name = member.getName();
if (member.getGuildrank() != null)
{
privatePerson.guildrank = member.getGuildrank().getTitle();
privatePerson.guildlevel = member.getGuildrank().getGuildrankPK().getGuildlevel();
}
return privatePerson;
}
/**
* Removes a member from the guild.
*
* @param membername the name of the guild member to remove
* @param name the name of the user
* @return member
*/
@DELETE
@Path("members/{membername}")
@RolesAllowed("guildmaster")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public Response deleteMember(@PathParam("name") String name,
@PathParam("membername") String membername)
{
itsLog.finer("entering deleteMember");
User person = authenticateGuildMaster(name);
Guild guild = person.getGuild();
if (membername != null && membername.equals(person.getName()))
{
throw new MudWebException(name, "Cannot remove the guildmaster of guild " + guild.getName(), Response.Status.BAD_REQUEST);
}
User member = guild.getMember(membername);
if (member == null)
{
throw new MudWebException(name, membername + " is either not a user or not a member of this guild.", Response.Status.NOT_FOUND);
}
member.setGuild(null);
return Response.ok().build();
}
/**
* Adds a member to the guild of the user. There are some checks made:
* <ul><li>possible member should exist</li>
* <li>should be a user, not a bot</li>
* <li>should not be a member of a guild</li>
* <li>should have a guildwish corresponding to the name of the guild>/li>
* </ul>
*
* @param name the name of the user
* @param member the member to add, really should contain only the name,
* that's enough
* @return Response.ok if everything is okay.
*/
@POST
@Path("members")
@RolesAllowed("guildmaster")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public Response createMember(@PathParam("name") String name, PrivatePerson member)
{
itsLog.finer("entering createMember");
User person = authenticateGuildMaster(name);
Guild guild = person.getGuild();
String membername = member.name;
User possibleMember = personBean.getUser(membername);
if (possibleMember == null)
{
throw new MudWebException(name, membername + " is not a user.", Response.Status.NOT_FOUND);
}
if (possibleMember.getGuild() != null)
{
throw new MudWebException(name, membername + " is already part of a guild.", Response.Status.NOT_FOUND);
}
if (!possibleMember.verifyAttribute(Attributes.GUILDWISH, guild.getName()))
{
throw new MudWebException(name, membername + " has no appropriate guildwish.", Response.Status.NOT_FOUND);
}
possibleMember.setGuild(guild);
possibleMember.removeAttribute(Attributes.GUILDWISH);
return Response.ok().build();
}
/**
* Set or deletes the rank of a member of the guild of the user.
*
* @param membername the name of the guild member, to set the guild rank for
* @param member the member object that contains the changes
* @param name the name of the user
* @return Response.ok() if everything's okay.
*/
@PUT
@Path("members/{membername}")
@RolesAllowed("guildmaster")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public Response updateMember(@PathParam("name") String name,
@PathParam("membername") String membername, PrivatePerson member)
{
itsLog.finer("entering updateMember");
User person = authenticateGuildMaster(name);
Guild guild = person.getGuild();
User user = guild.getMember(membername);
if (user == null)
{
throw new MudWebException(name, membername + " is either not a user or not a member of this guild.", Response.Status.NOT_FOUND);
}
if (member.guildlevel == null)
{
user.setGuildrank(null);
itsLog.finer("updateMember cleared rank");
return Response.ok().build();
}
Guildrank rank = guild.getRank(member.guildlevel);
if (rank == null)
{
throw new MudWebException(name, "Rank " + member.guildlevel + " does not exist in this guild.", Response.Status.NOT_FOUND);
}
user.setGuildrank(rank);
return Response.ok().build();
}
/**
* Get the hopefuls of the guild of the user.
*
* @param name the name of the user
* @return list of hopefuls, i.e. people who wish to join the guild
*/
@GET
@Path("hopefuls")
@RolesAllowed("guildmember")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public List<PrivatePerson> getGuildHopefuls(@PathParam("name") String name)
{
itsLog.finer("entering getGuildHopefuls");
Guild guild = authenticate(name);
Collection<User> hopefuls = getGuildHopefuls(guild);
List<PrivatePerson> result = new ArrayList<>();
for (User person : hopefuls)
{
PrivatePerson privatePerson = new PrivatePerson();
privatePerson.name = person.getName();
if (person.getGuild() != null)
{
privatePerson.guild = person.getGuild().getTitle();
}
if (person.getGuildrank() != null)
{
privatePerson.guildrank = person.getGuildrank().getTitle();
}
result.add(privatePerson);
}
Collections.sort(result, new Comparator<PrivatePerson>()
{
@Override
public int compare(PrivatePerson o1, PrivatePerson o2)
{
return o1.name.compareTo(o2.name);
}
});
return result;
}
/**
* Remove a hopeful of the guild of the user.
*
* @param name the name of the user
* @param hopefulname the name of the hopeful to reject
* @return Response.Status.ok if everything's okay.
*/
@DELETE
@Path("hopefuls/{hopefulname}")
@RolesAllowed("guildmaster")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public Response deleteGuildHopeful(@PathParam("name") String name,
@PathParam("hopefulname") String hopefulname)
{
itsLog.finer("entering getGuildHopefuls");
User person = authenticateGuildMaster(name);
Guild guild = person.getGuild();
User possibleMember = personBean.getUser(hopefulname);
if (possibleMember == null)
{
throw new MudWebException(name, hopefulname + " is not a user.", Response.Status.NOT_FOUND);
}
possibleMember.removeAttribute(Attributes.GUILDWISH);
return Response.ok().build();
}
/**
* Get the ranks of the guild of the user.
*
* @param name the name of the user
* @return list of hopefuls
*/
@GET
@Path("ranks")
@RolesAllowed("guildmember")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public List<PrivateRank> getGuildRanks(@PathParam("name") String name)
{
itsLog.finer("entering getGuildRanks");
Guild guild = authenticate(name);
Guildrank[] ranks = guild.getGuildrankCollection().toArray(new Guildrank[0]);
Arrays.sort(ranks, new Comparator<Guildrank>()
{
@Override
public int compare(Guildrank o1, Guildrank o2
)
{
return Integer.valueOf(o1.getGuildrankPK().getGuildlevel()).compareTo(Integer.valueOf(o2.getGuildrankPK().getGuildlevel()));
}
});
List<PrivateRank> result = new ArrayList<>();
for (Guildrank rank : ranks)
{
PrivateRank privateRank = new PrivateRank();
privateRank.title = rank.getTitle();
privateRank.guildlevel = rank.getGuildrankPK().getGuildlevel();
privateRank.accept_access = rank.getAcceptAccess();
privateRank.reject_access = rank.getRejectAccess();
privateRank.settings_access = rank.getSettingsAccess();
privateRank.logonmessage_access = rank.getLogonmessageAccess();
result.add(privateRank);
}
Collections.sort(result, new Comparator<PrivateRank>()
{
@Override
public int compare(PrivateRank o1, PrivateRank o2)
{
return o1.guildlevel.compareTo(o2.guildlevel);
}
});
return result;
}
/**
* Get the ranks of the guild of the user.
*
* @param name the name of the user
* @param guildlevel the id of the guild rank
* @return list of hopefuls
*/
@GET
@Path("ranks/{guildlevel}")
@RolesAllowed("guildmember")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public PrivateRank getGuildRank(@PathParam("name") String name, @PathParam("guildlevel") Integer guildlevel)
{
itsLog.finer("entering getGuildRank");
User person = authenticateGuildMaster(name);
Guild guild = person.getGuild();
if (guildlevel == null)
{
throw new MudWebException(name, "Rank was not received.", "guildlevel was null, never found.", Response.Status.NOT_FOUND);
}
Guildrank rank = guild.getRank(guildlevel);
if (rank == null)
{
throw new MudWebException(name, "Rank " + guildlevel + " of guild " + guild.getName() + " not found.", Response.Status.NOT_FOUND);
}
PrivateRank privateRank = new PrivateRank();
privateRank.title = rank.getTitle();
privateRank.guildlevel = rank.getGuildrankPK().getGuildlevel();
privateRank.accept_access = rank.getAcceptAccess();
privateRank.reject_access = rank.getRejectAccess();
privateRank.settings_access = rank.getSettingsAccess();
privateRank.logonmessage_access = rank.getLogonmessageAccess();
return privateRank;
}
/**
* Create a rank of the guild of the user.
*
* @param name the name of the user
* @param rank the rank to add
* @return Response.ok if everything is okay.
*/
@POST
@RolesAllowed("guildmaster")
@Path("ranks")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public Response createGuildRank(@PathParam("name") String name, PrivateRank rank)
{
itsLog.finer("entering createGuildRank");
User person = authenticateGuildMaster(name);
Guild guild = person.getGuild();
Guildrank newRank = new Guildrank();
newRank.setAcceptAccess(rank.accept_access);
newRank.setGuild(guild);
newRank.setLogonmessageAccess(rank.logonmessage_access);
newRank.setRejectAccess(rank.reject_access);
newRank.setSettingsAccess(rank.settings_access);
newRank.setTitle(rank.title);
GuildrankPK pk = new GuildrankPK();
pk.setGuildlevel(rank.guildlevel);
pk.setGuildname(guild.getName());
newRank.setGuildrankPK(pk);
try
{
getEntityManager().persist(newRank);
} catch (ConstraintViolationException ex)
{
StringBuilder buffer = new StringBuilder("ConstraintViolationException:");
for (ConstraintViolation<?> violation : ex.getConstraintViolations())
{
buffer.append(violation);
}
throw new MudWebException(name, buffer.toString(), ex, Response.Status.BAD_REQUEST);
}
return Response.ok().build();
}
/**
* Update a rank of the guild of the user.
*
* @param name the name of the user
* @param guildlevel the guildlevel of the rank
* @param rank the rank to update
* @return Response.ok if everything is okay.
*/
@PUT
@RolesAllowed("guildmaster")
@Path("ranks/{guildlevel}")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public Response updateGuildRank(@PathParam("name") String name, @PathParam("guildlevel") Integer guildlevel, PrivateRank rank)
{
itsLog.finer("entering updateGuildRank");
User person = authenticateGuildMaster(name);
Guild guild = person.getGuild();
if (guildlevel == null)
{
throw new MudWebException(name, "Rank was not received.", "guildlevel was null, never found.", Response.Status.NOT_FOUND);
}
Guildrank guildrank = guild.getRank(guildlevel);
if (guildrank == null)
{
throw new MudWebException(name, "Rank " + guildlevel + " of guild " + guild.getName() + " not found.", Response.Status.NOT_FOUND);
}
guildrank.setAcceptAccess(rank.accept_access);
guildrank.setLogonmessageAccess(rank.logonmessage_access);
guildrank.setRejectAccess(rank.reject_access);
guildrank.setSettingsAccess(rank.settings_access);
guildrank.setTitle(rank.title);
return Response.ok().build();
}
/**
* Delete a rank of the guild of the user.
*
* @param name the name of the user
* @param guildlevel the guildlevel of the rank
* @return Response.ok if everything is okay.
*/
@DELETE
@RolesAllowed("guildmaster")
@Path("ranks/{guildlevel}")
@Consumes(
{
MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
})
public Response deleteGuildRank(@PathParam("name") String name, @PathParam("guildlevel") Integer guildlevel)
{
itsLog.finer("entering deleteGuildRank");
User person = authenticateGuildMaster(name);
Guild guild = person.getGuild();
if (guildlevel == null)
{
throw new MudWebException(name, "Rank was not received.", "guildlevel was null, never found.", Response.Status.NOT_FOUND);
}
Guildrank guildrank = guild.getRank(guildlevel);
if (guildrank == null)
{
throw new MudWebException(name, "Rank " + guildlevel + " of guild " + guild.getName() + " not found.", Response.Status.NOT_FOUND);
}
getEntityManager().remove(guildrank);
return Response.ok().build();
}
private Guild authenticate(String name)
{
User person = privateBean.authenticate(name);
final Guild guild = person.getGuild();
if (guild == null)
{
throw new MudWebException(name,
"User is not a member of a guild.",
"User is not a member of a guild (" + name + ")",
Response.Status.NOT_FOUND);
}
return guild;
}
private User authenticateGuildMaster(String name)
{
return privateBean.authenticateGuildMaster(name);
}
}