Source Code Cross Referenced for DirectoryMonitor.java in  » EJB-Server-geronimo » plugins » org » apache » geronimo » deployment » hot » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » EJB Server geronimo » plugins » org.apache.geronimo.deployment.hot 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /**
002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
003:         *  contributor license agreements.  See the NOTICE file distributed with
004:         *  this work for additional information regarding copyright ownership.
005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
006:         *  (the "License"); you may not use this file except in compliance with
007:         *  the License.  You may obtain a copy of the License at
008:         *
009:         *     http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         *  Unless required by applicable law or agreed to in writing, software
012:         *  distributed under the License is distributed on an "AS IS" BASIS,
013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         *  See the License for the specific language governing permissions and
015:         *  limitations under the License.
016:         */package org.apache.geronimo.deployment.hot;
017:
018:        import org.apache.commons.logging.LogFactory;
019:        import org.apache.commons.logging.Log;
020:        import org.apache.geronimo.deployment.cli.DeployUtils;
021:        import org.apache.geronimo.deployment.util.DeploymentUtil;
022:        import org.apache.geronimo.kernel.repository.Artifact;
023:        import org.apache.geronimo.kernel.config.IOUtil;
024:
025:        import java.io.File;
026:        import java.io.Serializable;
027:        import java.io.IOException;
028:        import java.util.Map;
029:        import java.util.HashMap;
030:        import java.util.HashSet;
031:        import java.util.Iterator;
032:        import java.util.List;
033:        import java.util.LinkedList;
034:        import java.util.Set;
035:
036:        /**
037:         * Meant to be run as a Thread that tracks the contents of a directory.
038:         * It sends notifications for changes to its immediate children (it
039:         * will look into subdirs for changes, but will not send notifications
040:         * for files within subdirectories).  If a file continues to change on
041:         * every pass, this will wait until it stabilizes before sending an
042:         * add or update notification (to handle slow uploads, etc.).
043:         *
044:         * @version $Rev: 539130 $ $Date: 2007-05-17 14:45:24 -0700 (Thu, 17 May 2007) $
045:         */
046:        public class DirectoryMonitor implements  Runnable {
047:            private static final Log log = LogFactory
048:                    .getLog(DirectoryMonitor.class);
049:
050:            public static interface Listener {
051:                /**
052:                 * The directory monitor doesn't take any action unless this method
053:                 * returns true (to avoid deploying before the deploy GBeans are
054:                 * running, etc.).
055:                 */
056:                boolean isServerRunning();
057:
058:                /**
059:                 * Checks if the file with same configID is already deployed 
060:                 *
061:                 * @return true if the file in question is already available in the
062:                 *         server, false if it should be deployed on the next pass.
063:                 */
064:                boolean isFileDeployed(File file, String configId);
065:
066:                /**
067:                 * Called during initialization on previously deployed files.
068:                 *
069:                 * @return The time that the file was deployed.  If the current
070:                 *         version in the directory is newer, the file will be
071:                 *         updated on the first pass.
072:                 */
073:                long getDeploymentTime(File file, String configId);
074:
075:                /**
076:                 * Called to indicate that the monitor has fully initialized
077:                 * and will be doing normal deployment operations from now on.
078:                 */
079:                void started();
080:
081:                /**
082:                 * Called to check whether a file passes the smell test before
083:                 * attempting to deploy it.
084:                 *
085:                 * @return true if there's nothing obviously wrong with this file.
086:                 *         false if there is (for example, it's clearly not
087:                 *         deployable).
088:                 */
089:                boolean validateFile(File file, String configId);
090:
091:                /**
092:                 * @return A configId for the deployment if the addition was processed
093:                 *         successfully (or an empty String if the addition was OK but
094:                 *         the configId could not be determined).  null if the addition
095:                 *         failed, in which case the file will be added again next time
096:                 *         it changes.
097:                 */
098:                String fileAdded(File file);
099:
100:                /**
101:                 * @return true if the removal was processed successfully.  If not
102:                 *         the file will be removed again on the next pass.
103:                 */
104:                boolean fileRemoved(File file, String configId);
105:
106:                String fileUpdated(File file, String configId);
107:
108:                /**
109:                 * This method returns the module id of an application deployed in the default group.
110:                 * @return String respresenting the ModuleId if the application is already deployed
111:                 */
112:                String getModuleId(String config);
113:
114:            }
115:
116:            private int pollIntervalMillis;
117:            private File directory;
118:            private boolean done = false;
119:            private Listener listener; // a little cheesy, but do we really need multiple listeners?
120:            private final Map files = new HashMap();
121:            private volatile String workingOnConfigId;
122:
123:            public DirectoryMonitor(File directory, Listener listener,
124:                    int pollIntervalMillis) {
125:                this .directory = directory;
126:                this .listener = listener;
127:                this .pollIntervalMillis = pollIntervalMillis;
128:            }
129:
130:            public int getPollIntervalMillis() {
131:                return pollIntervalMillis;
132:            }
133:
134:            public void setPollIntervalMillis(int pollIntervalMillis) {
135:                this .pollIntervalMillis = pollIntervalMillis;
136:            }
137:
138:            public Listener getListener() {
139:                return listener;
140:            }
141:
142:            public void setListener(Listener listener) {
143:                this .listener = listener;
144:            }
145:
146:            public File getDirectory() {
147:                return directory;
148:            }
149:
150:            /**
151:             * Warning: changing the directory at runtime will cause all files in the
152:             * old directory to be removed and all files in the new directory to be
153:             * added, next time the thread awakens.
154:             */
155:            public void setDirectory(File directory) {
156:                if (!directory.isDirectory() || !directory.canRead()) {
157:                    throw new IllegalArgumentException(
158:                            "Cannot monitor directory "
159:                                    + directory.getAbsolutePath());
160:                }
161:                this .directory = directory;
162:            }
163:
164:            public synchronized boolean isDone() {
165:                return done;
166:            }
167:
168:            public synchronized void close() {
169:                this .done = true;
170:            }
171:
172:            public void removeModuleId(Artifact id) {
173:                log.info("Hot deployer notified that an artifact was removed: "
174:                        + id);
175:                if (id.toString().equals(workingOnConfigId)) {
176:                    // since the redeploy process inserts a new thread to handle progress,
177:                    // this is called by a different thread than the hot deploy thread during
178:                    // a redeploy, and this check must be executed outside the synchronized
179:                    // block or else it will cause a deadlock!
180:                    return; // don't react to events we generated ourselves
181:                }
182:                synchronized (files) {
183:                    for (Iterator it = files.keySet().iterator(); it.hasNext();) {
184:                        String path = (String) it.next();
185:                        FileInfo info = (FileInfo) files.get(path);
186:                        Artifact target = Artifact.create(info.getConfigId());
187:                        if (id.matches(target)) { // need to remove record & delete file
188:                            File file = new File(path);
189:                            if (file.exists()) { // if not, probably it's deletion kicked off this whole process
190:                                log.info("Hot deployer deleting " + id);
191:                                if (!IOUtil.recursiveDelete(file)) {
192:                                    log.error("Hot deployer unable to delete "
193:                                            + path);
194:                                }
195:                                it.remove();
196:                            }
197:                        }
198:                    }
199:                }
200:            }
201:
202:            public void run() {
203:                boolean serverStarted = false, initialized = false;
204:                while (!done) {
205:                    try {
206:                        Thread.sleep(pollIntervalMillis);
207:                    } catch (InterruptedException e) {
208:                        continue;
209:                    }
210:                    try {
211:                        if (listener != null) {
212:                            if (!serverStarted && listener.isServerRunning()) {
213:                                serverStarted = true;
214:                            }
215:                            if (serverStarted) {
216:                                if (!initialized) {
217:                                    initialized = true;
218:                                    initialize();
219:                                    listener.started();
220:                                } else {
221:                                    scanDirectory();
222:                                }
223:                            }
224:                        }
225:                    } catch (Exception e) {
226:                        log.error("Error during hot deployment", e);
227:                    }
228:                }
229:            }
230:
231:            public void initialize() {
232:                File parent = directory;
233:                File[] children = parent.listFiles();
234:                for (int i = 0; i < children.length; i++) {
235:                    File child = children[i];
236:                    if (!child.canRead()) {
237:                        continue;
238:                    }
239:                    FileInfo now = child.isDirectory() ? getDirectoryInfo(child)
240:                            : getFileInfo(child);
241:                    now.setChanging(false);
242:                    try {
243:                        now.setConfigId(calculateModuleId(child));
244:                        if (listener == null
245:                                || listener.isFileDeployed(child, now
246:                                        .getConfigId())) {
247:                            if (listener != null) {
248:                                now.setModified(listener.getDeploymentTime(
249:                                        child, now.getConfigId()));
250:                            }
251:                            log.info("At startup, found " + now.getPath()
252:                                    + " with deploy time " + now.getModified()
253:                                    + " and file time "
254:                                    + new File(now.getPath()).lastModified());
255:                            files.put(now.getPath(), now);
256:                        }
257:                    } catch (Exception e) {
258:                        log.error("Unable to scan file "
259:                                + child.getAbsolutePath()
260:                                + " during initialization", e);
261:                    }
262:                }
263:            }
264:
265:            /**
266:             * Looks for changes to the immediate contents of the directory we're watching.
267:             */
268:            private void scanDirectory() {
269:                File parent = directory;
270:                File[] children = parent.listFiles();
271:                if (!directory.exists() || children == null) {
272:                    log
273:                            .error("Hot deploy directory has disappeared!  Shutting down directory monitor.");
274:                    done = true;
275:                    return;
276:                }
277:                synchronized (files) {
278:                    Set oldList = new HashSet(files.keySet());
279:                    List actions = new LinkedList();
280:                    for (int i = 0; i < children.length; i++) {
281:                        File child = children[i];
282:                        if (!child.canRead()) {
283:                            continue;
284:                        }
285:                        FileInfo now = child.isDirectory() ? getDirectoryInfo(child)
286:                                : getFileInfo(child);
287:                        FileInfo then = (FileInfo) files.get(now.getPath());
288:                        if (then == null) { // Brand new, wait a bit to make sure it's not still changing
289:                            now.setNewFile(true);
290:                            files.put(now.getPath(), now);
291:                            log.debug("New File: " + now.getPath());
292:                        } else {
293:                            oldList.remove(then.getPath());
294:                            if (now.isSame(then)) { // File is the same as the last time we scanned it
295:                                if (then.isChanging()) {
296:                                    log.debug("File finished changing: "
297:                                            + now.getPath());
298:                                    // Used to be changing, now in (hopefully) its final state
299:                                    if (then.isNewFile()) {
300:                                        actions.add(new FileAction(
301:                                                FileAction.NEW_FILE, child,
302:                                                then));
303:                                    } else {
304:                                        actions.add(new FileAction(
305:                                                FileAction.UPDATED_FILE, child,
306:                                                then));
307:                                    }
308:                                    then.setChanging(false);
309:                                } // else it's just totally unchanged and we ignore it this pass
310:                            } else if (then.isNewFile()
311:                                    || now.getModified() > then.getModified()) {
312:                                // The two records are different -- record the latest as a file that's changing
313:                                // and later when it stops changing we'll do the add or update as appropriate.
314:                                now.setConfigId(then.getConfigId());
315:                                now.setNewFile(then.isNewFile());
316:                                files.put(now.getPath(), now);
317:                                log.debug("File Changed: " + now.getPath());
318:                            }
319:                        }
320:                    }
321:                    // Look for any files we used to know about but didn't find in this pass
322:                    for (Iterator it = oldList.iterator(); it.hasNext();) {
323:                        String name = (String) it.next();
324:                        FileInfo info = (FileInfo) files.get(name);
325:                        log.debug("File removed: " + name);
326:                        if (info.isNewFile()) { // Was never added, just whack it
327:                            files.remove(name);
328:                        } else {
329:                            actions.add(new FileAction(FileAction.REMOVED_FILE,
330:                                    new File(name), info));
331:                        }
332:                    }
333:                    if (listener != null) {
334:                        // First pass: validate all changed files, so any obvious errors come out first
335:                        for (Iterator it = actions.iterator(); it.hasNext();) {
336:                            FileAction action = (FileAction) it.next();
337:                            if (!listener.validateFile(action.child,
338:                                    action.info.getConfigId())) {
339:                                resolveFile(action);
340:                                it.remove();
341:                            }
342:                        }
343:                        // Second pass: do what we're meant to do
344:                        for (Iterator it = actions.iterator(); it.hasNext();) {
345:                            FileAction action = (FileAction) it.next();
346:                            try {
347:                                if (action.action == FileAction.REMOVED_FILE) {
348:                                    workingOnConfigId = action.info
349:                                            .getConfigId();
350:                                    if (listener.fileRemoved(action.child,
351:                                            action.info.getConfigId())) {
352:                                        files.remove(action.child.getPath());
353:                                    }
354:                                    workingOnConfigId = null;
355:                                } else if (action.action == FileAction.NEW_FILE) {
356:                                    if (listener.isFileDeployed(action.child,
357:                                            calculateModuleId(action.child))) {
358:                                        workingOnConfigId = calculateModuleId(action.child);
359:                                        String result = listener
360:                                                .fileUpdated(action.child,
361:                                                        workingOnConfigId);
362:                                        if (result != null) {
363:                                            if (!result.equals("")) {
364:                                                action.info.setConfigId(result);
365:                                            } else {
366:                                                action.info
367:                                                        .setConfigId(calculateModuleId(action.child));
368:                                            }
369:                                        }
370:                                        // remove the previous jar or directory if duplicate
371:                                        File[] childs = directory.listFiles();
372:                                        for (int i = 0; i < childs.length; i++) {
373:                                            String path = childs[i]
374:                                                    .getAbsolutePath();
375:                                            String configId = ((FileInfo) files
376:                                                    .get(path)).configId;
377:                                            if (configId != null
378:                                                    && configId
379:                                                            .equals(workingOnConfigId)
380:                                                    && !action.child
381:                                                            .getAbsolutePath()
382:                                                            .equals(path)) {
383:                                                File fd = new File(path);
384:                                                if (fd.isDirectory()) {
385:                                                    log
386:                                                            .info("Deleting the Directory: "
387:                                                                    + path);
388:                                                    if (DeploymentUtil
389:                                                            .recursiveDelete(fd))
390:                                                        log
391:                                                                .debug("Successfully deleted the Directory: "
392:                                                                        + path);
393:                                                    else
394:                                                        log
395:                                                                .error("Couldn't delete the hot deployed directory="
396:                                                                        + path);
397:                                                } else if (fd.isFile()) {
398:                                                    log
399:                                                            .info("Deleting the File: "
400:                                                                    + path);
401:                                                    if (fd.delete()) {
402:                                                        log
403:                                                                .debug("Successfully deleted the File: "
404:                                                                        + path);
405:                                                    } else
406:                                                        log
407:                                                                .error("Couldn't delete the hot deployed file="
408:                                                                        + path);
409:                                                }
410:                                                files.remove(path);
411:                                            }
412:                                        }
413:                                        workingOnConfigId = null;
414:                                    } else {
415:                                        String result = listener
416:                                                .fileAdded(action.child);
417:                                        if (result != null) {
418:                                            if (!result.equals("")) {
419:                                                action.info.setConfigId(result);
420:                                            } else {
421:                                                action.info
422:                                                        .setConfigId(calculateModuleId(action.child));
423:                                            }
424:                                        }
425:                                    }
426:                                    action.info.setNewFile(false);
427:                                } else if (action.action == FileAction.UPDATED_FILE) {
428:                                    workingOnConfigId = action.info
429:                                            .getConfigId();
430:                                    String result = listener.fileUpdated(
431:                                            action.child, action.info
432:                                                    .getConfigId());
433:                                    FileInfo update = action.info;
434:                                    if (result != null) {
435:                                        if (!result.equals("")) {
436:                                            update.setConfigId(result);
437:                                        } else {
438:                                            update
439:                                                    .setConfigId(calculateModuleId(action.child));
440:                                        }
441:                                    }
442:                                    workingOnConfigId = null;
443:                                }
444:                            } catch (Exception e) {
445:                                log.error("Unable to " + action.getActionName()
446:                                        + " file "
447:                                        + action.child.getAbsolutePath(), e);
448:                            } finally {
449:                                resolveFile(action);
450:                            }
451:                        }
452:                    }
453:                }
454:            }
455:
456:            private void resolveFile(FileAction action) {
457:                if (action.action == FileAction.REMOVED_FILE) {
458:                    files.remove(action.child.getPath());
459:                } else {
460:                    action.info.setChanging(false);
461:                }
462:            }
463:
464:            private String calculateModuleId(File module) {
465:                String moduleId = null;
466:                try {
467:                    moduleId = DeployUtils.extractModuleIdFromArchive(module);
468:                } catch (Exception e) {
469:                    try {
470:                        moduleId = DeployUtils.extractModuleIdFromPlan(module);
471:                    } catch (IOException e2) {
472:                        log.warn("Unable to calculate module ID for file "
473:                                + module.getAbsolutePath() + " ["
474:                                + e2.getMessage() + "]");
475:                    }
476:                }
477:                if (moduleId == null) {
478:                    int pos = module.getName().lastIndexOf('.');
479:                    moduleId = pos > -1 ? module.getName().substring(0, pos)
480:                            : module.getName();
481:                    moduleId = listener.getModuleId(moduleId);
482:                }
483:                return moduleId;
484:            }
485:
486:            /**
487:             * We don't pay attention to the size of the directory or files in the
488:             * directory, only the highest last modified time of anything in the
489:             * directory.  Hopefully this is good enough.
490:             */
491:            private FileInfo getDirectoryInfo(File dir) {
492:                FileInfo info = new FileInfo(dir.getAbsolutePath());
493:                info.setSize(0);
494:                info.setModified(getLastModifiedInDir(dir));
495:                return info;
496:            }
497:
498:            private long getLastModifiedInDir(File dir) {
499:                long value = dir.lastModified();
500:                File[] children = dir.listFiles();
501:                long test;
502:                for (int i = 0; i < children.length; i++) {
503:                    File child = children[i];
504:                    if (!child.canRead()) {
505:                        continue;
506:                    }
507:                    if (child.isDirectory()) {
508:                        test = getLastModifiedInDir(child);
509:                    } else {
510:                        test = child.lastModified();
511:                    }
512:                    if (test > value) {
513:                        value = test;
514:                    }
515:                }
516:                return value;
517:            }
518:
519:            private FileInfo getFileInfo(File child) {
520:                FileInfo info = new FileInfo(child.getAbsolutePath());
521:                info.setSize(child.length());
522:                info.setModified(child.lastModified());
523:                return info;
524:            }
525:
526:            private static class FileAction {
527:                private static int NEW_FILE = 1;
528:                private static int UPDATED_FILE = 2;
529:                private static int REMOVED_FILE = 3;
530:                private int action;
531:                private File child;
532:                private FileInfo info;
533:
534:                public FileAction(int action, File child, FileInfo info) {
535:                    this .action = action;
536:                    this .child = child;
537:                    this .info = info;
538:                }
539:
540:                public String getActionName() {
541:                    return action == NEW_FILE ? "deploy"
542:                            : action == UPDATED_FILE ? "redeploy" : "undeploy";
543:                }
544:            }
545:
546:            private static class FileInfo implements  Serializable {
547:                private String path;
548:                private long size;
549:                private long modified;
550:                private boolean newFile;
551:                private boolean changing;
552:                private String configId;
553:
554:                public FileInfo(String path) {
555:                    this .path = path;
556:                    newFile = false;
557:                    changing = true;
558:                }
559:
560:                public String getPath() {
561:                    return path;
562:                }
563:
564:                public long getSize() {
565:                    return size;
566:                }
567:
568:                public void setSize(long size) {
569:                    this .size = size;
570:                }
571:
572:                public long getModified() {
573:                    return modified;
574:                }
575:
576:                public void setModified(long modified) {
577:                    this .modified = modified;
578:                }
579:
580:                public boolean isNewFile() {
581:                    return newFile;
582:                }
583:
584:                public void setNewFile(boolean newFile) {
585:                    this .newFile = newFile;
586:                }
587:
588:                public boolean isChanging() {
589:                    return changing;
590:                }
591:
592:                public void setChanging(boolean changing) {
593:                    this .changing = changing;
594:                }
595:
596:                public String getConfigId() {
597:                    return configId;
598:                }
599:
600:                public void setConfigId(String configId) {
601:                    this .configId = configId;
602:                }
603:
604:                public boolean isSame(FileInfo info) {
605:                    if (!path.equals(info.path)) {
606:                        throw new IllegalArgumentException(
607:                                "Should only be used to compare two files representing the same path!");
608:                    }
609:                    return size == info.size && modified == info.modified;
610:                }
611:            }
612:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.