View Javadoc
1   package org.argeo.cms.internal.kernel;
2   
3   import static java.util.Locale.ENGLISH;
4   
5   import java.net.InetAddress;
6   import java.net.UnknownHostException;
7   import java.nio.file.spi.FileSystemProvider;
8   import java.util.ArrayList;
9   import java.util.List;
10  import java.util.Locale;
11  
12  import javax.jcr.RepositoryFactory;
13  import javax.transaction.TransactionManager;
14  import javax.transaction.UserTransaction;
15  
16  import org.apache.commons.logging.Log;
17  import org.apache.commons.logging.LogFactory;
18  import org.argeo.api.NodeConstants;
19  import org.argeo.api.NodeState;
20  import org.argeo.cms.CmsException;
21  import org.argeo.cms.LocaleUtils;
22  import org.argeo.transaction.simple.SimpleTransactionManager;
23  import org.argeo.util.LangUtils;
24  import org.osgi.framework.BundleContext;
25  import org.osgi.framework.Constants;
26  import org.osgi.framework.FrameworkUtil;
27  import org.osgi.service.cm.ManagedServiceFactory;
28  
29  public class CmsState implements NodeState {
30  	private final static Log log = LogFactory.getLog(CmsState.class);
31  	private final BundleContext bc = FrameworkUtil.getBundle(CmsState.class).getBundleContext();
32  
33  	// REFERENCES
34  	private Long availableSince;
35  
36  	// i18n
37  	private Locale defaultLocale;
38  	private List<Locale> locales = null;
39  
40  	private ThreadGroup threadGroup = new ThreadGroup("CMS");
41  	private KernelThread kernelThread;
42  	private List<Runnable> stopHooks = new ArrayList<>();
43  
44  	private final String stateUuid;
45  //	private final boolean cleanState;
46  	private String hostname;
47  
48  	public CmsState() {
49  //		this.stateUuid = stateUuid;
50  		this.stateUuid = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_UUID);
51  //		this.cleanState = stateUuid.equals(frameworkUuid);
52  		try {
53  			this.hostname = InetAddress.getLocalHost().getHostName();
54  		} catch (UnknownHostException e) {
55  			log.error("Cannot set hostname: " + e);
56  		}
57  
58  		availableSince = System.currentTimeMillis();
59  		if (log.isDebugEnabled())
60  			// log.debug("## CMS starting... stateUuid=" + this.stateUuid + (cleanState ? "
61  			// (clean state) " : " "));
62  			log.debug("## CMS starting... (" + stateUuid + ")");
63  
64  		initI18n();
65  		initServices();
66  
67  		// kernel thread
68  		kernelThread = new KernelThread(threadGroup, "Kernel Thread");
69  		kernelThread.setContextClassLoader(getClass().getClassLoader());
70  		kernelThread.start();
71  	}
72  
73  	private void initI18n() {
74  		Object defaultLocaleValue = KernelUtils.getFrameworkProp(NodeConstants.I18N_DEFAULT_LOCALE);
75  		defaultLocale = defaultLocaleValue != null ? new Locale(defaultLocaleValue.toString())
76  				: new Locale(ENGLISH.getLanguage());
77  		locales = LocaleUtils.asLocaleList(KernelUtils.getFrameworkProp(NodeConstants.I18N_LOCALES));
78  	}
79  
80  	private void initServices() {
81  		// JTA
82  		String tmType = KernelUtils.getFrameworkProp(NodeConstants.TRANSACTION_MANAGER,
83  				NodeConstants.TRANSACTION_MANAGER_SIMPLE);
84  		if (NodeConstants.TRANSACTION_MANAGER_SIMPLE.equals(tmType)) {
85  			initSimpleTransactionManager();
86  		} else if (NodeConstants.TRANSACTION_MANAGER_BITRONIX.equals(tmType)) {
87  //			initBitronixTransactionManager();
88  			throw new UnsupportedOperationException(
89  					"Bitronix is not supported anymore, but could be again if there is enough interest.");
90  		} else {
91  			throw new CmsException("Usupported transaction manager type " + tmType);
92  		}
93  
94  		// POI
95  //		POIXMLTypeLoader.setClassLoader(CTConnection.class.getClassLoader());
96  
97  		// Tika
98  //		OpenDocumentParser odfParser = new OpenDocumentParser();
99  //		bc.registerService(Parser.class, odfParser, new Hashtable());
100 //		PDFParser pdfParser = new PDFParser();
101 //		bc.registerService(Parser.class, pdfParser, new Hashtable());
102 //		OOXMLParser ooxmlParser = new OOXMLParser();
103 //		bc.registerService(Parser.class, ooxmlParser, new Hashtable());
104 //		TesseractOCRParser ocrParser = new TesseractOCRParser();
105 //		ocrParser.setLanguage("ara");
106 //		bc.registerService(Parser.class, ocrParser, new Hashtable());
107 
108 		// JCR
109 		RepositoryServiceFactory repositoryServiceFactory = new RepositoryServiceFactory();
110 		stopHooks.add(() -> repositoryServiceFactory.shutdown());
111 		bc.registerService(ManagedServiceFactory.class, repositoryServiceFactory,
112 				LangUtils.dico(Constants.SERVICE_PID, NodeConstants.NODE_REPOS_FACTORY_PID));
113 
114 		NodeRepositoryFactory repositoryFactory = new NodeRepositoryFactory();
115 		bc.registerService(RepositoryFactory.class, repositoryFactory, null);
116 
117 		// Security
118 		NodeUserAdmin userAdmin = new NodeUserAdmin(NodeConstants.ROLES_BASEDN, NodeConstants.TOKENS_BASEDN);
119 		stopHooks.add(() -> userAdmin.destroy());
120 		bc.registerService(ManagedServiceFactory.class, userAdmin,
121 				LangUtils.dico(Constants.SERVICE_PID, NodeConstants.NODE_USER_ADMIN_PID));
122 
123 		// File System
124 		CmsFsProvider cmsFsProvider = new CmsFsProvider();
125 //		ServiceLoader<FileSystemProvider> fspSl = ServiceLoader.load(FileSystemProvider.class);
126 //		for (FileSystemProvider fsp : fspSl) {
127 //			log.debug("FileSystemProvider " + fsp);
128 //			if (fsp instanceof CmsFsProvider) {
129 //				cmsFsProvider = (CmsFsProvider) fsp;
130 //			}
131 //		}
132 //		for (FileSystemProvider fsp : FileSystemProvider.installedProviders()) {
133 //			log.debug("Installed FileSystemProvider " + fsp);
134 //		}
135 		bc.registerService(FileSystemProvider.class, cmsFsProvider,
136 				LangUtils.dico(Constants.SERVICE_PID, NodeConstants.NODE_FS_PROVIDER_PID));
137 	}
138 
139 	private void initSimpleTransactionManager() {
140 		SimpleTransactionManager transactionManager = new SimpleTransactionManager();
141 		bc.registerService(TransactionManager.class, transactionManager, null);
142 		bc.registerService(UserTransaction.class, transactionManager, null);
143 		// TODO TransactionSynchronizationRegistry
144 	}
145 
146 //	private void initBitronixTransactionManager() {
147 //		// TODO manage it in a managed service, as startup could be long
148 //		ServiceReference<TransactionManager> existingTm = bc.getServiceReference(TransactionManager.class);
149 //		if (existingTm != null) {
150 //			if (log.isDebugEnabled())
151 //				log.debug("Using provided transaction manager " + existingTm);
152 //			return;
153 //		}
154 //
155 //		if (!TransactionManagerServices.isTransactionManagerRunning()) {
156 //			bitronix.tm.Configuration tmConf = TransactionManagerServices.getConfiguration();
157 //			tmConf.setServerId(UUID.randomUUID().toString());
158 //
159 //			Bundle bitronixBundle = FrameworkUtil.getBundle(bitronix.tm.Configuration.class);
160 //			File tmBaseDir = bitronixBundle.getDataFile(KernelConstants.DIR_TRANSACTIONS);
161 //			File tmDir1 = new File(tmBaseDir, "btm1");
162 //			tmDir1.mkdirs();
163 //			tmConf.setLogPart1Filename(new File(tmDir1, tmDir1.getName() + ".tlog").getAbsolutePath());
164 //			File tmDir2 = new File(tmBaseDir, "btm2");
165 //			tmDir2.mkdirs();
166 //			tmConf.setLogPart2Filename(new File(tmDir2, tmDir2.getName() + ".tlog").getAbsolutePath());
167 //		}
168 //		BitronixTransactionManager transactionManager = getTransactionManager();
169 //		stopHooks.add(() -> transactionManager.shutdown());
170 //		BitronixTransactionSynchronizationRegistry transactionSynchronizationRegistry = getTransactionSynchronizationRegistry();
171 //		// register
172 //		bc.registerService(TransactionManager.class, transactionManager, null);
173 //		bc.registerService(UserTransaction.class, transactionManager, null);
174 //		bc.registerService(TransactionSynchronizationRegistry.class, transactionSynchronizationRegistry, null);
175 //		if (log.isDebugEnabled())
176 //			log.debug("Initialised default Bitronix transaction manager");
177 //	}
178 
179 	void shutdown() {
180 		if (log.isDebugEnabled())
181 			log.debug("CMS stopping...  (" + this.stateUuid + ")");
182 
183 		if (kernelThread != null)
184 			kernelThread.destroyAndJoin();
185 		// In a different thread in order to avoid interruptions
186 		Thread stopHookThread = new Thread(() -> applyStopHooks(), "Apply Argeo Stop Hooks");
187 		stopHookThread.start();
188 		try {
189 			stopHookThread.join(10 * 60 * 1000);
190 		} catch (InterruptedException e) {
191 			// silent
192 		}
193 
194 		long duration = ((System.currentTimeMillis() - availableSince) / 1000) / 60;
195 		log.info("## ARGEO CMS STOPPED after " + (duration / 60) + "h " + (duration % 60) + "min uptime ##");
196 	}
197 
198 	/** Apply shutdown hoos in reverse order. */
199 	private void applyStopHooks() {
200 		for (int i = stopHooks.size() - 1; i >= 0; i--) {
201 			try {
202 				stopHooks.get(i).run();
203 			} catch (Exception e) {
204 				log.error("Could not run shutdown hook #" + i);
205 			}
206 		}
207 		// Clean hanging Gogo shell thread
208 		new GogoShellKiller().start();
209 	}
210 
211 //	@Override
212 //	public boolean isClean() {
213 //		return cleanState;
214 //	}
215 
216 	@Override
217 	public Long getAvailableSince() {
218 		return availableSince;
219 	}
220 
221 	/*
222 	 * ACCESSORS
223 	 */
224 	public Locale getDefaultLocale() {
225 		return defaultLocale;
226 	}
227 
228 	public List<Locale> getLocales() {
229 		return locales;
230 	}
231 
232 	public String getHostname() {
233 		return hostname;
234 	}
235 }