* anti-abuse upgrade: filters now stored in the database (experimental)
[mir.git] / source / mircoders / global / MirGlobal.java
1 /*\r
2  * Copyright (C) 2001, 2002 The Mir-coders group\r
3  *\r
4  * This file is part of Mir.\r
5  *\r
6  * Mir is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 2 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * Mir is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with Mir; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  *\r
20  * In addition, as a special exception, The Mir-coders gives permission to link\r
21  * the code of this program with  any library licensed under the Apache Software License,\r
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
23  * (or with modified versions of the above that use the same license as the above),\r
24  * and distribute linked combinations including the two.  You must obey the\r
25  * GNU General Public License in all respects for all of the code used other than\r
26  * the above mentioned libraries.  If you modify this file, you may extend this\r
27  * exception to your version of the file, but you are not obligated to do so.\r
28  * If you do not wish to do so, delete this exception statement from your version.\r
29  */\r
30 \r
31 package mircoders.global;\r
32 \r
33 import mir.bundle.BasicBundleFactory;\r
34 import mir.bundle.BundleFactory;\r
35 import mir.bundle.CascadingBundleFactory;\r
36 import mir.bundle.PropertiesFileBundleLoader;\r
37 import mir.config.MirPropertiesConfiguration;\r
38 import mir.entity.adapter.EntityAdapter;\r
39 import mir.log.LoggerEngine;\r
40 import mir.log.LoggerWrapper;\r
41 import mir.misc.ConfigException;\r
42 import mircoders.accesscontrol.AccessControl;\r
43 import mircoders.entity.EntityComment;\r
44 import mircoders.entity.EntityContent;\r
45 import mircoders.entity.EntityUsers;\r
46 import mircoders.localizer.MirAdminInterfaceLocalizer;\r
47 import mircoders.localizer.MirCachingLocalizerDecorator;\r
48 import mircoders.localizer.MirLocalizer;\r
49 import mircoders.localizer.MirLocalizerExc;\r
50 \r
51 import java.util.*;\r
52 \r
53 public class MirGlobal {\r
54   static private MirLocalizer localizer;\r
55   static private ProducerEngine producerEngine;\r
56   static private Abuse abuse;\r
57   static private MRUCache mruCache;\r
58   static private AccessControl accessControl;\r
59   static private Map articleOperations;\r
60   static private Map commentOperations;\r
61   static private Map loggedInUsers = new HashMap();\r
62   static private Map loggedInUserIds = new HashMap();\r
63   static private LoggerWrapper logger = new LoggerWrapper("Global");\r
64   static private LoggerWrapper adminUsageLogger = new LoggerWrapper("AdminUsage");\r
65 //  static private ChangeEngine changeEngine = new ChangeEngine();\r
66   static private DatabaseEngine databaseEngine;\r
67 \r
68   static private BundleFactory bundleFactory =\r
69       new CascadingBundleFactory(\r
70         new BasicBundleFactory(\r
71             new PropertiesFileBundleLoader(\r
72                 config().getHome())));\r
73 \r
74   public synchronized static MirLocalizer localizer() {\r
75     String localizerClassName;\r
76     Class localizerClass;\r
77 \r
78     if (localizer == null ) {\r
79       localizerClassName = config().getString("Mir.Localizer", "mirlocal.localizer.basic.MirBasicLocalizer");\r
80 \r
81       try {\r
82         localizerClass = Class.forName(localizerClassName);\r
83       }\r
84       catch (Throwable t) {\r
85         throw new ConfigException("localizer class '" +\r
86             localizerClassName + "' not found: " + t.toString());\r
87       }\r
88 \r
89       if (!(MirLocalizer.class.isAssignableFrom(localizerClass)))\r
90         throw new ConfigException("localizer class '" +\r
91             localizerClassName + "' is not assignable from MirLocalizer");\r
92 \r
93       try {\r
94         localizer = new MirCachingLocalizerDecorator((MirLocalizer) localizerClass.newInstance());\r
95       }\r
96       catch (Throwable t) {\r
97         throw new ConfigException("localizer class '" +\r
98             localizerClassName + "' cannot be instantiated: " + t.toString());\r
99       }\r
100     }\r
101 \r
102     return localizer;\r
103   }\r
104 \r
105   /**\r
106    * Returns a string that provides some global status information\r
107    */\r
108   public static String getStatus() {\r
109     StringBuffer result = new StringBuffer();\r
110 \r
111     result.append((Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())/(1024*1024));\r
112     result.append("M in use, ");\r
113     result.append(Thread.activeCount()).append(" threads, ");\r
114     result.append(getDatabaseEngine().getStatus());\r
115 \r
116     return result.toString();\r
117   }\r
118 \r
119   public synchronized static Abuse abuse() {\r
120     if (abuse==null) {\r
121       try {\r
122         abuse = new Abuse(localizer().dataModel().adapterModel());\r
123       }\r
124       catch (MirLocalizerExc e) {\r
125         throw new RuntimeException(e.getMessage());\r
126       }\r
127     }\r
128 \r
129     return abuse;\r
130   }\r
131 \r
132   /**\r
133    * returns the global change engine (used to track changed files)\r
134    */\r
135 //  public static ChangeEngine getChangeEngine() {\r
136 //    return changeEngine;\r
137 //  }\r
138 \r
139   public static MirPropertiesConfiguration config() {\r
140     return MirPropertiesConfiguration.instance();\r
141   }\r
142 \r
143   public synchronized static DatabaseEngine getDatabaseEngine() {\r
144     if (databaseEngine==null)\r
145       databaseEngine = new DatabaseEngine();\r
146 \r
147     return databaseEngine;\r
148   }\r
149 \r
150   public static ProducerEngine getProducerEngine() {\r
151     if (producerEngine == null) {\r
152       producerEngine = new ProducerEngine();\r
153     }\r
154 \r
155     return producerEngine;\r
156   }\r
157 \r
158   public static MRUCache mruCache() {\r
159     synchronized(MirGlobal.class) {\r
160       if (mruCache == null) {\r
161         mruCache = new MRUCache();\r
162       }\r
163       return mruCache;\r
164     }\r
165   }\r
166 \r
167   public static synchronized AccessControl accessControl() {\r
168     if (accessControl == null) {\r
169       accessControl=new AccessControl();\r
170     }\r
171 \r
172     return accessControl;\r
173   }\r
174 \r
175   public static void performArticleOperation(EntityUsers aUser, EntityContent  anArticle, String anOperation) {\r
176     MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation = getArticleOperationForName(anOperation);\r
177 \r
178     try {\r
179       EntityAdapter user = null;\r
180       if (aUser!=null)\r
181           user = localizer().dataModel().adapterModel().makeEntityAdapter("user", aUser);\r
182 \r
183       if (operation!=null)\r
184         operation.perform(\r
185             user,\r
186             localizer().dataModel().adapterModel().makeEntityAdapter("content", anArticle));\r
187     }\r
188     catch (Throwable t) {\r
189       t.printStackTrace(logger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));\r
190 \r
191       throw new RuntimeException(t.toString());\r
192     }\r
193   }\r
194 \r
195   public static void performCommentOperation(EntityUsers aUser, EntityComment  aComment, String anOperation) {\r
196     MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation = getCommentOperationForName(anOperation);\r
197 \r
198     try {\r
199       EntityAdapter user = null;\r
200       if (aUser!=null)\r
201           user = localizer().dataModel().adapterModel().makeEntityAdapter("user", aUser);\r
202 \r
203       if (operation!=null)\r
204         operation.perform(\r
205             user,\r
206             localizer().dataModel().adapterModel().makeEntityAdapter("comment", aComment));\r
207     }\r
208     catch (Throwable t) {\r
209       throw new RuntimeException(t.toString());\r
210     }\r
211   }\r
212 \r
213   private synchronized static MirAdminInterfaceLocalizer.MirSimpleEntityOperation\r
214       getArticleOperationForName(String aName) {\r
215     try {\r
216       if (articleOperations == null) {\r
217         articleOperations = new HashMap();\r
218         Iterator i = localizer().adminInterface().simpleArticleOperations().iterator();\r
219         while (i.hasNext()) {\r
220           MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =\r
221               (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();\r
222           articleOperations.put(operation.getName(), operation);\r
223         }\r
224       }\r
225 \r
226       return (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) articleOperations.get(aName);\r
227     }\r
228     catch (Throwable t) {\r
229       throw new RuntimeException(t.toString());\r
230     }\r
231   }\r
232 \r
233   private synchronized static MirAdminInterfaceLocalizer.MirSimpleEntityOperation\r
234       getCommentOperationForName(String aName) {\r
235     try {\r
236       if (commentOperations == null) {\r
237         commentOperations = new HashMap();\r
238         Iterator i = localizer().adminInterface().simpleCommentOperations().iterator();\r
239         while (i.hasNext()) {\r
240           MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =\r
241               (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();\r
242           commentOperations.put(operation.getName(), operation);\r
243         }\r
244       }\r
245 \r
246       return (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) commentOperations.get(aName);\r
247     }\r
248     catch (Throwable t) {\r
249       throw new RuntimeException(t.toString());\r
250     }\r
251   }\r
252 \r
253   public static boolean isUserLoggedIn(String anId) {\r
254     synchronized (loggedInUserIds) {\r
255       return loggedInUserIds.containsKey(anId);\r
256     }\r
257   }\r
258 \r
259   public static List getLoggedInUsers() {\r
260     List result = new ArrayList();\r
261 \r
262     synchronized (loggedInUsers) {\r
263       Iterator i = loggedInUsers.entrySet().iterator();\r
264 \r
265       while (i.hasNext()) {\r
266         Map.Entry entry = (Map.Entry) i.next();\r
267 \r
268         Map item = new HashMap();\r
269         item.put("name", entry.getKey());\r
270         item.put("count", entry.getValue());\r
271         result.add(item);\r
272       }\r
273     }\r
274 \r
275     return result;\r
276   }\r
277 \r
278   public static BundleFactory getBundleFactory() {\r
279     return bundleFactory;\r
280   }\r
281 \r
282   public static void registerLogin(String aName, String anId) {\r
283     modifyLoggedInCount(aName, anId, 1);\r
284   }\r
285 \r
286   public static void registerLogout(String aName, String anId) {\r
287     modifyLoggedInCount(aName, anId, -1);\r
288   }\r
289 \r
290   private static void modifyLoggedInCount(String aName, String anId, int aModifier) {\r
291     synchronized (loggedInUsers) {\r
292       Integer count = (Integer) loggedInUsers.get(aName);\r
293       if (count==null)\r
294         count = new Integer(0);\r
295 \r
296       if (count.intValue()+aModifier<=0) {\r
297         loggedInUsers.remove(aName);\r
298       }\r
299       else {\r
300         loggedInUsers.put(aName, new Integer(count.intValue() + aModifier));\r
301       }\r
302     }\r
303 \r
304     synchronized (loggedInUserIds) {\r
305       Integer count = (Integer) loggedInUserIds.get(anId);\r
306       if (count==null)\r
307         count = new Integer(0);\r
308 \r
309       if (count.intValue()+aModifier<=0) {\r
310         loggedInUserIds.remove(anId);\r
311       }\r
312       else {\r
313         loggedInUserIds.put(anId, new Integer(count.intValue() + aModifier));\r
314       }\r
315     }\r
316   }\r
317 \r
318   /**\r
319    * Called whenever a modifying admin action occurs. Used to log\r
320    * the action, if admin activity logging is turned on,\r
321    */\r
322   public static void logAdminUsage(EntityUsers aUser, String anObject, String aDescription) {\r
323     try {\r
324       if (config().getString("Mir.Admin.LogAdminActivity", "0").equals("1")) {\r
325         String user = "unknown (" + aUser.toString() + ")";\r
326         if (aUser != null)\r
327           user = aUser.getFieldValue("login");\r
328         adminUsageLogger.info(user + " | " + anObject + " | " + aDescription);\r
329       }\r
330     }\r
331     catch (Throwable t) {\r
332       logger.error("Error while logging admin usage ("+\r
333           aUser.toString()+", "+aDescription+"): " +t.toString());\r
334     }\r
335   }\r
336 \r
337   /**\r
338    * Reloads all reloadable configurations, such as the producer subsystem.\r
339    */\r
340   public static void reloadConfigurations() throws MirGlobalExc, MirGlobalFailure {\r
341     getProducerEngine().reloadConfiguration();\r
342     try {\r
343       LoggerEngine.reload();\r
344     }\r
345     catch (Throwable e) {\r
346       throw new MirGlobalFailure(e);\r
347     }\r
348     getBundleFactory().reload();\r
349   }\r
350 }\r
351 \r
352 \r