001/**
002 *   GRANITE DATA SERVICES
003 *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 *   This file is part of the Granite Data Services Platform.
006 *
007 *                               ***
008 *
009 *   Community License: GPL 3.0
010 *
011 *   This file is free software: you can redistribute it and/or modify
012 *   it under the terms of the GNU General Public License as published
013 *   by the Free Software Foundation, either version 3 of the License,
014 *   or (at your option) any later version.
015 *
016 *   This file is distributed in the hope that it will be useful, but
017 *   WITHOUT ANY WARRANTY; without even the implied warranty of
018 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
019 *   GNU General Public License for more details.
020 *
021 *   You should have received a copy of the GNU General Public License
022 *   along with this program. If not, see <http://www.gnu.org/licenses/>.
023 *
024 *                               ***
025 *
026 *   Available Commercial License: GraniteDS SLA 1.0
027 *
028 *   This is the appropriate option if you are creating proprietary
029 *   applications and you are not prepared to distribute and share the
030 *   source code of your application under the GPL v3 license.
031 *
032 *   Please visit http://www.granitedataservices.com/license for more
033 *   details.
034 */
035package org.granite.client.tide.data.impl;
036
037import java.util.ArrayList;
038import java.util.Arrays;
039import java.util.HashMap;
040import java.util.List;
041import java.util.Map;
042
043import org.granite.client.messaging.RemoteService;
044import org.granite.client.messaging.ResultFaultIssuesResponseListener;
045import org.granite.client.messaging.events.FaultEvent;
046import org.granite.client.messaging.events.IssueEvent;
047import org.granite.client.messaging.events.ResultEvent;
048import org.granite.client.tide.Context;
049import org.granite.client.tide.data.EntityManager;
050import org.granite.client.tide.data.PersistenceManager;
051import org.granite.client.tide.data.RemoteInitializer;
052import org.granite.client.tide.impl.FaultHandler;
053import org.granite.client.tide.impl.ResultHandler;
054import org.granite.client.tide.server.ServerSession;
055import org.granite.logging.Logger;
056import org.granite.tide.invocation.InvocationCall;
057import org.granite.tide.invocation.InvocationResult;
058
059/**
060 * @author William DRAI
061 */
062public class RemoteInitializerImpl implements RemoteInitializer {
063        
064        private static final Logger log = Logger.getLogger(RemoteInitializerImpl.class);
065        
066        private final Context context;
067        private boolean enabled = true;
068
069        
070        public RemoteInitializerImpl(Context context) {
071                this.context = context;
072        }
073
074        @Override
075        public void setEnabled(boolean enabled) {
076                this.enabled = enabled;
077        }
078
079        @Override
080        public boolean isEnabled() {
081                return enabled;
082        }
083        
084        private List<Object[]> objectsInitializing = new ArrayList<Object[]>();
085    
086        /**
087         *      {@inheritDoc}
088         */
089    public boolean initializeObject(ServerSession serverSession, Object entity, String propertyName, Object object) {
090                if (!enabled || context.isFinished())
091                        return false;
092                
093                log.debug("initialize {0}", ObjectUtil.toString(object));
094                
095                EntityManager entityManager = PersistenceManager.getEntityManager(entity);
096                if (entityManager == null)
097                        return false;
098                
099                entityManager.addReference(entity, null, null);
100                
101                synchronized (objectsInitializing) {
102                        objectsInitializing.add(new Object[] { context, entity, propertyName });
103                }
104                
105                context.callLater(new DoInitializeObjects(serverSession));
106                return true;
107        }
108    
109    public class DoInitializeObjects implements Runnable {
110        
111        private final ServerSession serverSession;
112        
113        public DoInitializeObjects(ServerSession serverSession) {
114                this.serverSession = serverSession;
115        }
116        
117        public void run() {
118                Map<Object, List<String>> initMap = new HashMap<Object, List<String>>();
119                        
120                synchronized (objectsInitializing) {
121                                for (int i = 0; i < objectsInitializing.size(); i++) {
122                                        if (objectsInitializing.get(i)[0] != context)
123                                                continue;
124                                        
125                                        List<String> propertyNames = initMap.get(objectsInitializing.get(i)[1]);
126                                        if (propertyNames == null) {
127                                                propertyNames = Arrays.asList((String)objectsInitializing.get(i)[2]);
128                                                initMap.put(objectsInitializing.get(i)[1], propertyNames);
129                                        }
130                                        else
131                                                propertyNames.add((String)objectsInitializing.get(i)[2]);
132                                        
133                                        objectsInitializing.remove(i--);
134                                }
135                }
136                        
137                RemoteService rs = serverSession.getRemoteService();
138                        for (Object entity : initMap.keySet()) {
139                                rs.newInvocation("initializeObject", entity, initMap.get(entity).toArray(), new InvocationCall())
140                                        .addListener(new InitializerListener(serverSession, entity)).invoke();
141                                
142                        }
143        }
144        }
145        
146    
147    public class InitializerListener extends ResultFaultIssuesResponseListener {
148        
149        private final ServerSession serverSession;
150        private final Object entity;
151        
152        public InitializerListener(ServerSession serverSession, Object entity) {
153                this.serverSession = serverSession;
154                this.entity = entity;
155        }
156
157                @Override
158                public void onResult(final ResultEvent event) {
159                        context.callLater(new Runnable() {
160                                public void run() {
161                                        EntityManager entityManager = PersistenceManager.getEntityManager(entity);
162                                        
163                                        boolean saveUninitializeAllowed = entityManager.isUninitializeAllowed();
164                                        try {
165                                                entityManager.setUninitializeAllowed(false);
166                                                
167                                                // Assumes objects is a PersistentCollection or PersistentMap
168                        new ResultHandler<Object>(serverSession, null, null).handleResult(context, (InvocationResult) event.getResult(), ((InvocationResult) event.getResult()).getResult(), null);
169                                        }
170                                        finally {
171                                                entityManager.setUninitializeAllowed(saveUninitializeAllowed);
172                                        }
173                                }
174                        });
175                }
176
177                @Override
178                public void onFault(final FaultEvent event) {
179                        context.callLater(new Runnable() {
180                                public void run() {
181                                        log.error("Fault initializing collection " + ObjectUtil.toString(entity) + " " + event.toString());
182
183                    new FaultHandler<Object>(serverSession, null, null).handleFault(context, event.getMessage());
184                                }
185                        });
186                }       
187
188                @Override
189                public void onIssue(final IssueEvent event) {
190                        context.callLater(new Runnable() {
191                                public void run() {
192                                        log.error("Fault initializing collection " + ObjectUtil.toString(entity) + " " + event.toString());
193
194                    new FaultHandler<Object>(serverSession, null, null).handleFault(context, null);
195                                }
196                        });
197                }       
198    }
199}