1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package nl.hippo.portal.cms;
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.nio.ByteBuffer;
21 import java.nio.channels.Channels;
22 import java.nio.channels.ReadableByteChannel;
23 import java.nio.channels.WritableByteChannel;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Locale;
28
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34
35 import nl.hippo.client.api.content.Document;
36 import nl.hippo.portal.cms.CMSRequestContext.UrlType;
37 import nl.hippo.portal.cms.site.SiteMap;
38 import nl.hippo.portal.cms.site.SiteMapItem;
39 import nl.hippo.portal.domain.model.User;
40 import nl.hippo.portal.locking.RequestLockManager;
41 import nl.hippo.portal.registry.Registration;
42
43 /***
44 * @version $Id: CMSApplicationRegistryImpl.java 14738 2008-11-17 10:46:54Z ddam $
45 *
46 */
47 public class CMSApplicationRegistryImpl implements CMSApplicationRegistry
48 {
49 private static final Log log = LogFactory.getLog(CMSApplicationRegistryImpl.class);
50
51 private static final Class[] REGISTRATION_TYPES = {CMSApplicationRegistration.class};
52
53 private static final int RESOURCE_BUFFER_SIZE = 1024 * 16;
54
55 private RequestLockManager lockManager;
56
57 private HashMap apps = new HashMap();
58 private HashMap domains = new HashMap();
59 private HashMap serverDomainMap = new HashMap();
60
61 public CMSApplicationRegistryImpl()
62 {
63 }
64
65 public CMSApplicationRegistryImpl(RequestLockManager lockManager)
66 {
67 this.lockManager = lockManager;
68 }
69
70
71
72
73 public Class[] getRegistrationTypes()
74 {
75 return REGISTRATION_TYPES;
76 }
77
78
79
80
81 public String getRegistryName()
82 {
83 return SERVICE_NAME;
84 }
85
86
87
88
89 public void registered()
90 {
91 }
92
93
94
95
96 public void unregistered()
97 {
98 }
99
100
101
102
103 public void available(Registration registration)
104 {
105 if ( registration instanceof CMSApplicationRegistration )
106 {
107 CMSApplicationRegistration cmsApp = (CMSApplicationRegistration)registration;
108 CMSApplicationImpl app = (CMSApplicationImpl)apps.get(cmsApp.getApplicationName());
109 if ( app != null )
110 {
111 app.available(cmsApp);
112 }
113 else
114 {
115 log.error("No CMSApplication defined for CMSApplicationRegistration named "+cmsApp.getApplicationName());
116
117 }
118 }
119 }
120
121
122
123
124 public void unavailable(Registration registration)
125 {
126 if ( registration instanceof CMSApplicationRegistration )
127 {
128 CMSApplicationRegistration cmsApp = (CMSApplicationRegistration)registration;
129 CMSApplicationImpl app = (CMSApplicationImpl)apps.get(cmsApp.getApplicationName());
130 if ( app != null )
131 {
132 app.available(null);
133 }
134 else
135 {
136
137 }
138 }
139 }
140
141 public void setDomains(List domains)
142 {
143 Iterator iter = domains.iterator();
144 while ( iter.hasNext() )
145 {
146 CMSDomainImpl domain = (CMSDomainImpl)iter.next();
147 this.domains.put(domain.getName(), domain);
148 this.serverDomainMap.put(domain.getFullName(), domain);
149 }
150 }
151
152 public void setApplications(List apps)
153 {
154 Iterator iter = apps.iterator();
155 while ( iter.hasNext() )
156 {
157 CMSApplicationImpl app = (CMSApplicationImpl)iter.next();
158 this.apps.put(app.getName(), app);
159 }
160 }
161
162 protected CMSDomainImpl getDomain(CMSPortalURL portalURL){
163 return (CMSDomainImpl) serverDomainMap.get(CMSDomainImpl.buildFullName(portalURL.getHost().getName(),portalURL.getHost().getPort()));
164 }
165
166 public CMSSite resolveSite(CMSUser cmsUser, CMSPortalURL portalURL, Locale locale){
167 CMSDomainImpl domain = getDomain(portalURL);
168 return resolveSiteImpl(domain,cmsUser, portalURL, locale);
169 }
170
171 public CMSSiteImpl resolveSiteImpl(CMSDomainImpl domain,CMSUser cmsUser, CMSPortalURL portalURL, Locale locale){
172 CMSSiteImpl site = null;
173 if ( domain != null ){
174
175 if ( portalURL.getSiteName() != null ) {
176 site = (CMSSiteImpl)domain.getSite(portalURL.getSiteName());
177 }
178 else if (domain.getDefaultSite() != null) {
179 site = (CMSSiteImpl)domain.getSite(domain.getDefaultSite());
180 }
181 }
182 return site;
183 }
184
185 protected SiteMapItem resolveSiteMapItem(CMSSiteImpl site, String path, CMSUser user, CMSPortalURL originalPortalUrl, Locale locale, boolean exactMatch, boolean usePortalUrl){
186 SiteMapItem smi = findSiteMapItem(site, path, exactMatch );
187 if (smi != null && !isSiteMapItemValid(smi, site, user, originalPortalUrl, locale,usePortalUrl)){
188 smi = null;
189 }
190 return smi;
191 }
192
193 protected boolean isSiteMapItemValid(SiteMapItem smi, CMSSiteImpl site, CMSUser user, CMSPortalURL portalURL, Locale locale, boolean usePortalUrl){
194 String sitePart = getSiteUrlPart(portalURL, site);
195 if (!usePortalUrl){
196 portalURL = portalURL.createPortalURL(portalURL.getBasePath()+sitePart+smi.getPath(),true);
197 }
198 CMSRequestContextImpl rc = createContext(site, user, portalURL, portalURL, smi, locale);
199 return rc.getSrc() == null || (rc.getSrc() != null && rc.getMetadata() != null);
200 }
201
202 /***
203 *
204 * @param portalUrl the original portal url
205 * @param site the site to be used to resolve the context
206 * @param user user
207 * @param path the sitemap path to be resolved to a context
208 * @param locale locale
209 * @param usePortalUrl true, if the original portal url's sitemap postfix and parameters should be used
210 * @return a status object containing information about which items could be resolved
211 */
212 protected ContextResolveStatus resolveContextForSite(CMSPortalURL portalUrl, CMSSiteImpl site, CMSUser user, String path, Locale locale, boolean usePortalUrl){
213 ContextResolveStatus resolveStatus = new ContextResolveStatus();
214 SiteMapItem smi = null;
215 if ( site.isAvailable() )
216 {
217 site.checkRefreshData();
218
219
220 if ( path != null )
221 {
222 smi = resolveSiteMapItem(site, path, user, portalUrl, locale, false, usePortalUrl );
223 }
224 else if ( site.getDefaultPath() != null )
225 {
226 smi = resolveSiteMapItem(site, site.getDefaultPath(), user, portalUrl, locale, true, usePortalUrl );
227 }
228 resolveStatus.setRequestedPage(smi);
229 if (smi == null){
230
231 smi = resolveSiteMapItem(site, site.getPageNotFoundPath(), user, portalUrl, locale, true, usePortalUrl );
232 resolveStatus.setPage404(smi);
233 }
234 if ( smi != null ){
235
236 if ( (user == null || user.getPrincipal() == null) && isLoginRequired(site,smi)){
237 if (site.getRequiredLoginPath() != null){
238 smi = resolveSiteMapItem(site, site.getRequiredLoginPath(), user, portalUrl, locale, true, usePortalUrl );
239 } else {
240 smi = null;
241 }
242 resolveStatus.setLoginPage(smi);
243 } else {
244
245 user = loadUser(site, user);
246 if (user.getUser() != null && user.getPrincipal() != null && site.getPageAcceptTermsOfUse() != null && !user.getUser().isTermsOfUseAccepted())
247 {
248 smi = resolveSiteMapItem(site, site.getPageAcceptTermsOfUse(), user, portalUrl, locale, true, usePortalUrl );
249 resolveStatus.setOtherPage(smi);
250 }
251 }
252
253
254 if (smi != null)
255 {
256
257 String sitePart = getSiteUrlPart(portalUrl, site);
258
259 CMSPortalURL newPortalUrl = null;
260
261 if (usePortalUrl && resolveStatus.requestedPageUsed){
262 newPortalUrl=portalUrl;
263 } else {
264
265 newPortalUrl=portalUrl.createPortalURL(portalUrl.getBasePath()+sitePart+smi.getPath(),usePortalUrl);
266 }
267
268 resolveStatus.context=createContext(site, user, newPortalUrl, portalUrl, smi, locale);
269 }
270
271 }
272 }
273 return resolveStatus;
274 }
275
276 private boolean isDefaultSite(CMSDomainImpl domain, CMSSite site){
277 return site != null && domain != null && domain.getDefaultSite() != null && site.getName() != null && site.getName().equals(domain.getDefaultSite());
278 }
279
280 public CMSRequestContext resolve(CMSUser user, CMSPortalURL portalURL, Locale locale)
281 {
282 logResolveInfo(user,portalURL,locale);
283 CMSDomainImpl domain = getDomain(portalURL);
284 ContextResolveStatus resolveStatus = new ContextResolveStatus();
285
286 if (domain != null){
287 CMSSiteImpl site = resolveSiteImpl(domain,user,portalURL,locale);
288 if (site != null){
289 resolveStatus = resolveContextForSite(portalURL,site,user,portalURL.getSiteMapPath(),locale,true);
290 }
291
292 if ( resolveStatus.context == null && domain.getDefaultSite() != null && !isDefaultSite(domain, site)){
293 site = (CMSSiteImpl) domain.getSite(domain.getDefaultSite());
294 if (site != null){
295
296 if (resolveStatus.page404NotFound){
297
298 if (site.getPageNotFoundPath() != null){
299 resolveStatus = resolveContextForSite(portalURL,site,user,site.getPageNotFoundPath(),locale,false);
300 }
301 } else if (resolveStatus.loginPageNotFound){
302
303 if (site.getRequiredLoginPath() != null){
304 resolveStatus = resolveContextForSite(portalURL,site,user,site.getRequiredLoginPath(),locale,false);
305 }
306 }
307
308
309 if (resolveStatus.context == null && site.getDefaultPath() != null){
310 resolveStatus = resolveContextForSite(portalURL,site,user,site.getDefaultPath(),locale,false);
311 }
312 }
313 }
314
315 if (resolveStatus.context != null){
316 setUrlType(resolveStatus.context, site);
317 }
318 }
319
320 return resolveStatus.context;
321 }
322
323 protected static void logResolveInfo(CMSUser user, CMSPortalURL portalURL, Locale locale){
324 if (log.isDebugEnabled())
325 {
326 StringBuffer b = new StringBuffer("resolve(user :");
327 b.append(user.getPrincipal() != null ? user.getPrincipal().getName() : "null");
328 b.append(", url: ").append(portalURL.toString());
329 b.append(", locale: ").append(locale != null ? locale.toString() : "null");
330 b.append(')');
331 log.debug(b.toString());
332 }
333 }
334
335 private void setUrlType(CMSRequestContextImpl context, CMSSiteImpl site){
336 CMSPortalURL portalUrl = context.getPortalURL();
337 if (portalUrl != null){
338 if (site.getPageNotFoundPath() != null && site.getPageNotFoundPath().equals(portalUrl.getSiteMapPath())){
339 context.setUrlType(UrlType.PAGENOTFOUND);
340 } else if (site.getPageAcceptTermsOfUse() != null && site.getPageAcceptTermsOfUse().equals(portalUrl.getSiteMapPath())) {
341 context.setUrlType(UrlType.ACCEPT_TERMS);
342 } else if (site.getDefaultPath() != null && site.getDefaultPath().equals(portalUrl.getSiteMapPath())) {
343 context.setUrlType(UrlType.DEFAULT);
344 } else if (site.getRequiredLoginPath() != null && site.getRequiredLoginPath().equals(portalUrl.getSiteMapPath())) {
345 context.setUrlType(UrlType.LOGIN);
346 } else {
347 context.setUrlType(UrlType.NORMAL);
348 }
349 }
350 }
351
352 private String getSiteUrlPart(CMSPortalURL portalURL, CMSSite site){
353 return (portalURL.getSiteName() == null && portalURL.usesDefaultSite() ? "" : "/"+site.getName());
354 }
355
356 private boolean isLoginRequired(CMSSiteImpl site, SiteMapItem smi) {
357 if ( site.getPublicPaths() != null ) {
358 String smiPath = smi.getPath();
359 String[] publicPaths = site.getPublicPaths();
360 for (int i = 0; i < publicPaths.length; i++ ) {
361 if (publicPaths[i] != null && smiPath.startsWith(publicPaths[i])) {
362 return false;
363 }
364 }
365 }
366 return true;
367 }
368
369 private SiteMapItem findSiteMapItem(CMSSiteImpl site, String path, boolean exact)
370 {
371 if ( log.isDebugEnabled() )
372 {
373 log.debug("findSiteMapItem("+site.getFullName()+","+path+","+exact+")");
374 }
375 SiteMapItem smi = null;
376 List siteMaps = site.getSiteMaps();
377 if ( siteMaps != null )
378 {
379 for ( int i = 0, size = siteMaps.size(); i < size; i++ )
380 {
381 SiteMap sm = (SiteMap)siteMaps.get(i);
382 if ( log.isDebugEnabled())
383 {
384 log.debug(" find in SiteMap: "+sm.getName());
385 }
386 if ( exact )
387 {
388 smi = sm.getByPath(path);
389 }
390 else
391 {
392 smi = sm.matchPath(path);
393 }
394 if ( smi != null )
395 {
396 if ( !smi.isLinkable() )
397 {
398 smi = null;
399 }
400 else
401 {
402 break;
403 }
404 }
405 }
406 }
407 if ( log.isDebugEnabled() )
408 {
409 if ( smi == null )
410 {
411 log.debug(" find result: null");
412 }
413 else
414 {
415 log.debug(" find result: "+smi.getPath());
416 }
417 }
418 return smi;
419 }
420
421 private CMSUser loadUser(CMSSiteImpl site, CMSUser user) {
422 if ( user.getUser() == null && user.getPrincipal() != null && site.getUserService() != null )
423 {
424 ClassLoader cl = Thread.currentThread().getContextClassLoader();
425 try
426 {
427 String userName = user.getPrincipal().getName();
428 Thread.currentThread().setContextClassLoader(site.getUserService().getClass().getClassLoader());
429 User usr = site.getUserService().getUser(userName);
430 if (usr != null )
431 {
432 user = new CMSUserWrapper(user, usr);
433 }
434 }
435 finally
436 {
437 Thread.currentThread().setContextClassLoader(cl);
438 }
439 }
440 return user;
441 }
442
443
444 private CMSRequestContextImpl createContext(CMSSiteImpl site, CMSUser user, CMSPortalURL portalURL, CMSPortalURL originalURL, SiteMapItem smi, Locale locale)
445 {
446 user = loadUser(site, user);
447 return new CMSRequestContextImpl(site,user,portalURL,originalURL,smi,locale);
448 }
449
450 public void serveResource(HttpServletRequest request, HttpServletResponse response) throws IOException
451 {
452 CMSDomainImpl domain = (CMSDomainImpl)serverDomainMap.get(CMSDomainImpl.buildFullName(request.getServerName(),request.getServerPort()));
453 if ( domain == null )
454 {
455 response.sendError(HttpServletResponse.SC_FORBIDDEN);
456 return;
457 }
458 String resourcePath = request.getPathInfo();
459 if ( resourcePath == null )
460 {
461 response.sendError(HttpServletResponse.SC_FORBIDDEN);
462 return;
463 }
464
465 resourcePath = resourcePath.substring(1);
466 int slash = resourcePath.indexOf('/');
467 if (slash == -1)
468 {
469 response.sendError(HttpServletResponse.SC_FORBIDDEN);
470 return;
471 }
472 CMSSiteImpl site = (CMSSiteImpl)domain.getSite(resourcePath.substring(0, slash));
473 if ( site == null )
474 {
475 response.sendError(HttpServletResponse.SC_NOT_FOUND);
476 return;
477 }
478 if ( resourcePath.length() < slash+1 )
479 {
480 response.sendError(HttpServletResponse.SC_FORBIDDEN);
481 return;
482 }
483 if ( site.getRequiredLoginPath() != null && request.getUserPrincipal() == null )
484 {
485 response.sendError(HttpServletResponse.SC_FORBIDDEN);
486 return;
487 }
488
489
490 resourcePath = resourcePath.substring(slash+1);
491 Document resource = site.getCMSService(CMSService.RESOURCE).get(resourcePath);
492 if ( resource == null )
493 {
494 response.sendError(HttpServletResponse.SC_NOT_FOUND);
495 return;
496 }
497 String contentType = resource.getMetadata().getContentType();
498 if ( contentType == null )
499 {
500 response.sendError(HttpServletResponse.SC_BAD_REQUEST);
501 return;
502 }
503
504 InputStream src = resource.getContent().getResponseAsStream();
505 ReadableByteChannel readChannel = null;
506 WritableByteChannel writeChannel = null;
507 try
508 {
509 if (src != null)
510 {
511 response.setContentType(contentType);
512
513 ByteBuffer buffer = ByteBuffer.allocateDirect(RESOURCE_BUFFER_SIZE);
514 readChannel = Channels.newChannel(src);
515 writeChannel = Channels.newChannel(response.getOutputStream());
516 while (readChannel.read(buffer) != -1 && writeChannel.isOpen())
517 {
518 buffer.flip();
519 writeChannel.write(buffer);
520 buffer.clear();
521 }
522
523 writeChannel.close();
524 writeChannel = null;
525 readChannel.close();
526 readChannel = null;
527 src.close();
528 src = null;
529 response.flushBuffer();
530 }
531 else
532 {
533 response.sendError(HttpServletResponse.SC_NOT_FOUND);
534 }
535 }
536 catch (Exception e)
537 {
538 if (src != null)
539 {
540 try
541 {
542 src.close();
543 }
544 catch (Exception e2)
545 {
546
547 }
548 }
549 if (writeChannel != null)
550 {
551 try
552 {
553 writeChannel.close();
554 }
555 catch (Exception e2)
556 {
557
558 }
559 }
560 if (readChannel != null)
561 {
562 try
563 {
564 readChannel.close();
565 }
566 catch (Exception e2)
567 {
568
569 }
570 }
571 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
572 }
573 }
574
575 protected static class ContextResolveStatus {
576
577 private boolean page404NotFound;
578 private boolean loginPageNotFound;
579 private boolean requestedPageUsed;
580
581 private CMSRequestContextImpl context;
582
583 public void setPage404(SiteMapItem smi){
584 requestedPageUsed=false;
585 page404NotFound= (smi == null);
586 }
587
588 public void setLoginPage(SiteMapItem smi){
589 requestedPageUsed=false;
590 loginPageNotFound= (smi == null);
591 }
592
593 public void setRequestedPage(SiteMapItem smi){
594 requestedPageUsed = (smi != null);
595 }
596
597 public void setOtherPage(SiteMapItem smi){
598 requestedPageUsed=false;
599 }
600 }
601
602 }