XPlanner.java :  » Project-Management » XPlanner-0.7b7 » com » technoetic » xplanner » soap » Java Open Source

Java Open Source » Project Management » XPlanner 0.7b7 
XPlanner 0.7b7 » com » technoetic » xplanner » soap » XPlanner.java
package com.technoetic.xplanner.soap;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.ObjectNotFoundException;
import net.sf.hibernate.Session;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.type.Type;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.converters.ByteArrayConverter;
import org.apache.log4j.Logger;

import com.technoetic.xplanner.db.QueryException;
import com.technoetic.xplanner.db.TaskQueryHelper;
import com.technoetic.xplanner.db.TaskQuery;
import com.technoetic.xplanner.db.hibernate.ThreadSession;
import com.technoetic.xplanner.domain.*;
import com.technoetic.xplanner.domain.repository.AttributeRepository;
import com.technoetic.xplanner.domain.repository.AttributeRepositoryImpl;
import com.technoetic.xplanner.filters.ThreadServletRequest;
import com.technoetic.xplanner.history.HistoricalEvent;
import com.technoetic.xplanner.history.HistorySupport;
import com.technoetic.xplanner.security.AuthenticationException;
import com.technoetic.xplanner.security.SecurityHelper;
import com.technoetic.xplanner.security.auth.SystemAuthorizer;
import com.technoetic.xplanner.soap.domain.*;
import com.technoetic.xplanner.tags.DomainContext;
import com.technoetic.xplanner.util.MainBeanFactory;

// TODO: SOAP input validation.
// Ideally, extract the validation out of the struts forms into reusable
// validation to be used by soap

public class XPlanner
{
    private Logger log = Logger.getLogger(getClass());
    private AttributeRepository attributes = new AttributeRepositoryImpl();

    public XPlanner()
    {
        //  The SOAP interface is required to use Calendars for dates. This
        //  converter is intended to be an adapter for the Date usage in the
        //  XPlanner domain objects. However, I'm not comfortable with this since
        //  the converters are global objects.
        ConvertUtils.register(new Converter()
        {
            public Object convert(Class type, Object value)
            {
                if (value == null) return null;
                if (value instanceof Calendar) return ((Calendar) value).getTime();
                return value;
            }
        }, Date.class);
        ConvertUtils.register(new Converter()
        {
            public Object convert(Class type, Object value)
            {
                if (value == null) return null;
                if (value instanceof Date)
                {
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime((Date) value);
                    return calendar;
                }
                return value;
            }
        }, Calendar.class);
        ConvertUtils.register(new ByteArrayConverter(null), byte[].class); // by default a null value is not converted in a null array.
    }

    //
    // Projects
    //

    public ProjectData[] getProjects() throws Exception
    {
        return (ProjectData[]) getObjects(ProjectData.class, null, null, null, null);
    }

    public ProjectData getProject(int id) throws Exception
    {
        return (ProjectData) getObject(ProjectData.class, id);
    }

    public ProjectData addProject(ProjectData project) throws Exception
    {
        return (ProjectData) addObject(0, project);
    }

    public void removeProject(int id) throws Exception
    {
        removeObject(ProjectData.class, id);
    }

    public void update(ProjectData object) throws Exception
    {
        updateObject(object);
    }

    public IterationData getCurrentIteration(int projectId) throws Exception
    {
        IterationData[] iterations = (IterationData[]) getObjects(IterationData.class,
                                                                  "object.startDate <= ? and object.endDate >= ? and object.projectId = ?",
                                                                  new Object[]{new Date(),
                                                                               new Date(),
                                                                               new Integer(projectId)},
                                                                  new Type[]{Hibernate.DATE,
                                                                             Hibernate.DATE,
                                                                             Hibernate.INTEGER},
                                                                  null);
        return iterations.length > 0 ? iterations[0] : null;
    }

    public IterationData[] getIterations(int projectId) throws Exception
    {
        return (IterationData[]) getObjects(ProjectData.class, projectId, "iterations", IterationData.class);
    }

    //
    // Iterations
    //

    public IterationData getIteration(int id) throws Exception
    {
        return (IterationData) getObject(IterationData.class, id);
    }

    public IterationData addIteration(IterationData iteration) throws Exception
    {
        return (IterationData) addObject(getProjectId(Project.class, iteration.getProjectId()), iteration);
    }

    public void removeIteration(int id) throws Exception
    {
        removeObject(IterationData.class, id);
    }

    public void update(IterationData object) throws Exception
    {
        updateObject(object);
    }

    public UserStoryData[] getUserStories(int containerId) throws Exception
    {
        return (UserStoryData[]) getObjects(IterationData.class, containerId, "userStories", UserStoryData.class);
    }

    //
    // User Stories
    //

    public UserStoryData getUserStory(int id) throws Exception
    {
        return (UserStoryData) getObject(UserStoryData.class, id);
    }

    public UserStoryData addUserStory(UserStoryData story) throws Exception
    {
        return (UserStoryData) addObject(getProjectId(Iteration.class, story.getIterationId()), story);
    }

    public void removeUserStory(int id) throws Exception
    {
        removeObject(UserStoryData.class, id);
    }

    public void update(UserStoryData object) throws Exception
    {
        updateObject(object);
    }

    public TaskData[] getTasks(int containerId) throws Exception
    {
        return (TaskData[]) getObjects(UserStoryData.class, containerId, "tasks", TaskData.class);
    }
//FEATURE:
//    public FeatureData[] getFeatures(int containerId) throws Exception {
//        return (FeatureData[])getObjects(UserStoryData.class, containerId, "features", FeatureData.class);
//    }


    //
    // Features
    //

//   public FeatureData getFeature(int id) throws Exception {
//       return (FeatureData)getObject(FeatureData.class, id);
//   }
//
//   public FeatureData addFeature(FeatureData feature) throws Exception {
//       return (FeatureData)addObject(getProjectId(UserStory.class, feature.getStoryId()), feature);
//   }
//
//   public void removeFeature(int id) throws Exception {
//       removeObject(FeatureData.class, id);
//   }
//
//   public void update(FeatureData object) throws Exception {
//           updateObject(object);
//   }


    //
    // Tasks
    //

    public TaskData getTask(int id) throws Exception
    {
        return (TaskData) getObject(TaskData.class, id);
    }

    public TaskData[] getCurrentTasksForPerson(int personId) throws QueryException
    {
       final TaskQueryHelper taskQueryHelper = (TaskQueryHelper) getSpringBean("taskQueryHelper");
       taskQueryHelper.setPersonId(personId);
       return (TaskData[]) toArray(TaskData.class,
                                    taskQueryHelper.getCurrentActiveTasksForPerson());
    }

    public TaskData[] getPlannedTasksForPerson(int personId) throws QueryException
    {
       final TaskQueryHelper taskQueryHelper = (TaskQueryHelper) getSpringBean("taskQueryHelper");
       taskQueryHelper.setPersonId(personId);
       taskQueryHelper.setPersonId(personId);
       return (TaskData[]) toArray(TaskData.class,
                                    taskQueryHelper.getCurrentPendingTasksForPerson());
    }

    public TaskData addTask(TaskData task) throws Exception
    {
        return (TaskData) addObject(getProjectId(UserStory.class, task.getStoryId()), task);
    }

    public void removeTask(int id) throws Exception
    {
        removeObject(TaskData.class, id);
    }

    public void update(TaskData object) throws Exception
    {
        updateObject(object);
    }


    //
    // Time Entries
    //

    public TimeEntryData[] getTimeEntries(int containerId) throws Exception
    {
        return (TimeEntryData[]) getObjects(TaskData.class, containerId, "timeEntries", TimeEntryData.class);
    }

    public TimeEntryData getTimeEntry(int id) throws Exception
    {
        return (TimeEntryData) getObject(TimeEntryData.class, id);
    }

    public TimeEntryData addTimeEntry(TimeEntryData timeEntry) throws Exception
    {
        return (TimeEntryData) addObject(getProjectId(Task.class, timeEntry.getTaskId()), timeEntry);
    }

    public void removeTimeEntry(int id) throws Exception
    {
        removeObject(TimeEntryData.class, id);
    }

    public void update(TimeEntryData object) throws Exception
    {
        updateObject(object);
    }

    //
    // Notes
    //

    public NoteData getNote(int id) throws Exception
    {
        return (NoteData) getObject(NoteData.class, id);
    }

    public NoteData addNote(NoteData note) throws Exception
    {
        return (NoteData) addObject(getProjectId(DomainContext.getNoteTarget(note.getAttachedToId())), note);
    }

    public void removeNote(int id) throws Exception
    {
        removeObject(NoteData.class, id);
    }

    public void update(NoteData note) throws Exception
    {
        updateObject(note);
    }

    public NoteData[] getNotesForObject(int attachedToId) throws Exception
    {
        return (NoteData[]) getObjects(NoteData.class, "attachedTo_Id = " + attachedToId, null, null, null);
    }

    //
    // People
    //

    public PersonData getPerson(int id) throws Exception
    {
        return (PersonData) getObject(PersonData.class, id);
    }

    public PersonData addPerson(PersonData object) throws Exception
    {
        return (PersonData) addObject(0, object);
    }

    public void removePerson(int id) throws Exception
    {
        removeObject(PersonData.class, id);
    }

    public void update(PersonData object) throws Exception
    {
        updateObject(object);
    }

    public PersonData[] getPeople() throws Exception
    {
        return (PersonData[]) getObjects(PersonData.class, null, null, null, null);
    }

    //
    // Attributes
    //

    public void setAttribute(int objectId, String key, String value) throws Exception
    {
        attributes.setAttribute(objectId, key, value);
        commit(ThreadSession.get());
    }

    public String getAttribute(int objectId, String key) throws Exception
    {
        return attributes.getAttribute(objectId, key);
    }

    public void deleteAttribute(int objectId, String key) throws Exception
    {
        attributes.delete(objectId, key);
        commit(ThreadSession.get());
    }

    public Map getAttributes(int objectId) throws Exception
    {
        return attributes.getAttributes(objectId, null);
    }

    public Map getAttributesWithPrefix(int objectId, String prefix) throws Exception
    {
        return attributes.getAttributes(objectId, prefix);
    }

    //
    // Support Functions
    //

    private int getProjectId(Class containerClass, int containerId) throws Exception
    {
        Object object = ThreadSession.get().load(containerClass, new Integer(containerId));
        DomainContext context = new DomainContext();
        context.populate(object);
        return context.getProjectId();
    }

    private int getProjectId(Object object) throws Exception
    {
        DomainContext context = new DomainContext();
        context.populate(object);
        return context.getProjectId();
    }

    private Object[] getObjects(Class dataClass, String where, Object[] values, Type[] types, String orderBy) throws Exception
    {
        try
        {
            Session session = ThreadSession.get();
            Class objectClass = getInternalClass(dataClass);
            String query = "from object in class " + objectClass.getName();
            if (where != null)
            {
                query += " where " + where;
            }
            if (orderBy != null)
            {
                query += " order by " + orderBy;
            }
            List objects = values != null
                ? session.find(query, values, types)
                : session.find(query);
            return toArray(dataClass, objects);
        }
        catch (Exception ex)
        {
            log.error("error loading objects", ex);
            throw ex;
        }
    }

    private Object[] getObjects(Class fromDataClass, int id, String propertyName, Class toDataClass) throws Exception
    {
        try
        {
            Session session = ThreadSession.get();
            Class objectClass = getInternalClass(fromDataClass);
            log.debug("getting object: " + id);
            Object object = session.load(objectClass, new Integer(id));
            log.debug("loaded object: " + object);
            Collection objects = (Collection) PropertyUtils.getProperty(object, propertyName);
            Object[] dataArray = toArray(toDataClass, objects);
            return dataArray;
        }
        catch (Exception ex)
        {
            log.error("error loading objects", ex);
            throw ex;
        }
    }

    private Object getObject(Class dataClass, int id) throws Exception
    {
       Session session = ThreadSession.get();
       try {
          Class objectClass = getInternalClass(dataClass);
          log.debug("getting object: " + id);
          DomainObject object = (DomainObject) session.load(objectClass, new Integer(id));
          log.debug("loaded object: " + object);
          DomainData data = (DomainData) dataClass.newInstance();
          if (hasPermission(getProjectId(object), object, "read"))
          {
             populateDomainData(data, object);
             return data;
          }
          else
          {
             throw new AuthenticationException("no permission to read object");
          }
       }
       catch (ObjectNotFoundException ex) {
          return null;
       }
       catch (Exception ex) {
          log.error("error loading objects", ex);
          throw ex;
       }
    }

    static Integer NULL = new Integer(-1);

    private void updateObject(DomainData data) throws Exception
    {
        Session session = null;
        try
        {
            Integer id = NULL;
            session = ThreadSession.get();
            Class objectClass = getInternalClass(data.getClass());
            id = getObjectId(data);
            DomainObject object = (DomainObject) session.load(objectClass, id);
            if (hasPermission(getProjectId(object), object, "edit"))
            {
                // JM: no need to write lock the object
                // There is a lot more chance to get the client out-of-sync during a get/update than just in that method
                // See to-do at the top of the file for better implementation
                if (object != null)
                {
                    populateDomainObject(object, data);
                }
                saveHistory(session, object, HistoricalEvent.UPDATED);
                commit(session);
            }
            else
            {
                throw new AuthenticationException("no permission to update object");
            }
        }
        catch (Exception ex)
        {
            rollback(session);
            throw ex;
        }
    }

    private void saveHistory(Session session, DomainObject object, String eventType) throws AuthenticationException
    {
        String description = null;
        if (eventType.equals(HistoricalEvent.DELETED))
        {
            try
            {
                description = BeanUtils.getProperty(object, "name");
            }
            catch (Exception e)
            {
                description = "unknown name";
            }
        }
        HistorySupport.saveEvent(session, object, eventType, description,
                                 SecurityHelper.getRemoteUserId(ThreadServletRequest.get()), new Date());
    }

    private Integer getObjectId(Object data) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
    {
        return (Integer) PropertyUtils.getProperty(data, "id");
    }

    protected void removeObject(Class dataClass, int id) throws Exception
    {
       //DEBT Should use the metarepository
        Session session = null;
        try
        {
            session = ThreadSession.get();
            log.debug("removing object: " + id);
            Class objectClass = getInternalClass(dataClass);
            DomainObject object = (DomainObject) session.load(objectClass, new Integer(id));
            if (hasPermission(getProjectId(object), (DomainObject) object, "delete"))
            {
                session.delete(object);
                saveHistory(session, object, HistoricalEvent.DELETED);
                commit(session);
            }
            else
            {
                throw new AuthenticationException("no permission to delete object");
            }
        }
        catch (ObjectNotFoundException ex)
        {
            throw ex;
        }
        catch (Exception ex)
        {
            rollback(session);
            throw ex;
        }
    }


    protected Object addObject(int projectId, DomainData data) throws Exception
    {
        Session session = null;
        try
        {
            session = ThreadSession.get();
            Class objectClass = getInternalClass(data.getClass());
            DomainObject object = (DomainObject) objectClass.newInstance();
            if (hasPermission(projectId, object, "create"))
            {
                populateDomainObject(object, data);
                log.debug("adding object: " + object);
                Serializable id = session.save(object);
                saveHistory(session, object, HistoricalEvent.CREATED);
                commit(session);
//                return getObject(data.getClass(), ((Integer) id).intValue());
                populateDomainData(data, object);
                return data;
            }
            else
            {
                throw new AuthenticationException("no permission to create object");
            }
        }
        catch (Exception ex)
        {
            rollback(session);
            throw ex;
        }
    }

    private void commit(Session session)
    {
        if (session == null) return;
        try
        {
            session.flush();
            session.connection().commit();
        }
        catch (Exception ex)
        {
            log.error("error", ex);
            throw new RuntimeException(ex);
        }
    }

    private void rollback(Session session)
    {
        if (session == null) return;
        try
        {
            session.connection().rollback();
        }
        catch (Exception e)
        {
            log.error("error", e);
        }
    }

    private void closeSession(Session session)
    {
        if (session == null) return;
        try
        {
            session.close();
        }
        catch (Exception ex)
        {
            log.error("error", ex);
        }
    }

    private Object[] toArray(Class dataClass, Collection objects)
    {
        try
        {
            ArrayList accessibleObjects = selectAccessibleObjects(objects);
            Object[] dataObjects = createArray(dataClass, accessibleObjects);
            Iterator iter = accessibleObjects.iterator();
            for (int i = 0; iter.hasNext(); i++)
            {
                populateDomainData((DomainData) dataObjects[i], (DomainObject) iter.next());
            }
            return dataObjects;
        }
        catch (Exception ex)
        {
            log.error("error in toArray", ex);
            return null;
        }
    }

    private ArrayList selectAccessibleObjects(Collection objects) throws Exception
    {
        ArrayList accessibleObjects = new ArrayList();
        for (Iterator objectIterator = objects.iterator(); objectIterator.hasNext();)
        {
            DomainObject object = (DomainObject) objectIterator.next();
            if (hasPermission(getProjectId(object), object, "read"))
            {
                accessibleObjects.add(object);
            }

        }
        return accessibleObjects;
    }

    private boolean hasPermission(int projectId, DomainObject sourceObject, String permission) throws Exception
    {
        int remoteUserId = SecurityHelper.getRemoteUserId(ThreadServletRequest.get());
        log.info("Checking permission for userid " + remoteUserId);
        return SystemAuthorizer.get().hasPermission(projectId, remoteUserId,
                                                    sourceObject, permission);
    }

    private void populateDomainData(DomainData data, DomainObject sourceObject) throws IllegalAccessException,
                                                                                       InvocationTargetException,
                                                                                       NoSuchMethodException
    {
        BeanUtils.copyProperties(data, sourceObject);
        Map description = PropertyUtils.describe(data);
        Iterator keyItr = description.keySet().iterator();
        while (keyItr.hasNext())
        {
            String key = (String) keyItr.next();
            if ("class".equals(key) || "relationshipMapping".equals(key)) continue;
            if (isRelationship(sourceObject, key))
            {
                RelationshipMappingRegistry.getInstance().getRelationshipMapping(sourceObject, key).populateAdapter(
                    data, sourceObject);
            }
        }
    }

    private void populateDomainObject(DomainObject targetObject, DomainData data)
        throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, HibernateException
    {
        BeanUtils.copyProperties(targetObject, data);
        Map description = PropertyUtils.describe(data);
        Iterator keyItr = description.keySet().iterator();
        while (keyItr.hasNext())
        {
            String key = (String) keyItr.next();
            if ("class".equals(key) || "relationshipMapping".equals(key)) continue;
            if (isRelationship(targetObject, key))
            {
                RelationshipMappingRegistry.getInstance().getRelationshipMapping(targetObject, key).populateDomainObject(
                    targetObject, data);
            }
        }
    }

    private boolean isRelationship(DomainObject domainObject, String key)
    {
        return RelationshipMappingRegistry.getInstance().getRelationshipMapping(domainObject, key) != null;
    }

    private Object[] createArray(Class dataClass, Collection objects) throws InstantiationException,
                                                                             IllegalAccessException
    {
        Object[] dataObjects = (Object[]) Array.newInstance(dataClass, objects.size());
        for (int i = 0; i < dataObjects.length; i++)
        {
            dataObjects[i] = dataClass.newInstance();
        }
        return dataObjects;
    }

    private Class getInternalClass(Class dataClass)
    {
        try
        {
            Method method = dataClass.getMethod("getInternalClass", null);
            return (Class) method.invoke(dataClass, null);
        }
        catch (Exception e)
        {
            return getDomainClassForDataClass(dataClass);
        }
    }

    private Class getDomainClassForDataClass(Class dataClass)
    {
        return (Class) dataToDomainClassMap.get(dataClass);
    }

    static Map dataToDomainClassMap = createDataToDomainClassMap();

    private static Map createDataToDomainClassMap()
    {
        HashMap map = new HashMap();
        map.put(ProjectData.class, Project.class);
        map.put(IterationData.class, Iteration.class);
        map.put(UserStoryData.class, UserStory.class);
        map.put(TaskData.class, Task.class);
        map.put(TimeEntryData.class, TimeEntry.class);
        map.put(PersonData.class, Person.class);
        map.put(NoteData.class, Note.class);
        return map;
    }

    Object getSpringBean(String beanName){
       return MainBeanFactory.getBean(beanName, true);
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.