git-svn-id: http://bigbluebutton.googlecode.com/svn/trunk@2289 af16638f-c34d-0410-8cfa-b39d5352b314

This commit is contained in:
Richard Alam 2009-08-15 20:57:12 +00:00
parent 67840af82a
commit eec62a2421
530 changed files with 66673 additions and 0 deletions

12
asteriskjava/.classpath Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.13/log4j-1.2.13.jar" sourcepath="M2_REPO/log4j/log4j/1.2.13/log4j-1.2.13-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/junit/junit/4.0/junit-4.0.jar" sourcepath="M2_REPO/junit/junit/4.0/junit-4.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/easymock/easymock/2.2/easymock-2.2.jar" sourcepath="M2_REPO/org/easymock/easymock/2.2/easymock-2.2-sources.jar"/>
<classpathentry exported="true" kind="con" path="GROOVY_SUPPORT"/>
<classpathentry kind="output" path="bin"/>
</classpath>

31
asteriskjava/.project Normal file
View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>asterisk-java-1.0.0-m2</name>
<comment>Java interface for Asterisk PBX.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.codehaus.groovy.eclipse.groovyBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
<nature>org.codehaus.groovy.eclipse.groovyNature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,4 @@
#Sat Aug 15 16:30:35 EDT 2009
eclipse.preferences.version=1
groovy.compiler.output.path=bin-groovy
support.groovy=true

View File

@ -0,0 +1,3 @@
#Sat Aug 15 16:30:35 EDT 2009
eclipse.preferences.version=1
org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch,*.groovy

39
asteriskjava/ANNOUNCEMENT Normal file
View File

@ -0,0 +1,39 @@
ANNOUNCEMENT: Asterisk-Java 0.3.1 released
Asterisk-Java 0.3.1, the free Java library for Asterisk PBX integration,
has been released.
The Asterisk-Java package consists of a set of Java classes that allow
you to easily build Java applications that interact with an Asterisk
PBX Server. Asterisk-Java supports both interfaces that Asterisk
provides for this scenario: The FastAGI protocol and the Manager API.
Asterisk-Java 0.3.1 is a maintenance release that solves the
following issues:
* [AJ-81] - executeCliCommand() always executes "show voicemail users"
* [AJ-86] - getChannelByName doesn't return the latest channel
* [AJ-80] - getMeetMeRooms() should only return active rooms
* [AJ-68] - Support for Bridge Action
* [AJ-74] - Support Strategy property in QueueParamsEvent
Asterisk-Java takes advantage of the features of Java 5.0 and therefore
requires a Java Virtual Machine of at least version 1.5.0.
Asterisk-Java is used in several commercial environments and by
the following Open Source projects:
* Asterisk-JTAPI
JTAPI implementation for Asterisk.
http://asterisk-jtapi.sf.net/
* Asterisk-IM
A plugin for the Openfire XMPP (jabber) server. It provides
integrated presence between your IM client and phone, notification
of incoming calls by IM and originate calls from supported IM
clients.
http://www.igniterealtime.org/projects/openfire/
* Asterisk Desktop Manager (ADM)
A desktop application that will allow for automatic on-call volume
reduction, one click dial from clipboard, integrated phonebook
and more.
http://adm.hamnett.org/
Asterisk-Java is available under Apache 2.0 license at http://asterisk-java.org

145
asteriskjava/CHANGES Normal file
View File

@ -0,0 +1,145 @@
Asterisk-Java 1.0.0
Warning:
Values for event properties of type String that match one of the null
literals used by Asterisk are automatically set to null in A-J 1.0.0.
The null literals are:
"<unknown>", "unknown", "none", "<none>", "-none-", "(none)",
"<not set>", "(not set)", "<no name>", "n/a", "<null>" and
"(null)".
Asterisk-Java 0.3.1
* [AJ-81] - executeCliCommand() always executes "show voicemail users"
* [AJ-86] - getChannelByName doesn't return the latest channel
* [AJ-79] - Support for the CallWeaver protocol identifier
* [AJ-80] - getMeetMeRooms() should only return active rooms
* [AJ-68] - Support for Bridge Action
* [AJ-74] - Support Strategy property in QueueParamsEvent
* [AJ-78] - Documentation needs thorough examples of the Live API
Asterisk-Java 0.3
* [AJ-30] - Fixed version detection when restarting Asterisk
* [AJ-59] - Fixed incorrect class and method names when using JavaLoggingLog
* [AJ-60] - Fixed DefaultManagerConnection.sendEventGeneratingAction()
for Asterisk 1.4.1
* [AJ-50] - Finished support for Asterisk 1.4
* [AJ-54] - Fixed AsteriskQueue observer and Park events
* [AJ-55] - Added "videoSupport" and "realtimeDevice" to PeerEntryEvent
* [AJ-56] - Added "callerIdNum" to AbstractChannelEvent
* [AJ-57] - Added "memberName" to AbstractQueueMemberEvent
* [AJ-58] - Added support for OpenPBX
* [AJ-43] - Added support for GetConfig and UpdateConfig actions
* [AJ-62] - Added executeCliCommand() method to AsteriskServer
* [AJ-2] - Updated design doc and tutorial according to AGI changes
Asterisk-Java 0.3-m2
* Added getManagerConnection() to AsteriskServer (AJ-41)
* Added timestamp property to ManagerEvent (AJ-35)
* Added QueueSummaryAction, QueueSummaryEvent and
QueueSummaryCompleteEvent (AJ-42)
* Added ZapRestartAction (AJ-45)
* Added PauseMontiorAction and UnpauseMonitorAction and
pauseMontior() and unpauseMonitor() methods to
AsteriskChannel (AJ-44)
* Added AbstractManagerEventListener
Asterisk-Java 0.3-m1
* Changed package name from net.sf.asterisk to org.asteriskjava
and renamed AGI classes to Agi to conform to Java coding
standards
* Renamed ManagerEventHandler and ManagerResponseHandler to
ManagerEventListener and SendActionCallback.
* Introduced generics and leveraged other Java5 features like
java.util.concurrent.
* Added SSL support for the Manager API.
* ManagerReader threads are now daemon threads so as soon as
all other threads are terminated the JVM will quit
* Changed log level for message about ManagerReader termination
from INFO to DEBUG
* ManagerConnectionFactory has been simplified. Usage example:
new ManagerConnectionFactory("host", "user", "pass")
.createManagerConnection();
* Fixed timing bug in ResourceBundleMappingStrategy (AJ-25)
* Fixed interrupt in DefaultManagerConnection (AJ-27)
* Fixed accountCode always being null in AgiRequest
* Fixed synchronization bug when generating internal action ids for
the Manager API
* Fixed synchronous sendAction for responses that are received really
fast, i.e. before the thread is put asleep.
* Fixed ConnectEvent being only fired after a successful
login (AJ-32)
* Fixed no setter for the dnd field when sending
ZapShowChannelsAction (AJ-33)
* Added support for login with eventMask (AJ-28)
* Added support for using non-shared instances AgiScript, i.e. a
new instance is used for each request if you set the
shareInstances property on your MappingStrategy to false.
Default is still to use shared instances (AJ-29)
* Live objects now fire PropertyChangeEvents
* Added extraContext, extraExten, extraPriority properties to
RedirectAction to support BRIstuffed versions of Asterisk (AJ-34)
* Added recordFile and controlStreamFile methods to AgiChannel and
BaseAgiScript
* Added channel variable AJ_AGISTATUS that is set by the AgiServer
to "SUCCESS" if the AgiScript completed successfully, "FAILED"
if it threw an exception or "NOT_FOUND" if the mapping strategy
did not return a script for the requested URL.
* Added MeetMeMuteEvent and muted property for MeetMeUser.
* Added MeetMeMuteAction and MeetMeUnmuteAction.
* Added ParkAction.
* Added PlayDtmfAction and playDtmf() method for AsteriskChannel.
* Added several new event properties for Asterisk 1.4:
- MeetMeEvent: channel and uniqueId
- MeetMeLeaveEvent: callerIdNum, callerIdName and duration
- MeetMeTalkingEvent: status
- StatusEvent: callerIdNum and callerIdName
- OriginateEvent: callerIdNum and callerIdName
- JoinEvent and LeaveEvent: uniqueId
- AgentConnectEvent: brigedChannel
Asterisk-Java 0.2
* Added SayDateTimeCommand (AJ-23)
* Added GetFullVariableCommand (AJ-23)
* Added ReceiveTextCommand (AJ-23)
* Changed SetPriorityCommand to support labels (AJ-23)
* Added callingPres, callingAni2, callingTns and callingTon
properties to AGIRequest (AJ-22)
* Fixed CallerId information in AGIRequest for
Asterisk 1.2 (AJ-21)
Asterisk-Java 0.2-rc2
* Fixed mapping of Variable property in OriginateAction for
Asterisk 1.2 (AJ-15)
* Added FaxReceived event from spandsp (AJ-20)
* Added SimpleMappingStrategy and AGIServerThread to ease
integration of AGIServer when using Spring Framework
* Timeout for socket connection can now be specified for
the ManagerConnection (AJ-16)
* Added getPort() method to lookup port of an AGIServer (AJ-14)
* Readded getContext(), getExtension(), getPriority() as
convenience methods to Channel (AJ-12)
* Decreased log level for unknown events to INFO (AJ-13)
Asterisk-Java 0.2-rc1
* Added Support for the new Actions, Events and Commands
of Asterisk 1.2
* Fixed getting the uniqueId from a successful originate
in the DefaultAsteriskManager
* Added isConnected() method to ManagerConnection
* Changed ManagerAction to be an interface rather that an
abstract base class. If you extended ManagerAction, please
use AbstractManagerAction instead.
* Added support for event generating Actions, i.e. Actions
that send their result as a series of Event rather than
the usual ManagerResults. See the sendEventGeneratingAction()
methods in ManagerConnection for more information.
* Deprecated AbstractAGIScript in favor of BaseAGIScript. This
allows you write cleaner AGI scripts as you don't have to
pass the channel variable to all methods.
* Added convenience constructors for manager actions
Asterisk-Java 0.1
* Added accessors for raw attributes in ManagerResponse
* Fixed bug in action id creation
* Changed logging to use either log4j or java.util.logging
* Fixed ExecCommand

202
asteriskjava/LICENSE.txt Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

36
asteriskjava/README.txt Normal file
View File

@ -0,0 +1,36 @@
README for Asterisk-Java
========================
== INTRODUCTION ==
The Asterisk-Java package consists of a set of Java classes that allow you to
easily build Java applications that interact with an Asterisk PBX Server.
Asterisk-Java supports both interfaces that Asterisk provides for this
scenario: The FastAGI protocol and the Manager API.
The FastAGI implementation supports all commands currently available from
Asterisk.
The Manager API implementation supports receiving events from the Asterisk
server (e.g. call progess, registered peers, channel state) and sending
actions to Asterisk (e.g. originate call, agent login/logoff, start/stop
voice recording).
A complete list of the available events and actions is available in the
javadocs.
See docs/tutorial.html for examples.
== LEGAL ==
Asterisk-Java is subject to the terms detailed in the license agreement
accompanying it.
== GETTING ASTERISK-JAVA ==
Asterisk-Java is available from http://asterisk-java.org
== SYSTEM REQUIREMENTS ==
Asterisk-Java needs a Java Virtual Machine of at least version 1.6
(Java SE 6.0).

View File

@ -0,0 +1,32 @@
<atlassian-ide-plugin>
<project-configuration>
<servers>
<jira>
<server-id>e88a6130-6bd2-45dd-aa5d-57b845f76d0f</server-id>
<name>jira.reucon.org</name>
<url>http://jira.reucon.org</url>
</jira>
<crucible>
<server-id>89c4100c-3c20-4d7d-8611-0dbe1bee742e</server-id>
<name>reucon</name>
<url>https://secure.reucon.net/fisheye</url>
<isFisheyeInstance>true</isFisheyeInstance>
</crucible>
<bamboo>
<server-id>68a20e42-e943-4a1d-b807-45cad35b4f73</server-id>
<name>reucon</name>
<url>https://secure.reucon.net/build</url>
<use-favourites>false</use-favourites>
<bamboo2>true</bamboo2>
<plans>
<plan key="AJ-DEF" />
<plan key="AJ-NIGHTLY" />
</plans>
</bamboo>
</servers>
<default-crucible-server>89c4100c-3c20-4d7d-8611-0dbe1bee742e</default-crucible-server>
<default-fisheye-server>89c4100c-3c20-4d7d-8611-0dbe1bee742e</default-fisheye-server>
<default-fisheye-repo>repos</default-fisheye-repo>
<fisheye-project-path>asterisk-java/trunk</fisheye-project-path>
</project-configuration>
</atlassian-ide-plugin>

204
asteriskjava/checkstyle.xml Normal file
View File

@ -0,0 +1,204 @@
<?xml version="1.0"?>
<!--
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.1//EN"
"http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
<!--
Checkstyle configuration that checks the sun coding conventions from:
- the Java Language Specification at
http://java.sun.com/docs/books/jls/second_edition/html/index.html
- the Sun Code Conventions at http://java.sun.com/docs/codeconv/
- the Javadoc guidelines at
http://java.sun.com/j2se/javadoc/writingdoccomments/index.html
- the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html
- some best practices
Checkstyle is very configurable. Be sure to read the documentation at
http://checkstyle.sf.net (or in your downloaded distribution).
Most Checks are configurable, be sure to consult the documentation.
To completely disable a check, just comment it out or delete it from the file.
Finally, it is worth reading the documentation.
-->
<module name="Checker">
<!-- Checks that a package.html file exists for each package. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html#PackageHtml -->
<module name="PackageHtml"/>
<!-- Checks whether files end with a new line. -->
<!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
<module name="NewlineAtEndOfFile"/>
<!-- Checks that property files contain the same keys. -->
<!-- See http://checkstyle.sf.net/config_misc.html#Translation -->
<module name="Translation"/>
<module name="TreeWalker">
<property name="cacheFile" value="${checkstyle.cache.file}"/>
<!-- ************************************************************** -->
<!-- Checks that are different from the sun coding conventions ones -->
<!-- ************************************************************** -->
<property name="tabWidth" value="4"/>
<module name="LeftCurly">
<property name="option" value="nl"/>
</module>
<module name="RightCurly">
<property name="option" value="alone"/>
</module>
<module name="LineLength">
<property name="max" value="120"/>
<property name="ignorePattern" value="@version"/>
</module>
<module name="MemberName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
</module>
<!-- ************************************************************** -->
<!-- Default Sun coding conventions checks -->
<!-- ************************************************************** -->
<!-- Checks for Javadoc comments. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
<module name="JavadocMethod"/>
<module name="JavadocType"/>
<module name="JavadocVariable"/>
<!-- Checks for Naming Conventions. -->
<!-- See http://checkstyle.sf.net/config_naming.html -->
<module name="ConstantName"/>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MethodName"/>
<module name="PackageName"/>
<module name="ParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<!-- Checks for Headers -->
<!-- See http://checkstyle.sf.net/config_header.html -->
<module name="Header">
<!-- The follow property value demonstrates the ability -->
<!-- to have access to ANT properties. In this case it uses -->
<!-- the ${basedir} property to allow Checkstyle to be run -->
<!-- from any directory within a project. -->
<property name="headerFile" value="${checkstyle.header.file}"/>
<property name="ignoreLines" value="1,6"/>
</module>
<!-- Following interprets the header file as regular expressions. -->
<!-- <module name="RegexpHeader"/> -->
<!-- Checks for imports -->
<!-- See http://checkstyle.sf.net/config_import.html -->
<module name="AvoidStarImport"/>
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<!-- Checks for Size Violations. -->
<!-- See http://checkstyle.sf.net/config_sizes.html -->
<module name="FileLength"/>
<module name="MethodLength"/>
<module name="ParameterNumber"/>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
<module name="EmptyForIteratorPad"/>
<module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<module name="OperatorWrap"/>
<module name="ParenPad"/>
<module name="TabCharacter"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
<!-- Modifier Checks -->
<!-- See http://checkstyle.sf.net/config_modifiers.html -->
<module name="ModifierOrder"/>
<module name="RedundantModifier"/>
<!-- Checks for blocks. You know, those {}'s -->
<!-- See http://checkstyle.sf.net/config_blocks.html -->
<module name="AvoidNestedBlocks"/>
<module name="EmptyBlock"/>
<module name="NeedBraces"/>
<!-- Checks for common coding problems -->
<!-- See http://checkstyle.sf.net/config_coding.html -->
<module name="AvoidInlineConditionals"/>
<module name="DoubleCheckedLocking"/> <!-- MY FAVOURITE -->
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<!-- module name="HiddenField"/ -->
<module name="IllegalInstantiation"/>
<module name="InnerAssignment"/>
<module name="MagicNumber"/>
<module name="MissingSwitchDefault"/>
<module name="RedundantThrows"/>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<!-- Checks for class design -->
<!-- See http://checkstyle.sf.net/config_design.html -->
<module name="DesignForExtension"/>
<module name="FinalClass"/>
<module name="HideUtilityClassConstructor"/>
<module name="InterfaceIsType"/>
<module name="VisibilityModifier"/>
<!-- Miscellaneous other checks. -->
<!-- See http://checkstyle.sf.net/config_misc.html -->
<module name="ArrayTypeStyle"/>
<module name="FinalParameters"/>
<module name="GenericIllegalRegexp">
<property name="format" value="\s+$"/>
<property name="ignoreComments" value="true"/>
<property name="message" value="Line has trailing spaces."/>
</module>
<module name="TodoComment"/>
<module name="UpperEll"/>
</module>
</module>

251
asteriskjava/codestyle.xml Normal file
View File

@ -0,0 +1,251 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="10">
<profile name="reucon" version="10">
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="52"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="48"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="64"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="64"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="125"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
</profile>
</profiles>

18
asteriskjava/dist/agi/demo.groovy vendored Normal file
View File

@ -0,0 +1,18 @@
// countdown
(10..0).each { digit -> channel.sayNumber(digit.toString()) }
channel.streamFile('beep');
// read a few dtmf digits
while ((digit = channel.waitForDigit(10000)) != 0)
{
if (digit == '#' || digit == '*')
{
break;
}
channel.sayDigits(digit.toString());
}
// beep to say good bye ;)
channel.streamFile('beep');

22
asteriskjava/dist/agi/demo.js vendored Normal file
View File

@ -0,0 +1,22 @@
// countdown
for (var i = 10; i >= 0; i--)
{
channel.sayNumber(i);
}
channel.streamFile('beep');
// read a few dtmf digits
var digit;
while ((digit = channel.waitForDigit(10000)) != 0)
{
if (digit == '#' || digit == '*')
{
break;
}
channel.sayDigits(digit);
}
// beep to say good bye ;)
channel.streamFile('beep');

24
asteriskjava/dist/agi/demo.php vendored Normal file
View File

@ -0,0 +1,24 @@
<?php
// countdown
for ($i = 10; $i >= 0; $i--)
{
$channel->sayNumber($i);
}
$channel->streamFile('beep');
// read a few dtmf digits
while (($digit = $channel->waitForDigit(10000)) != 0)
{
if ($digit == '#' || $digit == '*')
{
break;
}
$channel->sayDigits($digit);
}
// beep to say good bye ;)
$channel->streamFile('beep');
?>

Binary file not shown.

BIN
asteriskjava/dist/lib/javamail-141.jar vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
asteriskjava/dist/lib/quercus-3.2.1.jar vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,164 @@
Product: Clover
License: Open Source License, 0.x, 1.x
Issued: Thu Oct 21 2004 21:27:21 CDT
Expiry: Never
Key: 7e1c2ed27ee858f42adedd953
Name: Stefan Reuter
Org: asterisk-java
Certificate: AAABsm+Ow8B7/zEbxOMqqKwwrdpP+a1COmJGHco7sCNLjHkHnajPF+dQW
Ct12PMy0uml0s9xuus5wKngJ9OFk5XFeh01dzQF66bhXH1bvegLfvja3Kle6BYtDv4LZgE
gk3E0aJN4IbgTn+TgUckSevXDR4KzK77NWJfrVzkxV3/Jer0jWuM7QJbvwkyoXjNEVc/ye
OTlpI6MQPLOI4Og5zfT4dHD72UJcFEgGvSx6kEeWPn+RGX8xt3GVb8MJ1ywMWYUIcFWe2m
JfmT8OoDi6VDKGj/p0gCEpn+6zEmWuUoleg59zSy9cEHoJVDLjoVAqhUmFnDYl2Tk9LLP3
3Gn0yLWqYQk2fzWw7d6BiJrcX/2seoMHkW4+l9l5JKzy0XyFHUIsTFzbjbeTmZpk24hkje
f9PFP3hFn89RVjsozstxYnbhGeHhQZNk/uG0ftnAR0bXdFv0ZYFU0t/597/Kxw9gpyss1w
r/rdMDm0c+7KgckZjxPrfvvFgAFuutYe//Ol8Be8lguE7Fkews81gIyc4d0NvU+gu7qUZo
WOOjTVMuDM7TJWIHlKT54UGPELrE8E/I7XICOJa8WipV+qmMXPXk/q2oiu1udzSy7Tmvyi
hZ85yCnuH9DBnpBZRbS88AtM6Lje56JhNykODYtRipYlvD8vlukR+/c4sBWNkJlYG7FU/o
SP8Hrnh8VSFASymIfLGF/6v+wzRsoiAyO3MlQPDajIsCnmFIFanUVG453AmktJwxbKU0=
License Agreement: CLOVER VERSION 1 (ONE) SOFTWARE LICENSE AGREEMENT
1. Licenses and Software
Cortex eBusiness Pty Ltd, an Australian Proprietary Limited Company
("CENQUA") hereby grants to the purchaser (the "LICENSEE") a limited,
revocable, worldwide, non-exclusive, non-transferable,
non-sublicensable license to use the Clover version 1 (one) software
(the "Software"), including any minor upgrades thereof during the Term
(hereinafter defined) up to, but not including the next major version
of the Software. The licensee shall not, or knowingly allow others to,
reverse engineer, decompile, disassemble, modify, adapt, create
derivative works from or otherwise attempt to derive source code from
the Software provided. And, in accordance with the terms and
conditions of this Software License Agreement (the "Agreement"), the
Software shall be used solely by the licensed users in accordance with
the following edition specific conditions:
a) Server Edition
A Server Edition license entitles the Licensee to execute one instance
of Clover Server Edition on one (1) machine for the purposes of
instrumenting source code and generating reports. There are no
limitations on the use of the instrumented source code or generated
reports produced by Server Edition.
b) Workstation Edition
A Workstation Edition license entitles the licensee to use Clover
Workstation Edition on one (1) machine by one (1) individual end
user. Workstation Edition does not permit the generation of reports
for distribution.
c) Team Edition
A Team Edition license entitles the licensee to use Clover Team
edition on any number of machines solely by the licensed number of
users. Reports generated by Clover Team Edition are strictly for use
only by the licensed number of individual end users.
2. License Fee
In exchange for the License(s), the Licensee shall pay to Cenqua a
one-time, up front, non-refundable license fee. At the sole discretion
of Cenqua this fee will be waived for non-commercial
projects. Notwithstanding the Licensee's payment of the License Fee,
Cenqua reserves the right to terminate the License if Cenqua discovers
that the Licensee and/or the Licensee's use of the Software is in
breach of this Agreement.
3. Proprietary Rights
Cenqua will retain all right, title and interest in and to the
Software, all copies thereof, and Cenqua website(s), software, and
other intellectual property, including, but not limited to, ownership
of all copyrights, look and feel, trademark rights, design rights,
trade secret rights and any and all other intellectual property and
other proprietary rights therein. The Licensee will not directly or
indirectly obtain or attempt to obtain at any time, any right, title
or interest by registration or otherwise in or to the trademarks,
service marks, copyrights, trade names, symbols, logos or designations
or other intellectual property rights owned or used by Cenqua. All
technical manuals or other information provided by Cenqua to the
Licensee shall be the sole property of Cenqua.
4. Term and Termination
Subject to the other provisions hereof, this Agreement shall commence
upon the Licensee's opting into this Agreement and continue until the
Licensee discontinues use of the Software or the Agreement terminates
automatically upon the Licensee's breach of any term or condition of
this Agreement (the "Term"). Upon any such termination, the Licensee
will delete the Software immediately.
5. Copying & Transfer
The Licensee may copy the Software for back-up purposes only. The
Licensee may not assign or otherwise transfer the Software to any
third party.
6. Specific Disclaimer of Warranty and Limitation of Liability
THE SOFTWARE IS PROVIDED WITHOUT WARRANTY OF ANY KIND. CENQUA
DISCLAIMS ALL WARRANTIES, EXPRESSED OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE. CENQUA WILL NOT BE LIABLE FOR ANY DAMAGES
ASSOCIATED WITH THE SOFTWARE, INCLUDING, WITHOUT LIMITATION, ORDINARY,
INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING
BUT NOT LIMITED TO DAMAGES RELATING TO LOST DATA OR LOST PROFITS, EVEN
IF CENQUA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Warranties and Representations
Licensee Indemnification. CENQUA agrees to indemnify, defend and hold
the Licensee harmless from and against any and all liabilities,
damages, losses, claims, costs, and expenses (including reasonable
legal fees) arising out of or resulting from the Software or the use
thereof infringing upon, misappropriating or violating any patents,
copyrights, trademarks, or trade secret rights or other proprietary
rights of persons, firms or entities who are not parties to this
Agreement.
CENQUA Indemnification. The Licensee warrants and represents that the
Licensee's actions with regard to the Software will be in compliance
with all applicable laws; and the Licensee agrees to indemnify,
defend, and hold CENQUA harmless from and against any and all
liabilities, damages, losses, claims, costs, and expenses (including
reasonable legal fees) arising out of or resulting from the
Licensee's failure to observe the use restrictions set forth herein.
8. Publicity
The Licensee grants permission for CENQUA to use Licensee's name
solely in customer lists. CENQUA shall not, without prior consent in
writing, use the Licensee's name, or that of its affiliates, in any
form with the specific exception of customer lists. CENQUA agrees to
remove Licensee's name from any and all materials within 7 days if
notified by the Licensee in writing.
9. Governing Law
This Agreement shall be governed by the laws of New South Wales,
Australia.
10. Independent Contractors
The parties are independent contractors with respect to each other,
and nothing in this Agreement shall be construed as creating an
employer-employee relationship, a partnership, agency relationship or
a joint venture between the parties.
11. Assignment
This Agreement is not assignable or transferable by the Licensee.
CENQUA in its sole discretion may transfer a license to a third party
at the written request of the Licensee.
12. Entire Agreement
This Agreement constitutes the entire agreement between the parties
concerning the Licensee's use of the Software. This Agreement
supersedes any prior verbal understanding between the parties and any
Licensee purchase order or other ordering document, regardless of
whether such document is received by CENQUA before or after execution
of this Agreement. This Agreement may be amended only in writing by
CENQUA.

293
asteriskjava/pom.xml Normal file
View File

@ -0,0 +1,293 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.asteriskjava</groupId>
<artifactId>asterisk-java</artifactId>
<name>Asterisk-Java</name>
<version>1.0.0-m2</version>
<description>The free Java library for Asterisk PBX integration.</description>
<url>http://asterisk-java.org/</url>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<organization>
<name>Stefan Reuter</name>
<url>http://asterisk-java.org/</url>
</organization>
<inceptionYear>2004</inceptionYear>
<developers>
<developer>
<name>Stefan Reuter</name>
<id>srt</id>
<email>srt at users.sourceforge.net</email>
<timezone>+1</timezone>
</developer>
<developer>
<name>Pierre-Yves Roger</name>
<id>partoutatis</id>
<email>partoutatis at users.sourceforge.net</email>
<timezone>+1</timezone>
</developer>
<developer>
<name>John Hood</name>
<id>squinky86</id>
<email>john at asteriasgi.com</email>
<organization>Asteria Solutions Group, Inc.</organization>
<timezone>-6</timezone>
</developer>
<developer>
<name>Martin B. Smith</name>
<id>martins</id>
<email>martins at bebr.ufl.edu</email>
<organization>Bureau of Economic and Business Research, University of Florida</organization>
<timezone>-5</timezone>
</developer>
</developers>
<scm>
<connection>scm:svn:http://svn.reucon.net/repos/asterisk-java/tags/asterisk-java-1.0.0-m2</connection>
<developerConnection>scm:svn:https://secure.reucon.net/svn/repos/asterisk-java/tags/asterisk-java-1.0.0-m2</developerConnection>
</scm>
<distributionManagement>
<repository>
<id>reucon</id>
<url>https://secure.reucon.net/nexus/content/repositories/opensource</url>
</repository>
<snapshotRepository>
<id>reucon</id>
<url>https://secure.reucon.net/nexus/content/repositories/opensource-snapshots</url>
</snapshotRepository>
<site>
<id>reucon</id>
<url>dav:https://secure.reucon.net/maven/projects/public/${artifactId}/${version}</url>
</site>
</distributionManagement>
<issueManagement>
<system>JIRA</system>
<url>http://jira.reucon.org/browse/AJ</url>
</issueManagement>
<mailingLists>
<mailingList>
<name>Asterisk-Java User List</name>
<subscribe>http://lists.sourceforge.net/mailman/listinfo/asterisk-java-users</subscribe>
<unsubscribe>http://lists.sourceforge.net/mailman/listinfo/asterisk-java-users</unsubscribe>
<archive>http://sourceforge.net/mailarchive/forum.php?forum=asterisk-java-users</archive>
</mailingList>
<mailingList>
<name>Asterisk-Java Developer List</name>
<subscribe>http://lists.sourceforge.net/mailman/listinfo/asterisk-java-devel</subscribe>
<unsubscribe>http://lists.sourceforge.net/mailman/listinfo/asterisk-java-devel</unsubscribe>
<archive>http://sourceforge.net/mailarchive/forum.php?forum=asterisk-java-devel</archive>
</mailingList>
</mailingLists>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.3</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.0-beta-9</version>
<configuration>
<remoteTagging>true</remoteTagging>
<preparationGoals>clean install</preparationGoals>
<autoVersionSubmodules>true</autoVersionSubmodules>
<tagBase>https://secure.reucon.net/svn/repos/${artifactId}/tags</tagBase>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>org.asteriskjava.Cli</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-2</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/bin.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>attached</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.0</version>
</plugin>
</plugins>
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-webdav</artifactId>
<version>1.0-beta-2</version>
</extension>
</extensions>
<finalName>${artifactId}</finalName>
</build>
<dependencies>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>compile</scope>
</dependency>
</dependencies>
<reporting>
<plugins>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<groups>
<group>
<title>Core Packages</title>
<packages>
org.asteriskjava:org.asteriskjava.fastagi:org.asteriskjava.fastagi.command:org.asteriskjava.fastagi.reply:org.asteriskjava.manager:org.asteriskjava.manager.action:org.asteriskjava.manager.response:org.asteriskjava.manager.event:org.asteriskjava.live:org.asteriskjava.util
</packages>
</group>
<group>
<title>Internal Packages</title>
<packages>
org.asteriskjava.fastagi.internal:org.asteriskjava.manager.internal:org.asteriskjava.live.internal:org.asteriskjava.util.internal
</packages>
</group>
</groups>
<header>${project.name}</header>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<configuration>
<formats>
<format>html</format>
<format>xml</format>
</formats>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jxr-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>surefire-report-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>changelog-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>2.3</version>
<configuration>
<targetJdk>1.5</targetJdk>
<minimumTokens>100</minimumTokens>
<linkXRef>true</linkXRef>
<rulesets>
<ruleset>/rulesets/basic.xml</ruleset>
</rulesets>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>1.2</version>
</plugin>
<!--
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jdepend-maven-plugin</artifactId>
<version>2.0-beta-1-SNAPSHOT</version>
</plugin>
-->
</plugins>
</reporting>
<profiles>
<profile>
<id>release</id>
<activation>
<property>
<name>release</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- Add to the command line:
-Dkeystore=Stefan_Reuter_Code_Signing.jks
-Dstorepass=secret
-->
<alias>Stefan_Reuter_Code_Signing</alias>
<verify>true</verify>
<!--
<keystore>Stefan_Reuter_Code_Signing.jks</keystore>
<storepass>secret</storepass>
-->
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,6 @@
log4j.rootCategory=INFO, Console
log4j.category.org.asteriskjava.live=DEBUG
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d %c %p [%t] - %m\n

View File

@ -0,0 +1,31 @@
package org.asteriskjava.fastagi;
import org.asteriskjava.manager.DefaultManagerConnection;
import org.asteriskjava.manager.ManagerConnection;
import java.util.Date;
public class GetDataScript extends BaseAgiScript
{
public void service(AgiRequest request, AgiChannel channel) throws AgiException
{
channel.streamFile("tt-monkeys");
channel.sayDateTime(new Date().getTime());
}
public static void main(String[] args) throws Exception
{
ManagerConnection connection;
AsyncAgiServer agiServer;
connection = new DefaultManagerConnection("localhost", "manager", "obelisk");
agiServer = new AsyncAgiServer(new GetDataScript());
connection.addEventListener(agiServer);
connection.login();
while (true)
{
Thread.sleep(1000L);
}
}
}

View File

@ -0,0 +1,48 @@
package org.asteriskjava.fastagi;
import org.apache.log4j.Logger;
import org.asteriskjava.live.DefaultAsteriskServer;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Arrays;
public class HangupTest extends BaseAgiScript
{
private Logger logger = Logger.getLogger(HangupTest.class);
public void service(AgiRequest request, AgiChannel channel) throws AgiException
{
System.out.println(Arrays.toString(request.getArguments()));
answer();
try
{
for (int i = 0; i < 5000; i++)
{
System.out.println("Saying " + i);
sayDigits(String.valueOf(i));
}
}
catch (Exception e)
{
logger.info("Exception caught: " + e.getMessage(), e);
}
}
public static void main(String[] args) throws IOException
{
AgiServerThread agiServerThread = new AgiServerThread();
agiServerThread.setAgiServer(new DefaultAgiServer());
agiServerThread.setDaemon(false);
agiServerThread.startup();
DefaultAsteriskServer server = new DefaultAsteriskServer("localhost", 1234, "manager", "obelisk");
server.initialize();
server.originateToApplication("SIP/phone-02", "AGI",
"agi://" + InetAddress.getLocalHost().getHostAddress() + "/" + HangupTest.class.getName()
+ ", arg1,,arg3", 30000);
}
}

View File

@ -0,0 +1,130 @@
package org.asteriskjava.fastagi;
import java.io.IOException;
public class SpeechDemo extends BaseAgiScript
{
// the digits grammar is shipped as part of the Lumenvox engine
private final String grammarPath = "/etc/lumenvox/Lang/BuiltinGrammars/ABNFDigits.gram";
public void service(AgiRequest request, AgiChannel channel) throws AgiException
{
try
{
// answer the call
answer();
// and say hello
streamFile("speech-demo/welcome");
// initialize the speech engine
speechCreate();
}
catch (AgiHangupException e)
{
System.out.println("User hung up.");
}
catch (AgiSpeechException e)
{
System.out.println("Unable to initialize speech engine: no speech engine installed or licence trouble.");
streamFile("speech-demo/engine-error");
hangup();
return;
}
try
{
while (true)
{
recognizeDigits();
}
}
catch (AgiHangupException e)
{
System.out.println("User hung up.");
}
finally
{
try
{
// make sure to destroy the speech object otherwise licenses might leak.
speechDestroy();
}
catch (Exception e)
{
// swallow
}
}
}
public void recognizeDigits() throws AgiException
{
final String grammarLabel = "digits";
// load the grammar we are going the use
speechLoadGrammar(grammarLabel, grammarPath);
// active it
speechActivateGrammar(grammarLabel);
// and use if for recognition
SpeechRecognitionResult result = speechRecognize("speech-demo/prompt", 10);
System.out.println(result);
// deactivate the grammar
speechDeactivateGrammar(grammarLabel);
// check whether speech was recognized or a DTMF digit was pressed
if (result.isSpeech())
{
// if speech was recognized look at the confidence score
if (result.getScore() > 990)
{
streamFile("speech-demo/absolutely-sure");
}
else if (result.getScore() > 800)
{
streamFile("speech-demo/pretty-sure");
}
else
{
streamFile("speech-demo/not-sure");
}
// say what we have recognized
sayDigits(result.getText());
}
else if (result.isDtmf())
{
// if the user pressed a DTMF digit
streamFile("speech-demo/dtmf");
// read it back to him
if (result.getDigit() == '*')
{
streamFile("digits/star");
}
else if (result.getDigit() == '#')
{
streamFile("digits/pound");
}
else
{
sayDigits(Character.toString(result.getDigit()));
}
}
else
{
// if we received no input play an error message
streamFile("speech-demo/no-input");
}
}
public static void main(String[] args) throws IOException
{
AgiServerThread agiServerThread = new AgiServerThread();
agiServerThread.setAgiServer(new DefaultAgiServer());
agiServerThread.setDaemon(false);
agiServerThread.startup();
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.live;
import junit.framework.TestCase;
public class AsteriskServerTestCase extends TestCase
{
protected AsteriskServer server;
@Override
public void setUp() throws Exception
{
server = new DefaultAsteriskServer("pbx0", "manager", "obelisk");
//server = new DefaultAsteriskServer("localhost", "manager", "obelisk");
}
@Override
public void tearDown() throws Exception
{
server.getManagerConnection().logoff();
}
}

View File

@ -0,0 +1,31 @@
package org.asteriskjava.live;
import java.util.Collection;
public class MeetMeTest extends AsteriskServerTestCase
{
public void testMeetMeRoom() throws Exception
{
server.originateToExtension("Local/1201@basa", "conference", "1000", 1, 5000L);
server.getMeetMeRoom("1000");
printRooms();
System.out.println("waiting...");
Thread.sleep(20000);
printRooms();
}
private void printRooms() throws Exception
{
Collection<MeetMeRoom> rooms;
rooms = server.getMeetMeRooms();
for (MeetMeRoom room : rooms)
{
System.out.println(room);
for (MeetMeUser user : room.getUsers())
{
System.out.println(" " + user);
}
}
}
}

View File

@ -0,0 +1,42 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Oct 28, 2004
*/
package org.asteriskjava.live;
import org.asteriskjava.config.ConfigFile;
/**
* @author srt
* @version $Id: MiscTest.java 991 2008-03-08 10:10:34Z srt $
*/
public class MiscTest extends AsteriskServerTestCase
{
public void testGlobalVariables() throws Exception
{
server.setGlobalVariable("AJ_TEST_VAR", "foobar");
assertEquals("foobar", server.getGlobalVariable("AJ_TEST_VAR"));
}
public void testFunctions() throws Exception
{
System.err.println(server.getGlobalVariable("DB(/Agents,1301)"));
}
public void testGetVoicemailboxes() throws Exception
{
System.err.println("mailboxes: " + server.getVoicemailboxes());
}
public void testGetConfig() throws Exception
{
ConfigFile config;
config = server.getConfig("voicemail.conf");
assertEquals("voicemail.conf", config.getFilename());
System.err.println(config.getCategories());
}
}

View File

@ -0,0 +1,178 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Oct 28, 2004
*/
package org.asteriskjava.live;
/**
* @author srt
* @version $Id: OriginateCauseAsyncTest.java 938 2007-12-31 03:23:38Z srt $
*/
public class OriginateCauseAsyncTest extends AsteriskServerTestCase
{
private MyStatus status;
private MyOriginateCallback cb;
private Long timeout = 10000L;
@Override
public void setUp() throws Exception
{
super.setUp();
status = new MyStatus();
cb = new MyOriginateCallback();
}
public void testOriginateFailure() throws Exception
{
synchronized (status)
{
server.originateToExtensionAsync("Local/none@aj-test", "aj-test", "answer", 1, timeout, cb);
status.wait();
assertNotNull(status.failureException);
}
}
public void testOriginateSuccess() throws Exception
{
synchronized (status)
{
server.originateToExtensionAsync("Local/answer@aj-test", "aj-test", "answer", 1, timeout, cb);
status.wait();
status.print();
assertNotNull(status.dialingChannel);
assertNotNull(status.successChannel);
}
}
public void testOriginateBusy() throws Exception
{
synchronized (status)
{
server.originateToExtensionAsync("Local/busy@aj-test", "aj-test", "answer", 1, timeout, cb);
status.wait();
status.print();
assertNotNull(status.busyChannel);
}
}
public void testOriginateCongestion() throws Exception
{
synchronized (status)
{
server.originateToExtensionAsync("Local/congestion@aj-test", "aj-test", "answer", 1, timeout, cb);
status.wait();
status.print();
// congestion is treated like busy
assertNotNull(status.busyChannel);
}
}
public void testOriginateNoAnswer() throws Exception
{
synchronized (status)
{
server.originateToExtensionAsync("Local/noanswer@aj-test", "aj-test", "answer", 1, timeout, cb);
status.wait();
status.print();
assertNotNull(status.noAnswerChannel);
}
}
void showInfo(AsteriskChannel channel)
{
String name;
String otherName;
AsteriskChannel otherChannel;
System.err.println("linkedChannelHistory: " + channel.getLinkedChannelHistory());
System.err.println("dialedChannelHistory: " + channel.getDialedChannelHistory());
name = channel.getName();
if (name.startsWith("Local/"))
{
otherName = name.substring(0, name.length() - 1) + "2";
System.err.println("other name: " + otherName);
try
{
otherChannel = server.getChannelByName(otherName);
}
catch (ManagerCommunicationException e)
{
e.printStackTrace();
return;
}
System.err.println("other channel: " + otherChannel);
System.err.println("other dialedChannel: " + otherChannel.getDialedChannel());
System.err.println("other linkedChannelHistory: " + otherChannel.getLinkedChannelHistory());
System.err.println("other dialedChannelHistory: " + otherChannel.getDialedChannelHistory());
}
}
class MyOriginateCallback implements OriginateCallback
{
boolean sealed = false;
public void onDialing(AsteriskChannel channel)
{
status.dialingChannel = channel;
}
public void onFailure(LiveException cause)
{
status.failureException = cause;
doNotify();
}
public void onBusy(AsteriskChannel channel)
{
status.busyChannel = channel;
doNotify();
}
public void onNoAnswer(AsteriskChannel channel)
{
status.noAnswerChannel = channel;
doNotify();
}
public void onSuccess(AsteriskChannel channel)
{
status.successChannel = channel;
doNotify();
}
void doNotify()
{
if (sealed)
{
System.err.println("!!! Modifying sealed status !!!");
}
sealed = true;
synchronized (status)
{
status.notify();
}
}
}
class MyStatus
{
AsteriskChannel dialingChannel;
AsteriskChannel busyChannel;
AsteriskChannel noAnswerChannel;
AsteriskChannel successChannel;
LiveException failureException;
void print()
{
System.out.println("dialing = " + dialingChannel);
System.out.println("busy = " + busyChannel);
System.out.println("noAnswer = " + noAnswerChannel);
System.out.println("success = " + successChannel);
System.out.println("failure = " + failureException);
}
}
}

View File

@ -0,0 +1,173 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Oct 28, 2004
*/
package org.asteriskjava.live;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author srt
* @version $Id: OriginateCauseTest.java 938 2007-12-31 03:23:38Z srt $
*/
public class OriginateCauseTest extends AsteriskServerTestCase
{
private AsteriskChannel channel;
private Long timeout = 10000L;
@Override
public void setUp() throws Exception
{
super.setUp();
this.channel = null;
}
public void xtestOriginateInvalidSourceChannel() throws Exception
{
try
{
server.originateToExtension("Local/none@aj-test", "aj-test", "answer", 1, timeout);
fail("Originating from an invalid source channel must throw a NoSuchChannelException");
}
catch (NoSuchChannelException e)
{
// ok
}
}
public void testOriginate() throws Exception
{
AsteriskChannel channel;
channel = server.originateToExtension("Local/answer@aj-test", "aj-test-delayed", "answer", 1, timeout);
System.err.println(channel);
Thread.sleep(20000L);
System.err.println(channel);
}
public void xtestOriginateAsync() throws Exception
{
final String source;
//source = "SIP/1310";
source = "Local/1337@from-local";
// source = "Local/1310@from-local/n";
server.originateToExtensionAsync(source, "conference", "1399", 1, timeout, new CallerId("AJ Test Call",
"08003301000"), null, new OriginateCallback()
{
public void onDialing(final AsteriskChannel c)
{
channel = c;
System.err.println("Dialing: " + channel);
channel.addPropertyChangeListener(new PropertyChangeListener()
{
public void propertyChange(PropertyChangeEvent evt)
{
System.err.println("PropertyChange (" + ((AsteriskChannel) evt.getSource()).getName() + ") " + evt.getPropertyName() + ": " + evt.getOldValue() + " => " + evt.getNewValue());
}
});
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.schedule(new Runnable()
{
public void run()
{
System.out.println("Tata");
try
{
c.hangup();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, 10, TimeUnit.SECONDS);
}
public void onSuccess(AsteriskChannel c)
{
channel = c;
System.err.println("Success: " + c);
showInfo(c);
try
{
/*
c.setVariable(AsteriskChannel.VARIABLE_MONITOR_EXEC, "/usr/local/bin/2wav2mp3");
c.setVariable(AsteriskChannel.VARIABLE_MONITOR_EXEC_ARGS, "a b");
c.startMonitoring("mtest", "wav", true);
Thread.sleep(10000L);
c.stopMonitoring();
c.setAbsoluteTimeout(20);
*/
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void onNoAnswer(AsteriskChannel c)
{
channel = c;
System.err.println("No Answer: " + c);
showInfo(c);
}
public void onBusy(AsteriskChannel c)
{
channel = c;
System.err.println("Busy: " + c);
showInfo(c);
}
public void onFailure(LiveException cause)
{
System.err.println("Failed: " + cause.getMessage());
}
});
Thread.sleep(20000L);
System.err.println("final state: " + channel);
if (channel != null)
{
System.err.println("final state linked channels: " + channel.getLinkedChannelHistory());
}
}
void showInfo(AsteriskChannel channel)
{
String name;
String otherName;
AsteriskChannel otherChannel;
System.err.println("linkedChannelHistory: " + channel.getLinkedChannelHistory());
System.err.println("dialedChannelHistory: " + channel.getDialedChannelHistory());
name = channel.getName();
if (name.startsWith("Local/"))
{
otherName = name.substring(0, name.length() - 1) + "2";
System.err.println("other name: " + otherName);
try
{
otherChannel = server.getChannelByName(otherName);
}
catch (ManagerCommunicationException e)
{
e.printStackTrace();
return;
}
System.err.println("other channel: " + otherChannel);
System.err.println("other dialedChannel: " + otherChannel.getDialedChannel());
System.err.println("other linkedChannelHistory: " + otherChannel.getLinkedChannelHistory());
System.err.println("other dialedChannelHistory: " + otherChannel.getDialedChannelHistory());
}
}
}

View File

@ -0,0 +1,162 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Oct 28, 2004
*/
package org.asteriskjava.live;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author srt
* @version $Id: OriginateTest.java 1315 2009-06-02 22:36:54Z srt $
*/
public class OriginateTest extends AsteriskServerTestCase
{
private AsteriskChannel channel;
private Long timeout = 20000L;
@Override
public void setUp() throws Exception
{
super.setUp();
this.channel = null;
}
public void xtestOriginate() throws Exception
{
AsteriskChannel channel;
channel = server.originateToExtension("SIP/1310", "from-local", "1330", 1, timeout);
System.err.println(channel);
System.err.println(channel.getVariable("AJ_TRACE_ID"));
Thread.sleep(20000L);
System.err.println(channel);
System.err.println(channel.getVariable("AJ_TRACE_ID"));
}
public void testOriginateAsync() throws Exception
{
final String source;
//source = "SIP/1310";
source = "Local/1218@from-local";
// source = "Local/1310@from-local/n";
server.originateToExtensionAsync(source, "from-local", "1299", 1, timeout, new CallerId("AJ Test Call",
"08003301000"), null, new OriginateCallback()
{
public void onDialing(final AsteriskChannel c)
{
channel = c;
System.err.println("Dialing: " + channel);
channel.addPropertyChangeListener(new PropertyChangeListener()
{
public void propertyChange(PropertyChangeEvent evt)
{
System.err.println("PropertyChange (" + ((AsteriskChannel) evt.getSource()).getName() + ") " + evt.getPropertyName() + ": " + evt.getOldValue() + " => " + evt.getNewValue());
}
});
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.schedule(new Runnable()
{
public void run()
{
System.out.println("Tata");
try
{
System.out.println("Hanging up channel from onDial " + c);
c.hangup();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, 10, TimeUnit.SECONDS);
}
public void onSuccess(AsteriskChannel c)
{
channel = c;
System.err.println("Success: " + c);
showInfo(c);
try
{
/*
c.setVariable(AsteriskChannel.VARIABLE_MONITOR_EXEC, "/usr/local/bin/2wav2mp3");
c.setVariable(AsteriskChannel.VARIABLE_MONITOR_EXEC_ARGS, "a b");
c.startMonitoring("mtest", "wav", true);
Thread.sleep(10000L);
c.stopMonitoring();
c.setAbsoluteTimeout(20);
*/
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void onNoAnswer(AsteriskChannel c)
{
channel = c;
System.err.println("No Answer: " + c);
showInfo(c);
}
public void onBusy(AsteriskChannel c)
{
channel = c;
System.err.println("Busy: " + c);
showInfo(c);
}
public void onFailure(LiveException cause)
{
System.err.println("Failed: " + cause.getMessage());
}
});
Thread.sleep(20000L);
System.err.println("final state: " + channel);
if (channel != null)
{
System.err.println("final state linked channels: " + channel.getLinkedChannelHistory());
}
}
void showInfo(AsteriskChannel channel)
{
String name;
String otherName;
AsteriskChannel otherChannel;
System.err.println("linkedChannelHistory: " + channel.getLinkedChannelHistory());
System.err.println("dialedChannelHistory: " + channel.getDialedChannelHistory());
name = channel.getName();
if (name.startsWith("Local/"))
{
otherName = name.substring(0, name.length() - 1) + "2";
System.err.println("other name: " + otherName);
try
{
otherChannel = server.getChannelByName(otherName);
}
catch (ManagerCommunicationException e)
{
e.printStackTrace();
return;
}
System.err.println("other channel: " + otherChannel);
System.err.println("other dialedChannel: " + otherChannel.getDialedChannel());
System.err.println("other linkedChannelHistory: " + otherChannel.getLinkedChannelHistory());
System.err.println("other dialedChannelHistory: " + otherChannel.getDialedChannelHistory());
}
}
}

View File

@ -0,0 +1,31 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Oct 28, 2004
*/
package org.asteriskjava.live;
import org.asteriskjava.manager.action.OriginateAction;
/**
* @author srt
* @version $Id: SofthangupTest.java 1087 2008-08-08 19:22:24Z srt $
*/
public class SofthangupTest extends AsteriskServerTestCase
{
public void testSofthangup() throws Exception
{
OriginateAction originate;
originate = new OriginateAction();
originate.setChannel("Local/1310");
originate.setContext("default");
originate.setExten("1340");
originate.setPriority(1);
//ManagerResponse response = managerConnection.sendAction(originate);
//System.out.println("Response: " + response);
Thread.sleep(10000);
}
}

View File

@ -0,0 +1,87 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Oct 28, 2004
*/
package org.asteriskjava.live;
import java.util.Arrays;
import java.util.Collection;
/**
* @author srt
* @version $Id: TestDefaultAsteriskServer.java 1087 2008-08-08 19:22:24Z srt $
*/
public class TestDefaultAsteriskServer extends AsteriskServerTestCase
{
public void testGetChannels() throws Exception
{
System.out.println("waiting for channels...");
try
{
Thread.sleep(10000);
}
catch (InterruptedException e)
{
}
Collection<AsteriskChannel> channels = server.getChannels();
System.out.println("got channels. waiting to hangup...");
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
}
for (AsteriskChannel channel : channels)
{
if (!channel.getName().startsWith("SIP/1310"))
{
continue;
}
System.out.println(channel);
try
{
channel.redirectBothLegs("default", "1399", 1);
//channel.hangup();
}
catch (NoSuchChannelException e)
{
System.out.println(e.getMessage());
}
}
}
public void XtestGetQueues() throws Exception
{
System.out.println("waiting for queues...");
try
{
Thread.sleep(10000);
}
catch (InterruptedException e)
{
// swallow
}
Collection<AsteriskQueue> queues = server.getQueues();
for (AsteriskQueue queue : queues)
{
System.out.println(queue);
}
}
public void testGetVersion() throws Exception
{
System.out.println(Arrays.toString(server.getVersion("cdr_manager.c")));
System.out.println(server.getVersion());
}
}

View File

@ -0,0 +1,42 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Oct 28, 2004
*/
package org.asteriskjava.live;
import java.util.Collection;
/**
* @author srt
* @version $Id: TestExtensionHistory.java 938 2007-12-31 03:23:38Z srt $
*/
public class TestExtensionHistory extends AsteriskServerTestCase
{
public void testGetHistory() throws Exception
{
Collection<AsteriskChannel> channels;
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
}
channels = server.getChannels();
System.out.println("# of active channels: " + channels.size());
for (AsteriskChannel channel : channels)
{
System.out.println(channel);
System.out.println(" first extension: " + channel.getFirstExtension());
System.out.println(" current extension: " + channel.getCurrentExtension());
for (ExtensionHistoryEntry extensionHistoryEntry : channel.getExtensionHistory())
{
System.out.println(" " + extensionHistoryEntry);
}
}
}
}

View File

@ -0,0 +1,22 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Oct 28, 2004
*/
package org.asteriskjava.live;
/**
* @author srt
* @version $Id: TestLiveReconnect.java 938 2007-12-31 03:23:38Z srt $
*/
public class TestLiveReconnect extends AsteriskServerTestCase
{
public void testLiveReconnect() throws Exception
{
System.out.println("Please stop and restart the Asterisk server...");
while (true)
{
Thread.sleep(300000);
}
}
}

View File

@ -0,0 +1,19 @@
package org.asteriskjava.manager;
import junit.framework.TestCase;
public abstract class AbstractManagerTestCase extends TestCase
{
protected DefaultManagerConnection getDefaultManagerConnection()
{
DefaultManagerConnection dmc;
dmc = new DefaultManagerConnection();
dmc.setUsername("manager");
dmc.setPassword("obelisk");
dmc.setHostname("10.12.0.1");
dmc.setPort(5038);
return dmc;
}
}

View File

@ -0,0 +1,75 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Sep 24, 2004
*/
package org.asteriskjava.manager;
import org.asteriskjava.manager.action.CommandAction;
import org.asteriskjava.manager.action.StatusAction;
import org.asteriskjava.manager.action.VoicemailUsersListAction;
import org.asteriskjava.manager.action.AgiAction;
import org.asteriskjava.manager.event.ManagerEvent;
import org.asteriskjava.manager.event.AsyncAgiEvent;
import org.asteriskjava.manager.response.CommandResponse;
import org.asteriskjava.manager.response.ManagerResponse;
import junit.framework.TestCase;
import java.util.Iterator;
/**
* @author srt
* @version $Id: TestAsyncAgi.java 956 2008-02-02 14:08:11Z srt $
*/
public class TestAsyncAgi extends AbstractManagerTestCase
{
public void testDialplanShow() throws Exception
{
DefaultManagerConnection managerConnection;
managerConnection = getDefaultManagerConnection();
managerConnection.login();
CommandAction commandAction = new CommandAction("sip show peers");
ManagerResponse response = managerConnection.sendAction(commandAction);
if (response instanceof CommandResponse)
{
for (String item : ((CommandResponse) response).getResult())
{
System.out.println(item);
}
}
}
public void testAgiAction() throws Exception
{
DefaultManagerConnection dmc;
dmc = getDefaultManagerConnection();
dmc.addEventListener(new ManagerEventListener()
{
public void onManagerEvent(ManagerEvent event)
{
System.out.println("Got event: " + event);
if (event instanceof AsyncAgiEvent)
{
System.out.println("Decoded env: " + ((AsyncAgiEvent) event).decodeEnv());
}
}
});
dmc.login();
System.out.println("Dial 1296");
Thread.sleep(5000);
ManagerResponse response = dmc.sendAction(new AgiAction(
"IAX2/iax0-cgn_reucon_net-2",
"EXEC Playback tt-monkeysintro",
"myCommandId"));
System.out.println(response);
// wait to receive events
Thread.sleep(20000);
dmc.logoff();
Thread.sleep(3000);
}
}

View File

@ -0,0 +1,132 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Sep 24, 2004
*/
package org.asteriskjava.manager;
import java.util.concurrent.atomic.AtomicInteger;
import junit.framework.TestCase;
import org.asteriskjava.manager.action.StatusAction;
import org.asteriskjava.manager.event.ManagerEvent;
/**
* @author srt
* @version $Id: TestConcurrentUseOfDefaultManagerConnection.java 938 2007-12-31 03:23:38Z srt $
*/
public class TestConcurrentUseOfDefaultManagerConnection extends TestCase
{
private static final int NUM_THREADS = 400;
private static final int NUM_LOOPS = 200;
private DefaultManagerConnection dmc;
private AtomicInteger succeeded;
private AtomicInteger failed;
private AtomicInteger total;
@Override
protected void setUp() throws Exception
{
dmc = new DefaultManagerConnection();
dmc.setUsername("manager");
dmc.setPassword("obelisk");
dmc.setHostname("pbx0");
succeeded = new AtomicInteger(0);
failed = new AtomicInteger(0);
total = new AtomicInteger(0);
dmc.login();
}
@Override
protected void tearDown() throws Exception
{
dmc.logoff();
}
public void testConcurrency() throws Exception
{
Thread[] threads = new Thread[NUM_THREADS];
long start;
long end;
dmc.addEventListener(new ManagerEventListener()
{
public void onManagerEvent(ManagerEvent event)
{
//System.out.println("Got event: " + event);
}
});
dmc.setDefaultEventTimeout(20000);
dmc.setDefaultResponseTimeout(20000);
for (int i = 0; i < NUM_THREADS; i++)
{
threads[i] = new Thread(new Sender());
threads[i].setName("Sender-" + i);
}
start = System.currentTimeMillis();
for (int i = 0; i < NUM_THREADS; i++)
{
threads[i].start();
}
for (int i = 0; i < NUM_THREADS; i++)
{
threads[i].join();
}
end = System.currentTimeMillis();
Thread.sleep(1000);
System.out.println("succeeded: " + succeeded);
System.out.println("failed: " + failed);
System.out.println("total: " + total);
System.out.println("duration: " + (end - start));
assertEquals("failed actions", 0, failed.get());
}
private class Sender implements Runnable
{
public void run()
{
for (int i = 0; i < NUM_LOOPS; i++)
{
int id = total.getAndIncrement();
String actionId = "A_" + id;
try
{
/*
PingAction a = new PingAction();
a.setActionId(actionId);
dmc.sendAction(a);
succeeded.getAndIncrement();
*/
ResponseEvents responseEvents;
StatusAction a = new StatusAction();
a.setActionId(actionId);
responseEvents = dmc.sendEventGeneratingAction(a);
if (responseEvents.getEvents().size() == 2)
{
succeeded.getAndIncrement();
}
else
{
failed.getAndIncrement();
}
}
catch (Exception e)
{
failed.getAndIncrement();
System.err.println("Error for " + actionId);
e.printStackTrace();
}
}
}
}
}

View File

@ -0,0 +1,119 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Sep 24, 2004
*/
package org.asteriskjava.manager;
import org.asteriskjava.manager.action.CommandAction;
import org.asteriskjava.manager.action.StatusAction;
import org.asteriskjava.manager.action.SipShowPeerAction;
import org.asteriskjava.manager.event.ManagerEvent;
import org.asteriskjava.manager.response.CommandResponse;
import org.asteriskjava.manager.response.SipShowPeerResponse;
import junit.framework.TestCase;
/**
* @author srt
* @version $Id: TestDefaultManagerConnection.java 1242 2009-03-09 15:49:12Z srt $
*/
public class TestDefaultManagerConnection extends TestCase
{
private DefaultManagerConnection getDefaultManagerConnection()
{
DefaultManagerConnection dmc;
dmc = new DefaultManagerConnection();
dmc.setUsername("manager");
dmc.setPassword("obelisk");
dmc.setHostname("pbx0.reucon.net");
dmc.setPort(5038);
//dmc.setSsl(true);
return dmc;
}
public void XtestLogin() throws Exception
{
DefaultManagerConnection dmc;
dmc = getDefaultManagerConnection();
dmc.login();
dmc.addEventListener(new ManagerEventListener()
{
public void onManagerEvent(ManagerEvent event)
{
System.out.println("Got event: " + event);
}
});
dmc.sendAction(new StatusAction());
// wait for 3 seconds to receive events
Thread.sleep(3000);
dmc.logoff();
}
public void testMultipleLogins() throws Exception
{
DefaultManagerConnection dmc;
CommandResponse response;
dmc = getDefaultManagerConnection();
dmc.setDefaultResponseTimeout(5000);
for (int i = 0; i < 10; i++)
{
dmc.login();
response = (CommandResponse) dmc.sendAction(new CommandAction("show version"));
assertTrue("version does not start with \"Asterisk\"", response.getResult().get(0).startsWith("Asterisk"));
dmc.logoff();
}
}
public void testLoginAuthenticationFailure() throws Exception
{
DefaultManagerConnection dmc;
dmc = getDefaultManagerConnection();
dmc.setPassword("");
try
{
dmc.login();
dmc.logoff();
fail("No AuthenticationFailedException received.");
}
catch (AuthenticationFailedException e)
{
}
}
public void testCommandAction() throws Exception
{
DefaultManagerConnection dmc;
CommandResponse response;
dmc = getDefaultManagerConnection();
dmc.login();
response = (CommandResponse) dmc.sendAction(new CommandAction("show voicemail users"));
System.out.println("Got response: " + response.getResult());
dmc.logoff();
}
public void testSipShowPeerAction() throws Exception
{
DefaultManagerConnection dmc;
SipShowPeerResponse response;
dmc = getDefaultManagerConnection();
dmc.login();
response = (SipShowPeerResponse) dmc.sendAction(new SipShowPeerAction("phone-02"));
System.out.println("Got response: " + response);
dmc.logoff();
}
}

View File

@ -0,0 +1,40 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Sep 24, 2004
*/
package org.asteriskjava.manager;
import org.asteriskjava.manager.action.CommandAction;
import org.asteriskjava.manager.action.StatusAction;
import org.asteriskjava.manager.action.VoicemailUsersListAction;
import org.asteriskjava.manager.event.ManagerEvent;
import org.asteriskjava.manager.response.CommandResponse;
import junit.framework.TestCase;
/**
* @author srt
* @version $Id: TestVoicemailUsersListAction.java 947 2008-01-30 03:04:07Z srt $
*/
public class TestVoicemailUsersListAction extends AbstractManagerTestCase
{
public void testVoicemailUsersListAction() throws Exception
{
DefaultManagerConnection dmc;
dmc = getDefaultManagerConnection();
dmc.login();
ResponseEvents events = dmc.sendEventGeneratingAction(new VoicemailUsersListAction());
System.out.println(events.getResponse());
for (ManagerEvent event : events.getEvents())
{
System.out.println(event);
}
// wait for 3 seconds to receive events
Thread.sleep(3000);
dmc.logoff();
}
}

View File

@ -0,0 +1,52 @@
/*
* (c) 2004 Stefan Reuter
*
* Created on Sep 24, 2004
*/
package org.asteriskjava.manager;
import org.asteriskjava.manager.action.CommandAction;
import org.asteriskjava.manager.action.StatusAction;
import org.asteriskjava.manager.event.ManagerEvent;
import org.asteriskjava.manager.response.CommandResponse;
import junit.framework.TestCase;
/**
* @author srt
* @version $Id: TestVoid.java 981 2008-02-14 03:44:49Z srt $
*/
public class TestVoid extends TestCase
{
private DefaultManagerConnection getDefaultManagerConnection()
{
DefaultManagerConnection dmc;
dmc = new DefaultManagerConnection();
dmc.setUsername("manager");
dmc.setPassword("obelisk");
dmc.setHostname("pbx0.cologne.reucon.net");
dmc.setPort(5038);
return dmc;
}
public void testPrintEvents() throws Exception
{
DefaultManagerConnection dmc;
dmc = getDefaultManagerConnection();
dmc.login();
dmc.addEventListener(new ManagerEventListener()
{
public void onManagerEvent(ManagerEvent event)
{
System.out.println("Got event: " + event);
}
});
// dmc.sendAction(new StatusAction());
Thread.sleep(30000);
dmc.logoff();
}
}

View File

@ -0,0 +1,28 @@
<assembly xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/assembly-1.1.0-SNAPSHOT.xsd">
<id>bin</id>
<formats>
<format>zip</format>
</formats>
<baseDirectory>${artifactId}-${version}</baseDirectory>
<fileSets>
<fileSet>
<includes>
<include>README*</include>
<include>LICENSE*</include>
<include>NOTICE*</include>
</includes>
</fileSet>
<fileSet>
<directory>dist</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
<fileSet>
<directory>target</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@ -0,0 +1,128 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava;
import java.io.Serializable;
/**
* Represents the version of an Asterisk server.
*
* @author srt
* @version $Id: AsteriskVersion.java 1087 2008-08-08 19:22:24Z srt $
* @since 0.2
*/
public class AsteriskVersion implements Comparable<AsteriskVersion>, Serializable
{
private final int version;
private final String versionString;
/**
* Represents the Asterisk 1.0 series.
*/
public static final AsteriskVersion ASTERISK_1_0 = new AsteriskVersion(100, "Asterisk 1.0");
/**
* Represents the Asterisk 1.2 series.
*/
public static final AsteriskVersion ASTERISK_1_2 = new AsteriskVersion(120, "Asterisk 1.2");
/**
* Represents the Asterisk 1.4 series.
*
* @since 0.3
*/
public static final AsteriskVersion ASTERISK_1_4 = new AsteriskVersion(140, "Asterisk 1.4");
/**
* Represents the Asterisk 1.6 series.
*
* @since 1.0.0
*/
public static final AsteriskVersion ASTERISK_1_6 = new AsteriskVersion(160, "Asterisk 1.6");
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 1L;
private AsteriskVersion(int version, String versionString)
{
this.version = version;
this.versionString = versionString;
}
/**
* Returns <code>true</code> if this version is equal to or higher than
* the given version.
*
* @param o the version to compare to
* @return <code>true</code> if this version is equal to or higher than
* the given version, <code>false</code> otherwise.
*/
public boolean isAtLeast(AsteriskVersion o)
{
return version >= o.version;
}
public int compareTo(AsteriskVersion o)
{
int otherVersion;
otherVersion = o.version;
if (version < otherVersion)
{
return -1;
}
else if (version > otherVersion)
{
return 1;
}
else
{
return 0;
}
}
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
AsteriskVersion that = (AsteriskVersion) o;
return version == that.version;
}
@Override
public int hashCode()
{
return version;
}
@Override
public String toString()
{
return versionString;
}
}

View File

@ -0,0 +1,135 @@
package org.asteriskjava;
import org.asteriskjava.fastagi.DefaultAgiServer;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* Simple command line interface for Asterisk-Java. This class is run when Asterisk-Java is started
* with {@code java -jar asterisk-java.jar}. It is configured as Main-Class in the manifest.<p>
* The command line interface supports the following options:
* <dl>
* <dt>{@code -a}, {@code -agi [port]}<dt>
* <dd>Starts a FastAGI server</dd>
*
* <dt>{@code -h}, {@code -help}<dt>
* <dd>Displays the available options</dd>
*
* <dt>{@code -v}, {@code -version}</dt>
* <dd>Displays the version of Asterisk-Java</dd>
* </dl>
* If no option is given a FastAGI server is started on the default port.
*
* @since 1.0.0
*/
public class Cli
{
private void parseOptions(String[] args) throws Exception
{
if (args.length == 0)
{
startAgiServer();
return;
}
final String arg = args[0];
if ("-h".equals(arg) || "-help".equals(arg))
{
showHelp();
}
else if ("-v".equals(arg) || "-version".equals(arg))
{
showVersion();
}
else if ("-a".equals(arg) || "-agi".equals(arg))
{
if (args.length >= 2)
{
Integer port = null;
try
{
port = new Integer(args[1]);
}
catch (NumberFormatException e)
{
System.err.println("Invalid port '" + args[1] + "'. Port must be a number.");
exit(1);
}
startAgiServer(port);
}
}
else
{
showHelp();
}
}
private void showHelp()
{
showVersion();
System.err.println();
System.err.println("-a, -agi [port]\n\tStarts a FastAGI server");
System.err.println("-h, -help\n\tDisplays the available options\n");
System.err.println("-v, -version\n\tDisplays the version of Asterisk-Java\n");
}
private void showVersion()
{
System.out.println("Asterisk-Java " + getVersion());
}
private String getVersion()
{
String version = "<unknown>";
final InputStream is;
final Properties properties;
is = getClass().getResourceAsStream("/META-INF/maven/org.asteriskjava/asterisk-java/pom.properties");
if (is == null)
{
return version;
}
properties = new Properties();
try
{
properties.load(is); // contains version, groupId and artifactId
}
catch (IOException e)
{
return version;
}
version = properties.getProperty("version", version);
return version;
}
private void startAgiServer() throws IOException
{
startAgiServer(null);
}
private void startAgiServer(Integer port) throws IOException
{
final DefaultAgiServer server;
server = new DefaultAgiServer();
if (port != null)
{
server.setPort(port);
}
server.startup();
}
private void exit(int code)
{
System.exit(code);
}
public static void main(String[] args) throws Exception
{
new Cli().parseOptions(args);
}
}

View File

@ -0,0 +1,140 @@
package org.asteriskjava.config;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
/**
*
*/
public class Category extends ConfigElement
{
private String name;
private boolean template;
private final List<Category> baseCategories = new ArrayList<Category>();
private final List<ConfigElement> elements = new ArrayList<ConfigElement>();
/**
* The last object in the list will get assigned any trailing comments when EOF is hit.
*/
//private String trailingComment;
public Category(String name)
{
if (name == null)
{
throw new IllegalArgumentException("Name must not be null");
}
this.name = name;
}
public Category(String filename, int lineno, String name)
{
super(filename, lineno);
this.name = name;
}
/**
* Returns the name of this category.
*
* @return the name of this category.
*/
public String getName()
{
return name;
}
/**
* Checks if this category is a template.
*
* @return <code>true</code> if this category is a template, <code>false</code> otherwise.
*/
public boolean isTemplate()
{
return template;
}
void markAsTemplate()
{
template = true;
}
/**
* Returns a list of categories this category inherits from.
*
* @return a list of categories this category inherits from, never <code>null</code>.
*/
public List<Category> getBaseCategories()
{
return baseCategories;
}
void addBaseCategory(Category baseCategory)
{
baseCategories.add(baseCategory);
}
public List<ConfigElement> getElements()
{
return elements;
}
public void addElement(ConfigElement element)
{
if (element instanceof Category)
{
throw new IllegalArgumentException("Nested categories are not allowed");
}
elements.add(element);
}
public String format()
{
StringBuilder sb = new StringBuilder();
format(sb);
for (ConfigElement e : elements)
{
sb.append("\n");
e.format(sb);
}
return sb.toString();
}
@Override
protected StringBuilder rawFormat(StringBuilder sb)
{
sb.append("[").append(name).append("]");
if (isTemplate() || !getBaseCategories().isEmpty())
{
sb.append("(");
if (isTemplate())
{
sb.append("!");
if (!getBaseCategories().isEmpty())
{
sb.append(",");
}
}
Iterator<Category> inheritsFromIterator = getBaseCategories().iterator();
while (inheritsFromIterator.hasNext())
{
sb.append(inheritsFromIterator.next().getName());
if (inheritsFromIterator.hasNext())
{
sb.append(",");
}
}
sb.append(")");
}
return sb;
}
@Override
public String toString()
{
return name;
}
}

View File

@ -0,0 +1,13 @@
package org.asteriskjava.config;
public abstract class ConfigDirective extends ConfigElement
{
protected ConfigDirective()
{
}
protected ConfigDirective(String filename, int lineno)
{
super(filename, lineno);
}
}

View File

@ -0,0 +1,85 @@
package org.asteriskjava.config;
public abstract class ConfigElement
{
/**
* Name of the file the category was read from.
*/
private String filename;
/**
* Line number.
*/
private int lineno;
private String preComment;
private String samelineComment;
protected ConfigElement()
{
}
protected ConfigElement(String filename, int lineno)
{
this.filename = filename;
this.lineno = lineno;
}
public String getFileName()
{
return filename;
}
public void setFileName(String filename)
{
this.filename = filename;
}
public int getLineNumber()
{
return lineno;
}
void setLineNumber(int lineno)
{
this.lineno = lineno;
}
public String getPreComment()
{
return preComment;
}
public void setPreComment(String preComment)
{
this.preComment = preComment;
}
public String getComment()
{
return samelineComment;
}
public void setComment(String samelineComment)
{
this.samelineComment = samelineComment;
}
protected StringBuilder format(StringBuilder sb)
{
if (preComment != null && preComment.length() != 0)
{
sb.append(preComment);
}
rawFormat(sb);
if (samelineComment != null && samelineComment.length() != 0)
{
sb.append(" ; ").append(samelineComment);
}
return sb;
}
protected abstract StringBuilder rawFormat(StringBuilder sb);
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.config;
import java.util.Map;
import java.util.List;
/**
* An Asterisk configuration file.
*
* @author srt
* @version $Id: ConfigFile.java 992 2008-03-08 23:31:13Z srt $
* @since 1.0.0
*/
public interface ConfigFile
{
/**
* Returns the filename.
*
* @return the filename, for example "voicemail.conf".
*/
String getFilename();
/**
* Returns the lines per category.
*
* @return the lines per category.
*/
Map<String, List<String>> getCategories();
String getValue(String category, String key);
List<String> getValues(String category, String key);
}

View File

@ -0,0 +1,134 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.config;
import java.util.Map;
import java.util.List;
import java.util.TreeMap;
import java.util.ArrayList;
/**
* An Asterisk configuration file read from the filesystem.
*
* @author srt
* @version $Id: ConfigFileImpl.java 1044 2008-05-05 23:45:09Z msmith $
* @since 1.0.0
*/
public class ConfigFileImpl implements ConfigFile
{
private final String filename;
protected final Map<String, Category> categories;
public ConfigFileImpl(String filename, Map<String, Category> categories)
{
this.filename = filename;
this.categories = categories;
}
public String getFilename()
{
return filename;
}
public Map<String, List<String>> getCategories()
{
final Map<String, List<String>> c;
c = new TreeMap<String, List<String>>();
synchronized (categories)
{
for (Category category : categories.values())
{
List<String> lines;
lines = new ArrayList<String>();
for (ConfigElement element : category.getElements())
{
if (element instanceof ConfigVariable)
{
ConfigVariable cv = (ConfigVariable) element;
lines.add(cv.getName() + "=" + cv.getValue());
}
}
c.put(category.getName(), lines);
}
}
return c;
}
public String getValue(String categoryName, String key)
{
final Category category;
category = getCategory(categoryName);
if (category == null)
{
return null;
}
for (ConfigElement element : category.getElements())
{
if (element instanceof ConfigVariable)
{
ConfigVariable cv = (ConfigVariable) element;
if (cv.getName().equals(key))
{
return cv.getValue();
}
}
}
return null;
}
public List<String> getValues(String categoryName, String key)
{
final Category category;
final List<String> result;
category = getCategory(categoryName);
result = new ArrayList<String>();
if (category == null)
{
return result;
}
for (ConfigElement element : category.getElements())
{
if (element instanceof ConfigVariable)
{
ConfigVariable cv = (ConfigVariable) element;
if (cv.getName().equals(key))
{
result.add(cv.getValue());
}
}
}
return result;
}
protected Category getCategory(String name)
{
synchronized (categories)
{
return categories.get(name);
}
}
}

View File

@ -0,0 +1,492 @@
package org.asteriskjava.config;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.*;
/**
* Reads and parses Asterisk configuration files.
* <p/>
* See Asterisk's <code>main/config.c</code>.
* <p/>
* Client code is not supposed to use this class.
*
* @author srt
* @version $Id: ConfigFileReader.java 1140 2008-08-18 18:49:36Z srt $
*/
public class ConfigFileReader
{
private static final int MAX_LINE_LENGTH = 8192;
private static char COMMENT_META = ';';
private static char COMMENT_TAG = '-';
private static final Set<Class> WARNING_CLASSES;
static
{
WARNING_CLASSES = new HashSet<Class>();
WARNING_CLASSES.add(MissingEqualSignException.class);
WARNING_CLASSES.add(UnknownDirectiveException.class);
WARNING_CLASSES.add(MissingDirectiveParameterException.class);
}
private StringBuilder commentBlock;
protected final Map<String, Category> categories;
private final List<ConfigParseException> warnings;
protected Category currentCategory;
private int currentCommentLevel = 0;
public ConfigFileReader()
{
this.commentBlock = new StringBuilder();
this.categories = new LinkedHashMap<String, Category>();
this.warnings = new ArrayList<ConfigParseException>();
}
public ConfigFile readFile(String configfile) throws IOException, ConfigParseException
{
final ConfigFile result;
final BufferedReader reader;
reader = new BufferedReader(new FileReader(configfile));
try
{
readFile(configfile, reader);
}
finally
{
try
{
reader.close();
}
catch (Exception e) // NOPMD
{
// ignore
}
}
result = new ConfigFileImpl(configfile, new TreeMap<String, Category>(categories));
return result;
}
void reset()
{
commentBlock = new StringBuilder();
categories.clear();
warnings.clear();
currentCategory = null;
currentCommentLevel = 0;
}
Collection<Category> getCategories()
{
return categories.values();
}
public Collection<ConfigParseException> getWarnings()
{
return new ArrayList<ConfigParseException>(warnings);
}
void readFile(String configfile, BufferedReader reader) throws IOException, ConfigParseException
{
String line;
int lineno = 0;
CharBuffer buffer = CharBuffer.allocate(MAX_LINE_LENGTH);
reset();
while ((line = reader.readLine()) != null)
{
lineno++;
buffer.clear();
buffer.put(line);
buffer.put("\n");
buffer.flip();
processLine(configfile, lineno, buffer);
}
}
ConfigElement processLine(String configfile, int lineno, CharBuffer buffer) throws ConfigParseException
{
char c;
final StringBuilder processLineBuilder;
final StringBuilder lineCommentBuilder;
processLineBuilder = new StringBuilder(MAX_LINE_LENGTH);
lineCommentBuilder = new StringBuilder(MAX_LINE_LENGTH);
buffer.mark();
while (buffer.hasRemaining())
{
final int position;
position = buffer.position();
c = buffer.get();
//System.out.println(position + ": " + c);
if (c == COMMENT_META)
{
if (position >= 1 && buffer.get(position - 1) == '\\')
{
/* Escaped semicolons aren't comments. */
} // NOPMD
else if (buffer.remaining() >= 3
&& buffer.get(position + 1) == COMMENT_TAG
&& buffer.get(position + 2) == COMMENT_TAG
&& buffer.get(position + 3) != COMMENT_TAG)
{
/* Meta-Comment start detected ";--" */
currentCommentLevel++;
//System.out.println("Comment start, new level: " + currentCommentLevel);
if (!inComment())
{
commentBlock.append(";--");
buffer.position(position + 3);
buffer.mark();
continue;
}
}
else if (inComment()
&& position >= 2
&& buffer.get(position - 1) == COMMENT_TAG
&& buffer.get(position - 2) == COMMENT_TAG)
{
/* Meta-Comment end detected */
currentCommentLevel--;
if (!inComment())
{
buffer.reset();
//int commentLength = (position + 1) - buffer.position();
//buffer.reset();
//for (int i = 0; i < commentLength; i++)
//{
// commentBlock.append(buffer.get());
//}
commentBlock.append(c);
//System.out.println("Comment end at " + position + ": '" + commentBlock.toString() + "'");
buffer.position(position + 1);
buffer.compact();
buffer.flip();
//System.out.println("Buffer compacted");
continue;
}
}
else
{
if (!inComment())
{
/* If ; is found, and we are not nested in a comment, we immediately stop all comment processing */
//System.out.println("Found ; while not in comment");
while (buffer.hasRemaining())
{
lineCommentBuilder.append(buffer.get());
}
break;
}
else
{
/* Found ';' while in comment */
} // NOPMD
}
}
if (inComment())
{
commentBlock.append(c);
}
else
{
//System.out.println("Added '" + c + "' to processLine");
processLineBuilder.append(c);
}
}
String processLineString;
String lineCommentString;
ConfigElement configElement;
processLineString = processLineBuilder.toString().trim();
lineCommentString = lineCommentBuilder.toString().trim();
//System.out.println("process line: '" + processLineString + "'");
if (processLineString.length() == 0)
{
if (lineCommentString.length() != 0)
{
commentBlock.append(";");
commentBlock.append(lineCommentString);
}
if (!inComment())
{
commentBlock.append("\n");
}
return null;
}
try
{
configElement = processTextLine(configfile, lineno, processLineString);
}
catch (ConfigParseException e)
{
// some parsing exceptions are treated as warnings by Asterisk, we mirror this behavior.
if (WARNING_CLASSES.contains(e.getClass()))
{
warnings.add(e);
return null;
}
else
{
throw e;
}
}
if (lineCommentString.length() != 0)
{
configElement.setComment(lineCommentString);
}
if (commentBlock.length() != 0)
{
configElement.setPreComment(commentBlock.toString());
commentBlock.delete(0, commentBlock.length());
}
return configElement;
}
boolean inComment()
{
return currentCommentLevel != 0;
}
protected ConfigElement processTextLine(String configfile, int lineno, String line) throws ConfigParseException
{
ConfigElement configElement;
if (line.charAt(0) == '[') // A category header
{
configElement = parseCategoryHeader(configfile, lineno, line);
}
else if (line.charAt(0) == '#') // a directive - #include or #exec
{
configElement = parseDirective(configfile, lineno, line);
}
else // just a line
{
if (currentCategory == null)
{
throw new ConfigParseException(configfile, lineno,
"parse error: No category context for line %d of %s", lineno, configfile);
}
configElement = parseVariable(configfile, lineno, line);
currentCategory.addElement(configElement);
}
return configElement;
}
protected Category parseCategoryHeader(String configfile, int lineno, String line) throws ConfigParseException
{
final Category category;
final String name;
final int nameEndPos;
/* format is one of the following:
* [foo] define a new category named 'foo'
* [foo](!) define a new template category named 'foo'
* [foo](+) append to category 'foo', error if foo does not exist.
* [foo](a) define a new category and inherit from template a.
* You can put a comma-separated list of templates and '!' and '+'
* between parentheses, with obvious meaning.
*/
nameEndPos = line.indexOf(']');
if (nameEndPos == -1)
{
throw new ConfigParseException(configfile, lineno,
"parse error: no closing ']', line %d of %s", lineno, configfile);
}
name = line.substring(1, nameEndPos);
category = new Category(configfile, lineno, name);
/* Handle options or categories to inherit from if available */
if (line.length() > nameEndPos + 1 && line.charAt(nameEndPos + 1) == '(')
{
final String[] options;
final String optionsString;
final int optionsEndPos;
optionsString = line.substring(nameEndPos + 1);
optionsEndPos = optionsString.indexOf(')');
if (optionsEndPos == -1)
{
throw new ConfigParseException(configfile, lineno,
"parse error: no closing ')', line %d of %s", lineno, configfile);
}
options = optionsString.substring(1, optionsEndPos).split(",");
for (String cur : options)
{
if ("!".equals(cur)) // category template
{
category.markAsTemplate();
}
else if ("+".equals(cur)) // category addition
{
final Category categoryToAddTo;
categoryToAddTo = categories.get(name);
if (categoryToAddTo == null)
{
throw new ConfigParseException(configfile, lineno,
"Category addition requested, but category '%s' does not exist, line %d of %s",
name, lineno, configfile);
}
//todo implement category addition
//category = categoryToAddTo;
}
else
{
final Category baseCategory;
baseCategory = categories.get(cur);
if (baseCategory == null)
{
throw new ConfigParseException(configfile, lineno,
"Inheritance requested, but category '%s' does not exist, line %d of %s",
cur, lineno, configfile);
}
inheritCategory(category, baseCategory);
}
}
}
appendCategory(category);
return category;
}
ConfigDirective parseDirective(String configfile, int lineno, String line) throws ConfigParseException
{
ConfigDirective directive;
final StringBuilder nameBuilder;
final StringBuilder paramBuilder;
String name = null;
String param;
nameBuilder = new StringBuilder();
paramBuilder = new StringBuilder();
for (int i = 1; i < line.length(); i++)
{
final char c;
c = line.charAt(i);
if (name == null)
{
nameBuilder.append(c);
if (Character.isWhitespace(c) || i + 1 == line.length())
{
name = nameBuilder.toString().trim();
}
}
else
{
paramBuilder.append(c);
}
}
param = paramBuilder.toString().trim();
if (param.length() != 0 &&
(param.charAt(0) == '"' || param.charAt(0) == '<' || param.charAt(0) == '>'))
{
param = param.substring(1);
}
int endPos = param.length() - 1;
if (param.length() != 0 &&
(param.charAt(endPos) == '"' || param.charAt(endPos) == '<' || param.charAt(endPos) == '>'))
{
param = param.substring(0, endPos);
}
if ("exec".equalsIgnoreCase(name))
{
directive = new ExecDirective(configfile, lineno, param);
}
else if ("include".equalsIgnoreCase(name))
{
directive = new IncludeDirective(configfile, lineno, param);
}
else
{
throw new UnknownDirectiveException(configfile, lineno,
"Unknown directive '%s' at line %d of %s", name, lineno, configfile);
}
if (param.length() == 0)
{
throw new MissingDirectiveParameterException(configfile, lineno,
"Directive '#%s' needs an argument (%s) at line %d of %s",
name.toLowerCase(Locale.US),
"include".equalsIgnoreCase(name) ? "filename" : "/path/to/executable",
lineno,
configfile);
}
return directive;
}
protected ConfigVariable parseVariable(String configfile, int lineno, String line) throws ConfigParseException
{
int pos;
String name;
String value;
pos = line.indexOf('=');
if (pos == -1)
{
throw new MissingEqualSignException(configfile, lineno,
"No '=' (equal sign) in line %d of %s", lineno, configfile);
}
name = line.substring(0, pos).trim();
// Ignore > in =>
if (line.length() > pos + 1 && line.charAt(pos + 1) == '>')
{
pos++;
}
value = (line.length() > pos + 1) ? line.substring(pos + 1).trim() : "";
return new ConfigVariable(configfile, lineno, name, value);
}
void inheritCategory(Category category, Category baseCategory)
{
category.addBaseCategory(baseCategory);
}
void appendCategory(Category category)
{
categories.put(category.getName(), category);
currentCategory = category;
}
}

View File

@ -0,0 +1,35 @@
package org.asteriskjava.config;
/**
*
*/
public class ConfigParseException extends Exception
{
private static final long serialVersionUID = 4346366210261425734L;
private String filename;
private int lineno;
public ConfigParseException(String filename, int lineno, String message)
{
super(message);
this.filename = filename;
this.lineno = lineno;
}
public ConfigParseException(String filename, int lineno, String format, Object... params)
{
super(String.format(format, params));
this.filename = filename;
this.lineno = lineno;
}
public String getFileName()
{
return filename;
}
public int getLineNumber()
{
return lineno;
}
}

View File

@ -0,0 +1,64 @@
package org.asteriskjava.config;
/**
*
*/
public class ConfigVariable extends ConfigElement
{
private String name;
private String value;
public ConfigVariable(String name, String value)
{
setName(name);
setValue(value);
}
public ConfigVariable(String filename, int lineno, String name, String value)
{
super(filename, lineno);
setName(name);
setValue(value);
}
public String getName()
{
return name;
}
public void setName(String name)
{
if (name == null)
{
throw new IllegalArgumentException("Variable name must not be null");
}
this.name = name;
}
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
@Override
protected StringBuilder rawFormat(StringBuilder sb)
{
sb.append(name).append(" = ");
if (value != null)
{
sb.append(value);
}
return sb;
}
@Override
public String toString()
{
return name+"="+value;
}
}

View File

@ -0,0 +1,33 @@
package org.asteriskjava.config;
public class ExecDirective extends ConfigDirective
{
/**
* file name of the executable.
*/
private final String execFile;
public ExecDirective(String execFile)
{
super();
this.execFile = execFile;
}
public ExecDirective(String filename, int lineno, String execFile)
{
super(filename, lineno);
this.execFile = execFile;
}
public String getExecFile()
{
return execFile;
}
@Override
protected StringBuilder rawFormat(StringBuilder sb)
{
sb.append("#exec \"").append(execFile).append("\"");
return sb;
}
}

View File

@ -0,0 +1,33 @@
package org.asteriskjava.config;
public class IncludeDirective extends ConfigDirective
{
/**
* file name included.
*/
private final String includeFile;
public IncludeDirective(String includeFile)
{
super();
this.includeFile = includeFile;
}
public IncludeDirective(String filename, int lineno, String includeFile)
{
super(filename, lineno);
this.includeFile = includeFile;
}
public String getIncludeFile()
{
return includeFile;
}
@Override
protected StringBuilder rawFormat(StringBuilder sb)
{
sb.append("#include \"").append(includeFile).append("\"");
return sb;
}
}

View File

@ -0,0 +1,14 @@
package org.asteriskjava.config;
/**
* A required parameter to a directive is missing.<p>
* The #include and #exec directives require a parameter (include file or command to execute).
*/
public class MissingDirectiveParameterException extends ConfigParseException
{
private static final long serialVersionUID = -3802754628756681515L;
public MissingDirectiveParameterException(String filename, int lineno, String format, Object... params)
{
super(filename, lineno, format, params);
}
}

View File

@ -0,0 +1,14 @@
package org.asteriskjava.config;
/**
* The equal sign on a variable assignment line is missing.<p>
* A variable line must include an equal sign.
*/
public class MissingEqualSignException extends ConfigParseException
{
private static final long serialVersionUID = 2694490330074765342L;
public MissingEqualSignException(String filename, int lineno, String format, Object... params)
{
super(filename, lineno, format, params);
}
}

View File

@ -0,0 +1,14 @@
package org.asteriskjava.config;
/**
* An unknown directive has been encountered.<p>
* Asterisk only supports #include and #exec directives.
*/
public class UnknownDirectiveException extends ConfigParseException
{
private static final long serialVersionUID = 4356355066633810196L;
public UnknownDirectiveException(String filename, int lineno, String format, Object... params)
{
super(filename, lineno, format, params);
}
}

View File

@ -0,0 +1,58 @@
package org.asteriskjava.config.dialplan;
import java.util.Arrays;
import org.asteriskjava.config.ConfigElement;
/**
* Represents the dial plan extension as a specific kind of configuration
* directive This class makes no interpretation of syntax checking of names,
* priorities, or application (for now).
*
* @author martins
*/
public class ConfigExtension extends ConfigElement
{
String name, priority;
/**
* Holds the application in the first element, and arguments in all subsequent elements. Similar to command line arguments array.
*/
String [] application;
public ConfigExtension(String filename, int lineno, String name, String priority, String [] application)
{
super(filename,lineno);
this.name = name;
this.priority = priority;
this.application = application;
}
@Override
protected StringBuilder rawFormat(StringBuilder sb)
{
return sb.append(toString());
}
@Override
public String toString()
{
return "exten => " + name + "," + priority + "," + Arrays.asList(application);
}
public String getName()
{
return name;
}
public String getPriority()
{
return priority;
}
public String[] getApplication()
{
return application;
}
}

View File

@ -0,0 +1,32 @@
package org.asteriskjava.config.dialplan;
import org.asteriskjava.config.ConfigElement;
public class ConfigInclude extends ConfigElement
{
String category;
public ConfigInclude(String filename, int lineno, String category)
{
super(filename, lineno);
this.category = category;
}
@Override
protected StringBuilder rawFormat(StringBuilder sb)
{
return sb.append(toString());
}
@Override
public String toString()
{
return "include => " + category;
}
public String getName()
{
return category;
}
}

View File

@ -0,0 +1,20 @@
package org.asteriskjava.config.dialplan;
import java.util.Collection;
import java.util.Map;
import org.asteriskjava.config.Category;
import org.asteriskjava.config.ConfigFileImpl;
public class ExtensionsConfigFile extends ConfigFileImpl
{
public ExtensionsConfigFile(String filename, Map<String, Category> categories)
{
super(filename, categories);
}
public Collection<Category> getContexts()
{
return categories.values();
}
}

View File

@ -0,0 +1,187 @@
package org.asteriskjava.config.dialplan;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.asteriskjava.config.ConfigElement;
import org.asteriskjava.config.ConfigFileReader;
import org.asteriskjava.config.ConfigParseException;
import org.asteriskjava.config.ConfigVariable;
/*
* Interprets extensions.conf as a special kind of config file, the dialplan.
* - Line numbers correspond with pbx_config.c, tags/1.4.19 revision 96024
*/
public class ExtensionsConfigFileReader extends ConfigFileReader
{
/*
* This method corresponds to an iteration of the loop at line 2212 Notes:
* 1. [general] and [globals] are allowed to be a context here if they contain only configvariables
* 2. switch and ignorepat are treated like regular ConfigVariable.
*/
@Override
protected ConfigElement processTextLine(String configfile, int lineno, String line) throws ConfigParseException
{
ConfigElement configElement;
if(
(line.trim().startsWith("exten") || line.trim().startsWith("include")) &&
currentCategory != null &&
(currentCategory.getName().equals("general") || currentCategory.getName().equals("globals"))
)
throw new ConfigParseException(configfile, lineno, "cannot have 'exten' or 'include' in global or general sections");
/*
* Goal here is to break out anything unique that we might want to
* look at and parse separately. For now, only exten and include fit
* that criteria. Eventually, I could see parsing sections for things
* from macros, contexts to differentiate them from categories, switch
* for realtime, and more.
*/
if (line.trim().startsWith("exten"))
{
configElement = parseExtension(configfile, lineno, line);
currentCategory.addElement(configElement);
return configElement;
}
else if(line.trim().startsWith("include"))
{
// use parseVariable since we have access to it
ConfigVariable configvar = parseVariable(configfile, lineno, line);
configElement = new ConfigInclude(configfile, lineno, configvar.getValue());
currentCategory.addElement(configElement);
return configElement;
}
// leave everything else the same
configElement = super.processTextLine(configfile, lineno, line);
return configElement;
}
/* Roughly corresponds to pbx_config.c:2222 */
protected ConfigExtension parseExtension(String configfile, int lineno, String line) throws ConfigParseException
{
ConfigVariable initialVariable = parseVariable(configfile, lineno, line);
if(!initialVariable.getName().equals("exten"))
throw new ConfigParseException(configfile, lineno, "missing 'exten' near " + line);
line = initialVariable.getValue().trim();
int nameIndex = line.indexOf(",", 0);
if(nameIndex == -1)
throw new ConfigParseException(configfile, lineno, "missing extension name near " + line);
String name = line.substring(0, nameIndex);
line = line.substring(name.length()+1, line.length()).trim();
int priorityDelimiter = line.indexOf(",", 0);
if(priorityDelimiter == -1)
throw new ConfigParseException(configfile, lineno, "missing extension priority near " + line);
String priority = line.substring(0, priorityDelimiter);
line = line.substring(priority.length()+1, line.length()).trim();
String [] application = harvestApplicationWithArguments(line);
return new ConfigExtension(configfile,lineno,name,priority,application);
}
/* Roughly corresponds to pbx_config.c:2276 */
private static String [] harvestApplicationWithArguments(String arg)
{
List<String> args = new ArrayList<String>();
if(args != null && arg.trim().length() >= 0)
{
String appl = "", data = "";
/* Find the first occurrence of either '(' or ',' */
int firstc = arg.indexOf(',');
int firstp = arg.indexOf('(');
if (firstc != -1 && (firstp == -1 || firstc < firstp)) {
/* comma found, no parenthesis */
/* or both found, but comma found first */
String [] split = arg.split(",");
appl = split[0];
for(int i = 1; i < split.length; i++)
data += split[i] + (i+1<split.length?",":"");
} else if (firstc == -1 && firstp == -1) {
/* Neither found */
data = "";
} else {
/* Final remaining case is parenthesis found first */
String [] split = arg.split("\\(");
appl = split[0];
for(int i = 1; i < split.length; i++)
data += split[i] + (i+1<split.length?"(":"");
int end = data.lastIndexOf(')');
if (end == -1) {
//ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
} else if(end == data.length()-1) {
data = data.substring(0, end);
}
data = processQuotesAndSlashes(data, ',', '|');
}
if(!appl.trim().equals(""))
{
args.add(appl.trim());
if(!data.trim().equals(""))
{
String [] dataSplit = data.split("\\|");
for (String aDataSplit : dataSplit)
{
args.add(aDataSplit.trim());
}
}
}
}
return args.toArray(new String[args.size()]);
}
public ExtensionsConfigFile readExtensionsFile(String configfile) throws IOException, ConfigParseException
{
super.readFile(configfile);
/* at some point, we may want to resolve back references */
/* that include or goto from one context to another */
return new ExtensionsConfigFile(configfile, categories);
}
/* ast_process_quotes_and_slashes rewritten to be java friendly */
private static String processQuotesAndSlashes(String start, char find, char replace_with)
{
String dataPut = "";
int inEscape = 0;
int inQuotes = 0;
char [] startChars = start.toCharArray();
for (char startChar : startChars)
{
if (inEscape != 0)
{
dataPut += startChar; /* Always goes verbatim */
inEscape = 0;
}
else
{
if (startChar == '\\')
{
inEscape = 1; /* Do not copy \ into the data */
}
else if (startChar == '\'')
{
inQuotes = 1 - inQuotes; /* Do not copy ' into the data */
}
else
{
/* Replace , with |, unless in quotes */
dataPut += inQuotes != 0 ? startChar : ((startChar == find) ? replace_with : startChar);
}
}
}
return dataPut;
}
}

View File

@ -0,0 +1,27 @@
<html>
<head>
<!--
/*
* Copyright 2004-2006 Martin Smith
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
-->
</head>
<body>
<p>Provides classes to manage the dialplan of an Asterisk server.</p>
</body>
</html>

View File

@ -0,0 +1,27 @@
<html>
<head>
<!--
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
-->
</head>
<body>
<p>Provides classes to manage the configuration of an Asterisk server.</p>
</body>
</html>

View File

@ -0,0 +1,167 @@
package org.asteriskjava.fastagi;
import org.asteriskjava.util.DaemonThreadFactory;
import org.asteriskjava.util.Log;
import org.asteriskjava.util.LogFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.SynchronousQueue;
/**
* Abstract base class for FastAGI and AsyncAGI servers.
*
* @since 1.0.0
*/
public abstract class AbstractAgiServer
{
private final Log logger = LogFactory.getLog(getClass());
/**
* The default thread pool size.
*/
private static final int DEFAULT_POOL_SIZE = 10;
/**
* The default thread pool size.
*/
private static final int DEFAULT_MAXIMUM_POOL_SIZE = 100;
/**
* The minimum number of worker threads in the thread pool.
*/
private int poolSize = DEFAULT_POOL_SIZE;
/**
* The maximum number of worker threads in the thread pool. This equals the maximum number of
* concurrent requests this AgiServer can serve.
*/
private int maximumPoolSize = DEFAULT_MAXIMUM_POOL_SIZE;
/**
* The thread pool that contains the worker threads to process incoming requests.
*/
private ThreadPoolExecutor pool;
/**
* The strategy to use for mapping AgiRequests to AgiScripts that serve them.
*/
private MappingStrategy mappingStrategy;
private volatile boolean die = false;
/**
* Sets the number of worker threads in the thread pool.
* <p/>
* This is the number of threads that are available even if they are idle.
* <p/>
* The default pool size is 10.
*
* @param poolSize the size of the worker thread pool.
*/
public void setPoolSize(int poolSize)
{
this.poolSize = poolSize;
}
/**
* Sets the maximum number of worker threads in the thread pool.
* <p/>
* This equals the maximum number of concurrent requests this AgiServer can serve.
* <p/>
* The default maximum pool size is 100.
*
* @param maximumPoolSize the maximum size of the worker thread pool.
*/
public void setMaximumPoolSize(int maximumPoolSize)
{
this.maximumPoolSize = maximumPoolSize;
}
/**
* Sets the strategy to use for mapping AgiRequests to AgiScripts that serve them.
*
* @param mappingStrategy the mapping strategy to use.
*/
public void setMappingStrategy(MappingStrategy mappingStrategy)
{
this.mappingStrategy = mappingStrategy;
}
protected MappingStrategy getMappingStrategy()
{
return mappingStrategy;
}
protected boolean isDie()
{
return die;
}
protected synchronized void shutdown()
{
this.die = true;
if (pool != null)
{
pool.shutdown();
}
}
@Override
protected void finalize() throws Throwable
{
super.finalize();
this.die = true;
if (pool != null)
{
pool.shutdown();
}
}
protected void execute(Runnable command)
{
if (isDie())
{
logger.warn("AgiServer is shutting down: Refused to execute AgiScript");
return;
}
getPool().execute(command);
}
private synchronized ThreadPoolExecutor getPool()
{
if (pool == null)
{
pool = createPool();
logger.info("Thread pool started.");
}
return pool;
}
/**
* Creates a new ThreadPoolExecutor to serve the AGI requests. The nature of this pool
* defines how many concurrent requests can be handled. The default implementation
* returns a dynamic thread pool defined by the poolSize and maximumPoolSize properties.<p>
* You can override this method to change this behavior. For example you can use a cached
* pool with
* <pre>
* return Executors.newCachedThreadPool(new DaemonThreadFactory());
* </pre>
*
* @return the ThreadPoolExecutor to use for serving AGI requests.
* @see #setPoolSize(int)
* @see #setMaximumPoolSize(int)
*/
protected ThreadPoolExecutor createPool()
{
return new ThreadPoolExecutor(
poolSize,
(maximumPoolSize < poolSize) ? poolSize : maximumPoolSize,
50000L, TimeUnit.MILLISECONDS,
new SynchronousQueue<Runnable>(),
new DaemonThreadFactory()
);
}
}

View File

@ -0,0 +1,146 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.MalformedURLException;
import java.util.List;
import java.util.ArrayList;
import java.io.File;
import org.asteriskjava.util.Log;
import org.asteriskjava.util.LogFactory;
/**
* Abstract base class for common mapping strategies.
* <p/>
* If you implement your own mapping strategy you can derive from this class.
*
* @author srt
* @since 0.3
*/
public abstract class AbstractMappingStrategy implements MappingStrategy
{
/**
* Reference to Asterisk-Java's logging subsystem.
*/
protected Log logger = LogFactory.getLog(getClass());
private static final String[] DEFAULT_SCRIPT_PATH = new String[]{"agi"};
private ClassLoader defaultClassLoader = null;
/**
* Returns the ClassLoader to use for loading AgiScript classes and load
* other resources like the mapping properties file.<p>
* By default this method returns a class loader that searches for classes in the
* "agi" subdirectory (if it exists) and uses the context class loader of the
* current thread as the parent class loader.<p>
* You can override this method if you prefer using a different class loader.
*
* @return the ClassLoader to use for loading AgiScript classes and load
* other resources like the mapping properties file.
* @since 1.0.0
*/
protected synchronized ClassLoader getClassLoader()
{
if (defaultClassLoader == null)
{
final ClassLoader parentClassLoader = Thread.currentThread().getContextClassLoader();
final List<URL> dirUrls = new ArrayList<URL>();
for (String scriptPathEntry : DEFAULT_SCRIPT_PATH)
{
final File scriptDir = new File(scriptPathEntry);
if (! scriptDir.isDirectory())
{
continue;
}
try
{
dirUrls.add(scriptDir.toURI().toURL());
}
catch (MalformedURLException e)
{
// should not happen
}
}
if (dirUrls.size() == 0)
{
return parentClassLoader;
}
defaultClassLoader = new URLClassLoader(dirUrls.toArray(new URL[dirUrls.size()]), parentClassLoader);
}
return defaultClassLoader;
}
/**
* Creates a new instance of an AGI script.
*
* @param className Class name of the AGI script. The class must implement
* {@link AgiScript}.
* @return the created instance of the AGI script class. If the instance
* can't be created an error is logged and <code>null</code> is
* returned.
*/
@SuppressWarnings("unchecked")
protected AgiScript createAgiScriptInstance(String className)
{
Class tmpClass;
Class<AgiScript> agiScriptClass;
Constructor<AgiScript> constructor;
AgiScript agiScript;
agiScript = null;
try
{
tmpClass = getClassLoader().loadClass(className);
}
catch (ClassNotFoundException e1)
{
logger.debug("Unable to create AgiScript instance of type " + className
+ ": Class not found, make sure the class exists and is available on the CLASSPATH");
return null;
}
if (!AgiScript.class.isAssignableFrom(tmpClass))
{
logger.warn("Unable to create AgiScript instance of type " + className
+ ": Class does not implement the AgiScript interface");
return null;
}
agiScriptClass = (Class<AgiScript>) tmpClass;
try
{
constructor = agiScriptClass.getConstructor();
agiScript = constructor.newInstance();
}
catch (Exception e)
{
logger.warn("Unable to create AgiScript instance of type " + className, e);
}
return agiScript;
}
}

View File

@ -0,0 +1,799 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import org.asteriskjava.fastagi.command.AgiCommand;
import org.asteriskjava.fastagi.reply.AgiReply;
/**
* Provides the functionality to send AgiCommands to Asterisk while handling an
* AgiRequest.
* <p/>
* This interface is supposed to be used by AgiScripts for interaction with the
* Asterisk server.
*
* @author srt
* @version $Id: AgiChannel.java 1274 2009-03-21 11:08:19Z srt $
*/
public interface AgiChannel
{
/**
* Returns the name of the channel.
*
* @return the name of the channel.
*/
String getName();
/**
* Returns the unqiue id of the channel.
*
* @return the unqiue id of the channel.
*/
String getUniqueId();
/**
* Returns the reply received in response to the last command sent to Asterisk.
*
* @return the reply received in response to the last command sent to Asterisk
* or <code>null</code> if none has yet been received.
* @since 1.0.0
*/
AgiReply getLastReply();
/**
* Sends a command to asterisk and returns the corresponding reply. The reply is also
* available through {@link #getLastReply()}.
*
* @param command the command to send.
* @return the reply of the asterisk server containing the return value.
* @throws AgiException if the command can't be sent to Asterisk (for
* example because the channel has been hung up)
*/
AgiReply sendCommand(AgiCommand command) throws AgiException;
/**
* Answers the channel.
*
* @since 0.2
*/
void answer() throws AgiException;
/**
* Hangs the channel up.
*
* @since 0.2
*/
void hangup() throws AgiException;
/**
* Cause the channel to automatically hangup at the given number of seconds
* in the future.
*
* @param time the number of seconds before this channel is automatically
* hung up.<p>
* 0 disables the autohangup feature.
* @since 0.2
*/
void setAutoHangup(int time) throws AgiException;
/**
* Sets the caller id on the current channel.
*
* @param callerId the raw caller id to set, for example "John Doe<1234>".
* @since 0.2
*/
void setCallerId(String callerId) throws AgiException;
/**
* Plays music on hold from the default music on hold class.
*
* @since 0.2
*/
void playMusicOnHold() throws AgiException;
/**
* Plays music on hold from the given music on hold class.
*
* @param musicOnHoldClass the music on hold class to play music from as
* configures in Asterisk's <code><musiconhold.conf/code>.
* @since 0.2
*/
void playMusicOnHold(String musicOnHoldClass) throws AgiException;
/**
* Stops playing music on hold.
*
* @since 0.2
*/
void stopMusicOnHold() throws AgiException;
/**
* Returns the status of the channel.<p>
* Return values:
* <ul>
* <li>0 Channel is down and available
* <li>1 Channel is down, but reserved
* <li>2 Channel is off hook
* <li>3 Digits (or equivalent) have been dialed
* <li>4 Line is ringing
* <li>5 Remote end is ringing
* <li>6 Line is up
* <li>7 Line is busy
* </ul>
*
* @return the status of the channel.
* @since 0.2
*/
int getChannelStatus() throws AgiException;
/**
* Plays the given file and waits for the user to enter DTMF digits until he
* presses '#'. The user may interrupt the streaming by starting to enter
* digits.
*
* @param file the name of the file to play
* @return a String containing the DTMF the user entered
* @since 0.2
*/
String getData(String file) throws AgiException;
/**
* Plays the given file and waits for the user to enter DTMF digits until he
* presses '#' or the timeout occurs. The user may interrupt the streaming
* by starting to enter digits.
*
* @param file the name of the file to play
* @param timeout the timeout in milliseconds to wait for user input.<p>
* 0 means standard timeout value, -1 means "ludicrous time"
* (essentially never times out).
* @return a String containing the DTMF the user entered
* @since 0.2
*/
String getData(String file, long timeout) throws AgiException;
/**
* Plays the given file and waits for the user to enter DTMF digits until he
* presses '#' or the timeout occurs or the maximum number of digits has
* been entered. The user may interrupt the streaming by starting to enter
* digits.
*
* @param file the name of the file to play
* @param timeout the timeout in milliseconds to wait for user input.<p>
* 0 means standard timeout value, -1 means "ludicrous time"
* (essentially never times out).
* @param maxDigits the maximum number of digits the user is allowed to
* enter
* @return a String containing the DTMF the user entered
* @since 0.2
*/
String getData(String file, long timeout, int maxDigits)
throws AgiException;
/**
* Plays the given file, and waits for the user to press one of the given
* digits. If none of the esacpe digits is pressed while streaming the file
* it waits for the default timeout of 5 seconds still waiting for the user
* to press a digit.
*
* @param file the name of the file to stream, must not include extension.
* @param escapeDigits contains the digits that the user is expected to
* press.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char getOption(String file, String escapeDigits) throws AgiException;
/**
* Plays the given file, and waits for the user to press one of the given
* digits. If none of the esacpe digits is pressed while streaming the file
* it waits for the specified timeout still waiting for the user to press a
* digit.
*
* @param file the name of the file to stream, must not include extension.
* @param escapeDigits contains the digits that the user is expected to
* press.
* @param timeout the timeout in milliseconds to wait if none of the defined
* esacpe digits was presses while streaming.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char getOption(String file, String escapeDigits, long timeout)
throws AgiException;
/**
* Executes the given command.
*
* @param application the name of the application to execute, for example
* "Dial".
* @return the return code of the application of -2 if the application was
* not found.
* @since 0.2
*/
int exec(String application) throws AgiException;
/**
* Executes the given command.
*
* @param application the name of the application to execute, for example
* "Dial".
* @param options the parameters to pass to the application, for example
* "SIP/123".
* @return the return code of the application of -2 if the application was
* not found.
* @since 0.2
*/
int exec(String application, String options) throws AgiException;
/**
* Sets the context for continuation upon exiting the application.
*
* @param context the context for continuation upon exiting the application.
* @since 0.2
*/
void setContext(String context) throws AgiException;
/**
* Sets the extension for continuation upon exiting the application.
*
* @param extension the extension for continuation upon exiting the
* application.
* @since 0.2
*/
void setExtension(String extension) throws AgiException;
/**
* Sets the priority or label for continuation upon exiting the application.
*
* @param priority the priority or label for continuation upon exiting the
* application.
* @since 0.2
*/
void setPriority(String priority) throws AgiException;
/**
* Plays the given file.
*
* @param file name of the file to play.
* @since 0.2
*/
void streamFile(String file) throws AgiException;
/**
* Plays the given file and allows the user to escape by pressing one of the
* given digit.
*
* @param file name of the file to play.
* @param escapeDigits a String containing the DTMF digits that allow the
* user to escape.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char streamFile(String file, String escapeDigits) throws AgiException;
/**
* Plays the given file starting at the specified offset and allows the
* user to escape by pressing one of the given digit.
*
* @param file name of the file to play.
* @param escapeDigits a String containing the DTMF digits that allow the
* user to escape.
* @param offset the offset samples to skip before streaming.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 1.0.0
*/
char streamFile(String file, String escapeDigits, int offset) throws AgiException;
/**
* Says the given digit string.
*
* @param digits the digit string to say.
* @since 0.2
*/
void sayDigits(String digits) throws AgiException;
/**
* Says the given number, returning early if any of the given DTMF number
* are received on the channel.
*
* @param digits the digit string to say.
* @param escapeDigits a String containing the DTMF digits that allow the
* user to escape.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char sayDigits(String digits, String escapeDigits) throws AgiException;
/**
* Says the given number.
*
* @param number the number to say.
* @since 0.2
*/
void sayNumber(String number) throws AgiException;
/**
* Says the given number, returning early if any of the given DTMF number
* are received on the channel.
*
* @param number the number to say.
* @param escapeDigits a String containing the DTMF digits that allow the
* user to escape.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char sayNumber(String number, String escapeDigits) throws AgiException;
/**
* Says the given character string with phonetics.
*
* @param text the text to say.
* @since 0.2
*/
void sayPhonetic(String text) throws AgiException;
/**
* Says the given character string with phonetics, returning early if any of
* the given DTMF number are received on the channel.
*
* @param text the text to say.
* @param escapeDigits a String containing the DTMF digits that allow the
* user to escape.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char sayPhonetic(String text, String escapeDigits) throws AgiException;
/**
* Says the given character string.
*
* @param text the text to say.
* @since 0.2
*/
void sayAlpha(String text) throws AgiException;
/**
* Says the given character string, returning early if any of the given DTMF
* number are received on the channel.
*
* @param text the text to say.
* @param escapeDigits a String containing the DTMF digits that allow the
* user to escape.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char sayAlpha(String text, String escapeDigits) throws AgiException;
/**
* Says the given time.
*
* @param time the time to say in seconds since 00:00:00 on January 1, 1970.
* @since 0.2
*/
void sayTime(long time) throws AgiException;
/**
* Says the given time, returning early if any of the given DTMF number are
* received on the channel.
*
* @param time the time to say in seconds since 00:00:00 on January 1, 1970.
* @param escapeDigits a String containing the DTMF digits that allow the
* user to escape.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char sayTime(long time, String escapeDigits) throws AgiException;
/**
* Returns the value of the current channel or global variable.<p>
* Supports functions and builtin variables. To retrieve
* the caller id you can use <code>getVariable("CALLERID(name)");<code><p>
* Does not support expression parsing, use {@link #getFullVariable(String)} in those cases.
*
* @param name the name of the variable (or function call) to retrieve.
* @return the value of the given variable or <code>null</code> if not
* set.
* @since 0.2
*/
String getVariable(String name) throws AgiException;
/**
* Sets the value of the current channel or global variable to a new value.<p>
* Supports functions and builtin variables. To set the caller id
* you can use <code>setVariable("CALLERID(name)", "John Doe");</code>
*
* @param name the name of the variable (or function call) to set.
* @param value the new value to set.
* @since 0.2
*/
void setVariable(String name, String value) throws AgiException;
/**
* Waits up to 'timeout' milliseconds to receive a DTMF digit.
*
* @param timeout timeout the milliseconds to wait for the channel to
* receive a DTMF digit, -1 will wait forever.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char waitForDigit(int timeout) throws AgiException;
/**
* Evaluates a channel expression for the current channel. To extract
* the caller id use <code>getFullVariable("${CALLERID(name)}");</code>.<p>
* Available since Asterisk 1.2.
*
* @param expr the expression to evaluate.
* @return the value of the given expression or <code>null</code> if not
* set.
* @see #getVariable(String)
* @since 0.2
*/
String getFullVariable(String expr) throws AgiException;
/**
* Evaluates a channel expression for the given channel.To extract
* the caller id of channel use <code>getFullVariable("${CALLERID(name)}", "SIP/john-0085d860");</code>.<p>
* Available since Asterisk 1.2.
*
* @param expr the the expression to evaluate.
* @param channel the name of the channel.
* @return the value of the given expression or <code>null</code> if not
* set.
* @since 0.2
*/
String getFullVariable(String expr, String channel) throws AgiException;
/**
* Says the given time.<p>
* Available since Asterisk 1.2.
*
* @param time the time to say in seconds elapsed since 00:00:00 on January
* 1, 1970, Coordinated Universal Time (UTC)
* @since 0.2
*/
void sayDateTime(long time) throws AgiException;
/**
* Says the given time and allows interruption by one of the given escape
* digits.<p>
* Available since Asterisk 1.2.
*
* @param time the time to say in seconds elapsed since 00:00:00 on January
* 1, 1970, Coordinated Universal Time (UTC)
* @param escapeDigits the digits that allow the user to interrupt this
* command or <code>null</code> for none.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char sayDateTime(long time, String escapeDigits) throws AgiException;
/**
* Says the given time in the given format and allows interruption by one of
* the given escape digits.<p>
* Available since Asterisk 1.2.
*
* @param time the time to say in seconds elapsed since 00:00:00 on January
* 1, 1970, Coordinated Universal Time (UTC)
* @param escapeDigits the digits that allow the user to interrupt this
* command or <code>null</code> for none.
* @param format the format the time should be said in
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char sayDateTime(long time, String escapeDigits, String format) throws AgiException;
/**
* Says the given time in the given format and timezone and allows
* interruption by one of the given escape digits.<p>
* Available since Asterisk 1.2.
*
* @param time the time to say in seconds elapsed since 00:00:00 on January
* 1, 1970, Coordinated Universal Time (UTC)
* @param escapeDigits the digits that allow the user to interrupt this
* command or <code>null</code> for none.
* @param format the format the time should be said in
* @param timezone the timezone to use when saying the time, for example
* "UTC" or "Europe/Berlin".
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.2
*/
char sayDateTime(long time, String escapeDigits, String format,
String timezone) throws AgiException;
/**
* Retrieves an entry in the Asterisk database for a given family and key.
*
* @param family the family of the entry to retrieve.
* @param key the key of the entry to retrieve.
* @return the value of the given family and key or <code>null</code> if there
* is no such value.
* @since 0.3
*/
String databaseGet(String family, String key) throws AgiException;
/**
* Adds or updates an entry in the Asterisk database for a given family, key,
* and value.
*
* @param family the family of the entry to add or update.
* @param key the key of the entry to add or update.
* @param value the new value of the entry.
* @since 0.3
*/
void databasePut(String family, String key, String value) throws AgiException;
/**
* Deletes an entry in the Asterisk database for a given family and key.
*
* @param family the family of the entry to delete.
* @param key the key of the entry to delete.
* @since 0.3
*/
void databaseDel(String family, String key) throws AgiException;
/**
* Deletes a whole family of entries in the Asterisk database.
*
* @param family the family to delete.
* @since 0.3
*/
void databaseDelTree(String family) throws AgiException;
/**
* Deletes all entries of a given family in the Asterisk database that have a key
* that starts with a given prefix.
*
* @param family the family of the entries to delete.
* @param keytree the prefix of the keys of the entries to delete.
* @since 0.3
*/
void databaseDelTree(String family, String keytree) throws AgiException;
/**
* Sends a message to the Asterisk console via the verbose message system.
*
* @param message the message to send.
* @param level the verbosity level to use. Must be in [1..4].
* @since 0.3
*/
void verbose(String message, int level) throws AgiException;
/**
* Record to a file until a given dtmf digit in the sequence is received.
*
* @param file the name of the file to stream, must not include extension.
* @param format the format of the file to be recorded, for example "wav".
* @param escapeDigits contains the digits that allow the user to end
* recording.
* @param timeout the maximum record time in milliseconds, or -1 for no
* timeout.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.3
*/
char recordFile(String file, String format, String escapeDigits,
int timeout) throws AgiException;
/**
* Record to a file until a given dtmf digit in the sequence is received.
*
* @param file the name of the file to stream, must not include extension.
* @param format the format of the file to be recorded, for example "wav".
* @param escapeDigits contains the digits that allow the user to end
* recording.
* @param timeout the maximum record time in milliseconds, or -1 for no
* timeout.
* @param offset the offset samples to skip.
* @param beep <code>true</code> if a beep should be played before
* recording.
* @param maxSilence The amount of silence (in seconds) to allow before
* returning despite the lack of dtmf digits or reaching timeout.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.3
*/
char recordFile(String file, String format, String escapeDigits,
int timeout, int offset, boolean beep, int maxSilence) throws AgiException;
/**
* Plays the given file allowing the user to control the streaming by
* using "#" for forward and "*" for rewind.
*
* @param file the name of the file to stream, must not include extension.
* @since 0.3
*/
void controlStreamFile(String file) throws AgiException;
/**
* Plays the given file allowing the user to control the streaming by
* using "#" for forward and "*" for rewind. Pressing one of the escape
* digits stops streaming.
*
* @param file the name of the file to stream, must not include extension.
* @param escapeDigits contains the digits that allow the user to interrupt
* this command.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.3
*/
char controlStreamFile(String file, String escapeDigits) throws AgiException;
/**
* Plays the given file allowing the user to control the streaming by
* using "#" for forward and "*" for rewind. Pressing one of the escape
* digits stops streaming. The file is played starting at the indicated
* offset.
*
* @param file the name of the file to stream, must not include extension.
* @param escapeDigits contains the digits that allow the user to interrupt
* this command. May be <code>null</code> if you don't want the
* user to interrupt.
* @param offset the offset samples to skip before streaming.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.3
*/
char controlStreamFile(String file, String escapeDigits, int offset) throws AgiException;
/**
* Plays the given file allowing the user to control the streaming by
* using forwardDigit for forward, rewindDigit for rewind and pauseDigit for pause.
* Pressing one of the escape digits stops streaming.
* The file is played starting at the indicated
* offset, use 0 to start at the beginning.
*
* @param file the name of the file to stream, must not include extension.
* @param escapeDigits contains the digits that allow the user to interrupt
* this command. May be <code>null</code> if you don't want the
* user to interrupt.
* @param offset the offset samples to skip before streaming, use 0 to start at the beginning.
* @param forwardDigit the digit for fast forward.
* @param rewindDigit the digit for rewind.
* @param pauseDigit the digit for pause and unpause.
* @return the DTMF digit pressed or 0x0 if none was pressed.
* @since 0.3
*/
char controlStreamFile(String file, String escapeDigits,
int offset, String forwardDigit, String rewindDigit,
String pauseDigit) throws AgiException;
/**
* Creates a speech object that uses the default speech engine. The speech object is
* used by the other speech methods and must be created before they are called.
*
* @throws AgiSpeechException if the speech object cannot be created.
* @see #speechDestroy()
* @since 1.0.0
*/
void speechCreate() throws AgiException;
/**
* Creates a speech object that uses the given speech engine. The speech object is
* used by the other speech methods and must be created before they are called.
*
* @param engine the name of the speech engine. For example "lumenvox".
* @throws AgiSpeechException if the speech object cannot be created.
* @see #speechDestroy()
* @since 1.0.0
*/
void speechCreate(String engine) throws AgiException;
/**
* Sets the speech engine setting indicated by name to the given value.
*
* @param name the name of the setting to set.
* @param value the value to set.
* @throws AgiSpeechException if the setting cannot be set.
* @since 1.0.0
*/
void speechSet(String name, String value) throws AgiException;
/**
* Destroys the current speech object.
*
* @throws AgiSpeechException if the speech engine cannot be destroyed.
* @see #speechCreate(String)
* @since 1.0.0
*/
void speechDestroy() throws AgiException;
/**
* Loads the specified grammar. The grammer is then available for calls to {@link #speechActivateGrammar(String)}
* under the given name. Eplicitly loading a grammer is only required if the grammer has not been defined in the
* speech engine configuration, e.g. the <code>[grammars]</code> section of <code>lumenvox.conf</code>.
*
* @param label the name of the grammar, used for subsequent calls to {@link #speechActivateGrammar(String)},
* {@link #speechDeactivateGrammar(String)} and {@link #speechUnloadGrammar(String)}.
* @param path the path to the grammar to load.
* @throws AgiSpeechException if the grammar cannot be loaded.
* @see #speechUnloadGrammar(String)
* @see #speechActivateGrammar(String)
* @since 1.0.0
*/
void speechLoadGrammar(String label, String path) throws AgiException;
/**
* Unloads the specified grammar.
*
* @param label the name of the grammar to unload.
* @throws AgiSpeechException if the grammar cannot be unloaded.
* @see #speechLoadGrammar(String, String)
* @since 1.0.0
*/
void speechUnloadGrammar(String label) throws AgiException;
/**
* Activates the specified grammar.
*
* @param label the name of the grammar to activate.
* @throws AgiSpeechException if the grammar cannot be activated.
* @see #speechDeactivateGrammar(String)
* @see #speechLoadGrammar(String, String)
* @since 1.0.0
*/
void speechActivateGrammar(String label) throws AgiException;
/**
* Deactivates the specified grammar.
*
* @param label the name to the grammar to deactivate.
* @throws AgiSpeechException if the grammar cannot be deactivated.
* @see #speechActivateGrammar(String)
* @since 1.0.0
*/
void speechDeactivateGrammar(String label) throws AgiException;
/**
* Plays the given prompt while listening for speech and DTMF.
*
* @param prompt the name of the file to stream, must not include extension.
* @param timeout the timeout in milliseconds to wait for user input.<p>
* 0 means standard timeout value, -1 means "ludicrous time"
* (essentially never times out).
* @return the recognition result
* @since 1.0.0
*/
SpeechRecognitionResult speechRecognize(String prompt, int timeout) throws AgiException;
/**
* Plays the given prompt while listening for speech and DTMF.
*
* @param prompt the name of the file to stream, must not include extension.
* @param timeout the timeout in milliseconds to wait for user input.<p>
* 0 means standard timeout value, -1 means "ludicrous time"
* (essentially never times out).
* @param offset the offset samples to skip before streaming, use 0 to start at the beginning.
* @return the recognition result
* @since 1.0.0
*/
SpeechRecognitionResult speechRecognize(String prompt, int timeout, int offset) throws AgiException, AgiSpeechException;
/**
* Defines the point in the dialplan where the call will continue when the AGI script
* returns.<p>
* This is a shortcut for calling {@link #setContext(String)}, {@link #setExtension(String)}
* and {@link #setPriority(String)} in series.
*
* @param context the context for continuation upon exiting the application.
* @param extension the extension for continuation upon exiting the
* application.
* @param priority the priority or label for continuation upon exiting the
* application.
* @see #setContext(String)
* @see #setExtension(String)
* @see #setPriority(String)
* @since 1.0.0
*/
void continueAt(String context, String extension, String priority) throws AgiException;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
/**
* Base class for all AGI specific exceptions.
*
* @author srt
* @version $Id: AgiException.java 938 2007-12-31 03:23:38Z srt $
*/
public class AgiException extends Exception
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 1215836054948768757L;
/**
* Creates a new AgiException with the given message.
*
* @param message a message describing the AgiException.
*/
public AgiException(String message)
{
super(message);
}
/**
* Creates a new AgiException with the given message and cause.
*
* @param message a message describing the AgiException.
* @param cause the throwable that caused this exception.
*/
public AgiException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
/**
* The AgiHangupException is thrown if the channel is hung up while
* processing the {@link org.asteriskjava.fastagi.AgiRequest}.<p>
* Up to Asterisk 1.4 hanging up the channel also closes the TCP connection,
* since Asterisk 1.6 the connection is kept alive but commands that
* require an active channel return status code
* {@link org.asteriskjava.fastagi.reply.AgiReply#SC_DEAD_CHANNEL}. Both events
* are translated to an AgiHangupException.
*
* @author srt
* @version $Id: AgiHangupException.java 1261 2009-03-14 03:17:17Z srt $
*/
public class AgiHangupException extends AgiException
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3256444698691252274L;
/**
* Creates a new AgiHangupException.
*/
public AgiHangupException()
{
super("Channel was hung up.");
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
/**
* The AgiNetworkException usally wraps an IOException denoting a network
* problem while talking to the Asterisk server.
*
* @author srt
* @version $Id: AgiNetworkException.java 938 2007-12-31 03:23:38Z srt $
*/
public class AgiNetworkException extends AgiException
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3256445789629723703L;
/**
* Creates a new AgiNetworkException with the given message and cause.
*
* @param message a message describing the AgiException.
* @param cause the throwable that caused this exception.
*/
public AgiNetworkException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@ -0,0 +1,478 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import org.asteriskjava.fastagi.command.AgiCommand;
import org.asteriskjava.fastagi.internal.AgiConnectionHandler;
import org.asteriskjava.fastagi.reply.AgiReply;
/**
* AgiOperations provides some convinience methods that wrap the various
* {@link AgiCommand AgiCommands}.
*
* @since 0.3
* @author srt
* @version $Id: AgiOperations.java 1271 2009-03-21 03:41:24Z srt $
*/
public class AgiOperations implements AgiChannel
{
private final AgiChannel channel;
/**
* Creates a new instance that operates on the channel attached to the
* current thread.
*/
public AgiOperations()
{
this.channel = null;
}
/**
* Creates a new instance that operates on the given channel.
*
* @param channel the channel to operate on.
*/
public AgiOperations(AgiChannel channel)
{
this.channel = channel;
}
/**
* Returns the channel to operate on.
*
* @return the channel to operate on.
* @throws IllegalStateException if no {@link AgiChannel} is bound to the
* current channel and no channel has been passed to the
* constructor.
*/
protected AgiChannel getChannel()
{
AgiChannel threadBoundChannel;
if (channel != null)
{
return channel;
}
threadBoundChannel = AgiConnectionHandler.getChannel();
if (threadBoundChannel == null)
{
throw new IllegalStateException("Trying to send command from an invalid thread");
}
return threadBoundChannel;
}
/* The following methods simply delegate to #getChannel() */
public String getName()
{
return getChannel().getName();
}
public String getUniqueId()
{
return getChannel().getUniqueId();
}
public AgiReply getLastReply()
{
return getChannel().getLastReply();
}
public AgiReply sendCommand(AgiCommand command)
throws AgiException
{
return getChannel().sendCommand(command);
}
public void answer()
throws AgiException
{
getChannel().answer();
}
public void hangup()
throws AgiException
{
getChannel().hangup();
}
public void setAutoHangup(int time)
throws AgiException
{
getChannel().setAutoHangup(time);
}
public void setCallerId(String callerId)
throws AgiException
{
getChannel().setCallerId(callerId);
}
public void playMusicOnHold()
throws AgiException
{
getChannel().playMusicOnHold();
}
public void playMusicOnHold(String musicOnHoldClass)
throws AgiException
{
getChannel().playMusicOnHold(musicOnHoldClass);
}
public void stopMusicOnHold()
throws AgiException
{
getChannel().stopMusicOnHold();
}
public int getChannelStatus()
throws AgiException
{
return getChannel().getChannelStatus();
}
public String getData(String file)
throws AgiException
{
return getChannel().getData(file);
}
public String getData(String file, long timeout)
throws AgiException
{
return getChannel().getData(file, timeout);
}
public String getData(String file, long timeout, int maxDigits)
throws AgiException
{
return getChannel().getData(file, timeout, maxDigits);
}
public char getOption(String file, String escapeDigits)
throws AgiException
{
return getChannel().getOption(file, escapeDigits);
}
public char getOption(String file, String escapeDigits, long timeout)
throws AgiException
{
return getChannel().getOption(file, escapeDigits, timeout);
}
public int exec(String application)
throws AgiException
{
return getChannel().exec(application);
}
public int exec(String application, String options)
throws AgiException
{
return getChannel().exec(application, options);
}
public void setContext(String context)
throws AgiException
{
getChannel().setContext(context);
}
public void setExtension(String extension)
throws AgiException
{
getChannel().setExtension(extension);
}
public void setPriority(String priority)
throws AgiException
{
getChannel().setPriority(priority);
}
public void streamFile(String file)
throws AgiException
{
getChannel().streamFile(file);
}
public char streamFile(String file, String escapeDigits)
throws AgiException
{
return getChannel().streamFile(file, escapeDigits);
}
public char streamFile(String file, String escapeDigits, int offset)
throws AgiException
{
return getChannel().streamFile(file, escapeDigits, offset);
}
public void sayDigits(String digits)
throws AgiException
{
getChannel().sayDigits(digits);
}
public char sayDigits(String digits, String escapeDigits)
throws AgiException
{
return getChannel().sayDigits(digits, escapeDigits);
}
public void sayNumber(String number)
throws AgiException
{
getChannel().sayNumber(number);
}
public char sayNumber(String number, String escapeDigits)
throws AgiException
{
return getChannel().sayNumber(number, escapeDigits);
}
public void sayPhonetic(String text)
throws AgiException
{
getChannel().sayPhonetic(text);
}
public char sayPhonetic(String text, String escapeDigits)
throws AgiException
{
return getChannel().sayPhonetic(text, escapeDigits);
}
public void sayAlpha(String text)
throws AgiException
{
getChannel().sayAlpha(text);
}
public char sayAlpha(String text, String escapeDigits)
throws AgiException
{
return getChannel().sayAlpha(text, escapeDigits);
}
public void sayTime(long time)
throws AgiException
{
getChannel().sayTime(time);
}
public char sayTime(long time, String escapeDigits)
throws AgiException
{
return getChannel().sayTime(time, escapeDigits);
}
public String getVariable(String name)
throws AgiException
{
return getChannel().getVariable(name);
}
public void setVariable(String name, String value)
throws AgiException
{
getChannel().setVariable(name, value);
}
public char waitForDigit(int timeout)
throws AgiException
{
return getChannel().waitForDigit(timeout);
}
public String getFullVariable(String name)
throws AgiException
{
return getChannel().getFullVariable(name);
}
public String getFullVariable(String name, String channel)
throws AgiException
{
return getChannel().getFullVariable(name, channel);
}
public void sayDateTime(long time)
throws AgiException
{
getChannel().sayDateTime(time);
}
public char sayDateTime(long time, String escapeDigits)
throws AgiException
{
return getChannel().sayDateTime(time, escapeDigits);
}
public char sayDateTime(long time, String escapeDigits, String format)
throws AgiException
{
return getChannel().sayDateTime(time, escapeDigits, format);
}
public char sayDateTime(long time, String escapeDigits, String format, String timezone)
throws AgiException
{
return getChannel().sayDateTime(time, escapeDigits, format, timezone);
}
public String databaseGet(String family, String key)
throws AgiException
{
return getChannel().databaseGet(family, key);
}
public void databasePut(String family, String key, String value)
throws AgiException
{
getChannel().databasePut(family, key, value);
}
public void databaseDel(String family, String key)
throws AgiException
{
getChannel().databaseDel(family, key);
}
public void databaseDelTree(String family)
throws AgiException
{
getChannel().databaseDelTree(family);
}
public void databaseDelTree(String family, String keytree)
throws AgiException
{
getChannel().databaseDelTree(family, keytree);
}
public void verbose(String message, int level)
throws AgiException
{
getChannel().verbose(message, level);
}
public char recordFile(String file, String format, String escapeDigits, int timeout)
throws AgiException
{
return getChannel().recordFile(file, format, escapeDigits, timeout);
}
public char recordFile(String file, String format, String escapeDigits, int timeout, int offset, boolean beep, int maxSilence)
throws AgiException
{
return getChannel().recordFile(file, format, escapeDigits, timeout, offset, beep, maxSilence);
}
public void controlStreamFile(String file)
throws AgiException
{
getChannel().controlStreamFile(file);
}
public char controlStreamFile(String file, String escapeDigits)
throws AgiException
{
return getChannel().controlStreamFile(file, escapeDigits);
}
public char controlStreamFile(String file, String escapeDigits, int offset)
throws AgiException
{
return getChannel().controlStreamFile(file, escapeDigits, offset);
}
public char controlStreamFile(String file, String escapeDigits, int offset, String forwardDigit, String rewindDigit, String pauseDigit)
throws AgiException
{
return getChannel().controlStreamFile(file, escapeDigits, offset, forwardDigit, rewindDigit, pauseDigit);
}
public void speechCreate() throws AgiException
{
getChannel().speechCreate();
}
public void speechCreate(String engine)
throws AgiException
{
getChannel().speechCreate(engine);
}
public void speechSet(String name, String value)
throws AgiException
{
getChannel().speechSet(name, value);
}
public void speechDestroy()
throws AgiException
{
getChannel().speechDestroy();
}
public void speechLoadGrammar(String name, String path)
throws AgiException
{
getChannel().speechLoadGrammar(name, path);
}
public void speechUnloadGrammar(String name)
throws AgiException
{
getChannel().speechUnloadGrammar(name);
}
public void speechActivateGrammar(String name)
throws AgiException
{
getChannel().speechActivateGrammar(name);
}
public void speechDeactivateGrammar(String name)
throws AgiException
{
getChannel().speechDeactivateGrammar(name);
}
public SpeechRecognitionResult speechRecognize(String prompt, int timeout)
throws AgiException
{
return getChannel().speechRecognize(prompt, timeout);
}
public SpeechRecognitionResult speechRecognize(String prompt, int timeout, int offset)
throws AgiException
{
return getChannel().speechRecognize(prompt, timeout, offset);
}
public void continueAt(String context, String extension, String priority) throws AgiException
{
getChannel().continueAt(context, extension, priority);
}
}

View File

@ -0,0 +1,297 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import java.net.InetAddress;
import java.util.Map;
/**
* Provides client request information to an {@link org.asteriskjava.fastagi.AgiScript}.<p>
* This includes information about the channel the script is invoked on and
* parameters passed from the dialplan.
*
* @author srt
* @version $Id: AgiRequest.java 1286 2009-04-04 09:40:40Z srt $
*/
public interface AgiRequest
{
/**
* Returns a Map containing the raw request name/value pairs.
*
* @return Map contain raw request name/value pairs.
*/
Map getRequest();
/**
* Returns the name of the script to execute including its full path.<p>
* This corresponds to the request url with protocol, host, port and
* parameters stripped off.<p>
* As Async AGI does not yet pass a script parameter this property will
* be <code>null</code> for requests received through Async AGI.
*
* @return the name of the script to execute.
*/
String getScript();
/**
* Returns the full URL of the requestURL in the form
* agi://host[:port][/script][?param1=value1&param2=value2].
*
* @return the full URL of the requestURL in the form
* agi://host[:port][/script][?param1=value1&param2=value2].
*/
String getRequestURL();
/**
* Returns the name of the channel.
*
* @return the name of the channel.
*/
String getChannel();
/**
* Returns the unqiue id of the channel.
*
* @return the unqiue id of the channel.
*/
String getUniqueId();
/**
* Returns the type of the channel, for example "SIP".
*
* @return the type of the channel, for example "SIP".
*/
String getType();
/**
* Returns the language set for the current channel, for example "en".
*
* @return the language set for the current channel, for example "en".
*/
String getLanguage();
/**
* Returns the Caller*ID number, for example "1234".<p>
* Note: even with Asterisk 1.0 is contains only the numerical part
* of the Caller ID.
*
* @return the Caller*ID number, for example "1234", if no Caller*ID is set or it
* is "unknown" <code>null</code> is returned.
* @deprecated as of 0.3, use {@link #getCallerIdNumber()} instead.
*/
String getCallerId();
/**
* Returns the Caller*ID number, for example "1234".<p>
* Note: even with Asterisk 1.0 is contains only the numerical part
* of the Caller ID.
*
* @return the Caller*ID number, for example "1234", if no Caller*ID is set or it
* is "unknown" <code>null</code> is returned.
*/
String getCallerIdNumber();
/**
* Returns the the Caller*ID Name, for example "John Doe".
*
* @return the the Caller*ID Name, for example "John Doe", if no Caller*ID
* Name is set or it is "unknown" <code>null</code> is returned.
*/
String getCallerIdName();
/**
* Returns the number, that has been dialed by the user.
*
* @return the dialed number, if no DNID is available or it is "unknown"
* <code>null</code> is returned.
*/
String getDnid();
/**
* If this call has been forwared, the number of the person doing the
* redirect is returned (Redirected dialed number identification service).<p>
* This is usally only only available on PRI.
*
* @return the number of the person doing the redirect, , if no RDNIS is
* available or it is "unknown" <code>null</code> is returned.
*/
String getRdnis();
/**
* Returns the context in the dial plan from which the AGI script was
* called.
*
* @return the context in the dial plan from which the AGI script was
* called.
*/
String getContext();
/**
* Returns the extension in the dial plan from which the AGI script was
* called.
*
* @return the extension in the dial plan from which the AGI script was
* called.
*/
String getExtension();
/**
* Returns the priority of the dial plan entry the AGI script was
* called from.
*
* @return the priority of the dial plan entry the AGI script was
* called from.
*/
Integer getPriority();
/**
* Returns wheather this agi is passed audio (EAGI - Enhanced AGI).<p>
* Enhanced AGI is currently not supported on FastAGI.
*
* @return Boolean.TRUE if this agi is passed audio, Boolean.FALSE
* otherwise.
*/
Boolean getEnhanced();
/**
* Returns the account code set for the call.
*
* @return the account code set for the call.
*/
String getAccountCode();
/**
* Returns the Callerid presentation/screening.<p>
* Available since Asterisk 1.2.
*
* @return the Callerid presentation/screening.
* @since 0.2
*/
Integer getCallingPres();
/**
* Returns the Callerid ANI 2 (Info digits).<p>
* Available since Asterisk 1.2.
*
* @return the Callerid ANI 2 (Info digits).
* @since 0.2
*/
Integer getCallingAni2();
/**
* Returns the Callerid Type of Number.<p>
* Available since Asterisk 1.2.
*
* @return the Callerid Type of Number.
* @since 0.2
*/
Integer getCallingTon();
/**
* Returns the Callerid Transit Network Select.<p>
* Available since Asterisk 1.2.
*
* @return the Callerid Transit Network Select.
* @since 0.2
*/
Integer getCallingTns();
/**
* Returns the value of a request parameter as a String, or
* <code>null</code> if the parameter does not exist. You should only use
* this method when you are sure the parameter has only one value.<p>
* If the parameter might have more than one value, use
* {@link #getParameterValues(String)}.<p>
* If you use this method with a multivalued parameter, the value returned
* is equal to the first value in the array returned by
* <code>getParameterValues</code>.
*
* @param name a String containing the name of the parameter whose value is
* requested.
* @return a String representing the single value of the parameter.
* @see #getParameterValues(String)
*/
String getParameter(String name);
/**
* Returns an array of String objects containing all of the values the given
* request parameter has, or
* an empty array if the parameter does not exist.<p>
* If the parameter has a single value, the array has a length of 1.
*
* @param name a String containing the name of the parameter whose value is requested.
* @return an array of String objects containing the parameter's values.
*/
String[] getParameterValues(String name);
/**
* Returns a Map of the parameters of this request.
*
* @return a java.util.Map containing parameter names as keys and parameter
* values as map values. The keys in the parameter map are of type
* String. The values in the parameter map are of type String array.
*/
Map<String, String[]> getParameterMap();
/**
* Returns the array of arguments passed from the AGI dialplan command.<p>
* Example: {@code AGI(agi://localhost/HelloWorld,value1,,value2)} results in
* {@code getArguments()[0] = "value1"}, {@code getArguments()[1] = null}
* and {@code getArguments()[2] = "value2"}.<p>
* Available since Asterisk 1.6
*
* @return the array of arguments passed from the AGI command, never <code>null</code>.
* @since 1.0.0
*/
String[] getArguments();
/**
* Returns the local address this channel, that is the IP address of the AGI
* server.
*
* @return the local address this channel.
* @since 0.2
*/
InetAddress getLocalAddress();
/**
* Returns the local port of this channel, that is the port the AGI server
* is listening on.
*
* @return the local port of this socket channel.
* @since 0.2
*/
int getLocalPort();
/**
* Returns the remote address of this channel, that is the IP address of the
* Asterisk server.
*
* @return the remote address of this channel.
* @since 0.2
*/
InetAddress getRemoteAddress();
/**
* Returns the remote port of this channel, that is the client port the
* Asterisk server is using for the AGI connection.
*
* @return the remote port of this channel.
* @since 0.2
*/
int getRemotePort();
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
/**
* AgiScripts are used by the AsteriskServer to handle AgiRequests received from
* the Asterisk server.<p>
* To implement functionality using this framework you have to implement this
* interface.<p>
* Note: The implementation of AgiScript must be threadsafe as only one instance
* is used by AsteriskServer to handle all requests to a resource.
*
* @author srt
* @version $Id: AgiScript.java 938 2007-12-31 03:23:38Z srt $
*/
public interface AgiScript
{
/**
* The service method is called by the AsteriskServer whenever this
* AgiScript should handle an incoming AgiRequest.
*
* @param request the initial data received from Asterisk when requesting
* this script.
* @param channel a handle to communicate with Asterisk such as sending
* commands to the channel sending the request.
*
* @throws AgiException any exception thrown by your script will be logged.
*/
void service(final AgiRequest request, final AgiChannel channel) throws AgiException;
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import java.io.IOException;
/**
* Listens for incoming AGI connections, reads the inital data and builds an
* {@link AgiRequest} that is then handed over to the appropriate
* {@link org.asteriskjava.fastagi.AgiScript} for processing.
*
* @see org.asteriskjava.fastagi.AgiServerThread
* @author srt
* @version $Id: AgiServer.java 938 2007-12-31 03:23:38Z srt $
*/
public interface AgiServer
{
/**
* Starts this AgiServer.<p>
* After calling startup() this AgiServer is ready to receive requests from
* Asterisk servers and process them.<p>
* Note that this method will not return until the AgiServer has been shut down.
* If you want to run the AgiServer in the background use wrap it with an
* {@link AgiServerThread}.
*
* @throws IOException if the server socket cannot be bound.
* @throws IllegalStateException if this AgiServer is already running.
*/
void startup() throws IOException, IllegalStateException;
/**
* Stops this AgiServer.<p>
* The server socket is closed, new connections are refused and resources
* are freed. Any running {@link AgiScript}s are finish before shutdown
* completes.
*
* @throws IllegalStateException if this AgiServer is already shut down or
* has not yet been started.
*/
void shutdown() throws IllegalStateException;
}

View File

@ -0,0 +1,193 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.atomic.AtomicLong;
import org.asteriskjava.util.Log;
import org.asteriskjava.util.LogFactory;
/**
* Runs an AgiServer in a separate Thread.
* <p>
* You can use this class to run an AgiServer in the background of your
* application or run it in your servlet container or application server.
* <p>
* By default the thread used by this class is marked as daemon thread, that
* means it will be destroyed when the last user thread has finished.
*
* @author srt
* @version $Id: AgiServerThread.java 938 2007-12-31 03:23:38Z srt $
* @since 0.2
*/
public class AgiServerThread
{
private final Log logger = LogFactory.getLog(getClass());
private static AtomicLong idCounter = new AtomicLong();
private AgiServer agiServer;
private Thread thread;
private boolean daemon = true;
/**
* Creates a new AgiServerThread.
* <p>
* Before you can run this thread you must set an {@link AgiServer} using
* {@link #setAgiServer(AgiServer)}.
* <p>
* This constructor is mainly intended for use with setter based dependency
* injection.
*/
public AgiServerThread()
{
super();
}
/**
* Creates a new AgiServerThread that runs the given {@link AgiServer}.
*
* @param agiServer the AgiServer to run.
*/
public AgiServerThread(AgiServer agiServer)
{
super();
this.agiServer = agiServer;
}
/**
* Sets the AgiServer to run.
* <p>
* This property must be set before starting the AgiServerThread by calling
* startup.
*
* @param agiServer the AgiServer to run.
*/
public void setAgiServer(AgiServer agiServer)
{
this.agiServer = agiServer;
}
/**
* Marks the thread as either a daemon thread or a user thread.
* <p>
* Default is <code>true</code>.
*
* @param daemon if <code>false</code>, marks the thread as a user
* thread.
* @see Thread#setDaemon(boolean)
* @since 0.3
*/
public void setDaemon(boolean daemon)
{
this.daemon = daemon;
}
/**
* Starts the AgiServer in its own thread.
* <p>
* Note: The AgiServerThread is designed to handle one AgiServer instance at
* a time so calling this method twice without stopping the AgiServer in
* between will result in a RuntimeException.
*
* @throws IllegalStateException if the mandatory property agiServer has not
* been set or the AgiServer had already been started.
* @throws RuntimeException if the AgiServer can't be started due to IO
* problems, for example because the socket has already been
* bound by another process.
*/
public synchronized void startup() throws IllegalStateException, RuntimeException
{
if (agiServer == null)
{
throw new IllegalStateException("Mandatory property agiServer is not set.");
}
if (thread != null)
{
throw new IllegalStateException("AgiServer is already started");
}
thread = createThread();
thread.start();
}
protected Thread createThread()
{
Thread t;
t = new Thread(new Runnable()
{
public void run()
{
try
{
agiServer.startup();
}
catch (Throwable e)
{
throw new RuntimeException("Exception running AgiServer.", e);
}
}
});
t.setName("Asterisk-Java AgiServer-" + idCounter.getAndIncrement());
t.setDaemon(daemon);
t.setUncaughtExceptionHandler(new AgiThreadUncaughtExceptionHanlder());
return t;
}
/**
* Stops the {@link AgiServer}.
* <p>
* The AgiServer must have been started by calling {@link #startup()} before
* you can stop it.
*
* @see AgiServer#shutdown()
* @throws IllegalStateException if the mandatory property agiServer has not
* been set or the AgiServer had already been shut down.
*/
public synchronized void shutdown() throws IllegalStateException
{
if (agiServer == null)
{
throw new IllegalStateException("Mandatory property agiServer is not set.");
}
agiServer.shutdown();
if (thread != null)
{
try
{
thread.join();
}
catch (InterruptedException e)
{
logger.warn("Interrupted while waiting for AgiServer to shutdown.");
}
thread = null; // NOPMD by srt on 7/5/06 11:23 PM
}
}
class AgiThreadUncaughtExceptionHanlder implements UncaughtExceptionHandler
{
public void uncaughtException(Thread t, Throwable e)
{
logger.error("Uncaught exception in AgiServerThread", e);
}
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
/**
* The AgiSpeechException is thrown if a speech command can not be executed
* successfully. The Asterisk Speech API is not very verbose about the reasons for
* a failure so this exception is thrown for all failures of the speech
* recognition engine.
*
* @author srt
* @version $Id: AgiSpeechException.java 1271 2009-03-21 03:41:24Z srt $
* @since 1.0.0
*/
public class AgiSpeechException extends AgiException
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 0L;
/**
* Creates a new AgiSpeechException with the given message.
*
* @param message the message
*/
public AgiSpeechException(String message)
{
super(message);
}
}

View File

@ -0,0 +1,160 @@
package org.asteriskjava.fastagi;
import org.asteriskjava.manager.ManagerEventListener;
import org.asteriskjava.manager.ManagerConnection;
import org.asteriskjava.manager.event.ManagerEvent;
import org.asteriskjava.manager.event.AsyncAgiEvent;
import org.asteriskjava.manager.event.RenameEvent;
import org.asteriskjava.util.Log;
import org.asteriskjava.util.LogFactory;
import org.asteriskjava.fastagi.internal.AsyncAgiConnectionHandler;
import java.util.Map;
import java.util.HashMap;
/**
* AGI server for AGI over the Manager API (AsyncAGI).<p>
* AsyncAGI is available since Asterisk 1.6.
*
* @since 1.0.0
*/
public class AsyncAgiServer extends AbstractAgiServer implements ManagerEventListener
{
private final Log logger = LogFactory.getLog(getClass());
private final Map<Integer, AsyncAgiConnectionHandler> connectionHandlers;
/**
* Creates a new AsyncAgiServer.<p>
* Note that you must set a {@link org.asteriskjava.fastagi.MappingStrategy} before using it.
* @see #setMappingStrategy(MappingStrategy)
*/
public AsyncAgiServer()
{
this.connectionHandlers = new HashMap<Integer, AsyncAgiConnectionHandler>();
}
/**
* Creates a new AsyncAgiServer with the given MappingStrategy.<p>
* Please note that Async AGI does not currently support passing a script name, so your
* MappingStrategy must be aware that the {@link org.asteriskjava.fastagi.AgiRequest#getScript() script}
* property of the AgiRequests will likely be <code>null</code>.
*
* @param mappingStrategy the MappingStrategy to use to determine which AGI script to run
* for a certain request.
*/
public AsyncAgiServer(MappingStrategy mappingStrategy)
{
this();
setMappingStrategy(mappingStrategy);
}
/**
* Creates a new AsyncAgiServer that will execute the given AGI script for every
* request.<p>
* Internally this constructor uses a {@link org.asteriskjava.fastagi.StaticMappingStrategy}.
*
* @param agiScript the AGI script to execute.
*/
public AsyncAgiServer(AgiScript agiScript)
{
this();
setMappingStrategy(new StaticMappingStrategy(agiScript));
}
public void onManagerEvent(ManagerEvent event)
{
if (event instanceof AsyncAgiEvent)
{
handleAsyncAgiEvent((AsyncAgiEvent) event);
}
else if (event instanceof RenameEvent)
{
handleRenameEvent((RenameEvent) event);
}
}
private void handleAsyncAgiEvent(AsyncAgiEvent asyncAgiEvent)
{
final ManagerConnection connection;
final String channelName;
final AsyncAgiConnectionHandler connectionHandler;
connection = (ManagerConnection) asyncAgiEvent.getSource();
channelName = asyncAgiEvent.getChannel();
if (asyncAgiEvent.isStart())
{
connectionHandler = new AsyncAgiConnectionHandler(getMappingStrategy(), asyncAgiEvent);
setConnectionHandler(connection, channelName, connectionHandler);
execute(connectionHandler);
}
else
{
connectionHandler = getConnectionHandler(connection, channelName);
if (connectionHandler == null)
{
logger.info("No AsyncAgiConnectionHandler registered for channel " + channelName + ": Ignoring AsyncAgiEvent");
return;
}
if (asyncAgiEvent.isExec())
{
connectionHandler.onAsyncAgiExecEvent(asyncAgiEvent);
}
else if (asyncAgiEvent.isEnd())
{
connectionHandler.onAsyncAgiEndEvent(asyncAgiEvent);
removeConnectionHandler(connection, channelName);
}
else
{
logger.warn("Ignored unknown AsyncAgiEvent of sub type '" + asyncAgiEvent.getSubEvent() + "'");
}
}
}
private void handleRenameEvent(RenameEvent renameEvent)
{
final ManagerConnection connection = (ManagerConnection) renameEvent.getSource();
final AsyncAgiConnectionHandler connectionHandler = getConnectionHandler(connection, renameEvent.getChannel());
if (connectionHandler == null)
{
return;
}
removeConnectionHandler(connection, renameEvent.getChannel());
setConnectionHandler(connection, renameEvent.getNewname(), connectionHandler);
connectionHandler.updateChannelName(renameEvent.getNewname());
}
private AsyncAgiConnectionHandler getConnectionHandler(ManagerConnection connection, String channelName)
{
synchronized (connectionHandlers)
{
return connectionHandlers.get(calculateHashKey(connection, channelName));
}
}
private void setConnectionHandler(ManagerConnection connection, String channelName, AsyncAgiConnectionHandler connectionHandler)
{
synchronized (connectionHandlers)
{
connectionHandlers.put(calculateHashKey(connection, channelName), connectionHandler);
}
}
private void removeConnectionHandler(ManagerConnection connection, String channelName)
{
synchronized (connectionHandlers)
{
connectionHandlers.remove(calculateHashKey(connection, channelName));
}
}
private Integer calculateHashKey(ManagerConnection connection, String channelName)
{
return connection.hashCode() * 31 + channelName.hashCode();
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
/**
* The BaseAgiScript provides some convinience methods to make it easier to
* write custom {@link org.asteriskjava.fastagi.AgiScript}s.
* <p>
* Just extend it by your own script classes.
*
* @since 0.2
* @author srt
* @version $Id: BaseAgiScript.java 938 2007-12-31 03:23:38Z srt $
*/
public abstract class BaseAgiScript extends AgiOperations implements AgiScript
{
public BaseAgiScript()
{
super();
}
}

View File

@ -0,0 +1,109 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import java.util.HashMap;
import java.util.Map;
/**
* A MappingStrategy that determines the AGIScript based on the fully
* qualified class name given in the AGI URL.<p>
* To use this ClassNameMappingStrategy the calls to your
* {@link org.asteriskjava.fastagi.AgiScript} in
* your dialplan should look like this:
* <pre>
* exten => 123,1,AGI(agi://your.server.com/com.example.agi.MyScript)
* </pre>
* Where com.example.agi.MyScript is the fully qualified name of your
* AgiScript.
*
* @author srt
* @version $Id: ClassNameMappingStrategy.java 1140 2008-08-18 18:49:36Z srt $
*/
public class ClassNameMappingStrategy extends AbstractMappingStrategy
{
private Map<String, AgiScript> instances;
private boolean shareInstances;
/**
* Creates a new ClassNameMappingStrategy using shared instances.
*/
public ClassNameMappingStrategy()
{
this(true);
}
/**
* Creates a new ClassNameMappingStrategy indicating whether to use shared
* instances or not.
*
* @param shareInstances <code>true</code> to use shared instances,
* <code>false</code> to create a new instance for
* each request.
* @since 0.3
*/
public ClassNameMappingStrategy(boolean shareInstances)
{
super();
this.instances = new HashMap<String, AgiScript>();
this.shareInstances = shareInstances;
}
/**
* Sets whether to use shared instances or not. If set to <code>true</code>
* all AGIRequests are served by the same instance of an
* AGIScript, if set to <code>false</code> a new instance is created for
* each request.<p>
* Default is <code>true</code>.
*
* @param shareInstances <code>true</code> to use shared instances,
* <code>false</code> to create a new instance for
* each request.
* @since 0.3
*/
public synchronized void setShareInstances(boolean shareInstances)
{
this.shareInstances = shareInstances;
}
public synchronized AgiScript determineScript(AgiRequest request)
{
AgiScript script;
if (shareInstances)
{
script = instances.get(request.getScript());
if (script != null)
{
return script;
}
}
script = createAgiScriptInstance(request.getScript());
if (script == null)
{
return null;
}
if (shareInstances)
{
instances.put(request.getScript(), script);
}
return script;
}
}

View File

@ -0,0 +1,123 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
/**
* A mapping strategy that tries a sequence of other mapping strategies to find
* an AgiScript matching the request. The first strategy that returns a result wins,
* so the order of the mapping strategies passed to the CompositeMappingStrategy
* matters.<p>
* Example:
* <pre>
* new CompositeMappingStrategy(
* new ResourceBundleMappingStrategy(),
* new ClassNameMappingStrategy());
* </pre>
* This creates a new mapping strategy that first tries to look up the script
* in <code>fastagi-mapping.properties</code> and - if the properties file is
* not present on the classpath or contains no mapping for the request - uses
* a {@link ClassNameMappingStrategy} to get the script.
*
* @see ResourceBundleMappingStrategy
* @see ClassNameMappingStrategy
* @author srt
* @since 0.3
* @version $Id: CompositeMappingStrategy.java 1015 2008-04-04 21:56:36Z srt $
*/
public class CompositeMappingStrategy implements MappingStrategy
{
private List<MappingStrategy> strategies;
/**
* Creates a new empty CompositeMappingStrategy.
*/
public CompositeMappingStrategy()
{
super();
}
/**
* Creates a new CompositeMappingStrategy.
*
* @param strategies the strategies to use.
*/
public CompositeMappingStrategy(MappingStrategy... strategies)
{
super();
this.strategies = new ArrayList<MappingStrategy>(Arrays.asList(strategies));
}
/**
* Creates a new CompositeMappingStrategy.
*
* @param strategies the strategies to use.
*/
public CompositeMappingStrategy(List<MappingStrategy> strategies)
{
super();
this.strategies = new ArrayList<MappingStrategy>(strategies);
}
/**
* Adds a strategy (at the end of the list).
*
* @param strategy the strategy to add.
*/
public void addStrategy(MappingStrategy strategy)
{
if (strategies == null)
{
strategies = new ArrayList<MappingStrategy>();
}
strategies.add(strategy);
}
/**
* Sets the strategies to use.
*
* @param strategies the strategies to use.
*/
public void setStrategies(List<MappingStrategy> strategies)
{
this.strategies = new ArrayList<MappingStrategy>(strategies);
}
public AgiScript determineScript(AgiRequest request)
{
AgiScript script = null;
if (strategies == null)
{
return null;
}
for (MappingStrategy strategy : strategies)
{
script = strategy.determineScript(request);
if (script != null)
{
break;
}
}
return script;
}
}

View File

@ -0,0 +1,338 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import org.asteriskjava.fastagi.internal.AgiConnectionHandler;
import org.asteriskjava.fastagi.internal.FastAgiConnectionHandler;
import org.asteriskjava.util.*;
import org.asteriskjava.util.internal.ServerSocketFacadeImpl;
import java.io.IOException;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
/**
* Default implementation of the {@link org.asteriskjava.fastagi.AgiServer} interface for FastAGI.
*
* @author srt
* @version $Id: DefaultAgiServer.java 1304 2009-05-12 22:51:12Z srt $
*/
public class DefaultAgiServer extends AbstractAgiServer implements AgiServer
{
private final Log logger = LogFactory.getLog(getClass());
/**
* The default name of the resource bundle that contains the config.
*/
private static final String DEFAULT_CONFIG_RESOURCE_BUNDLE_NAME = "fastagi";
/**
* The default bind port.
*/
private static final int DEFAULT_BIND_PORT = 4573;
private ServerSocketFacade serverSocket;
private String configResourceBundleName = DEFAULT_CONFIG_RESOURCE_BUNDLE_NAME;
private int port = DEFAULT_BIND_PORT;
/**
* Creates a new DefaultAgiServer.
*/
public DefaultAgiServer()
{
this(null, null);
}
/**
* Creates a new DefaultAgiServer and loads its configuration from an alternative resource bundle.
*
* @param configResourceBundleName the name of the conifiguration resource bundle (default is "fastagi").
*/
public DefaultAgiServer(String configResourceBundleName)
{
this(configResourceBundleName, null);
}
/**
* Creates a new DefaultAgiServer that uses the given {@link MappingStrategy}.
*
* @param mappingStrategy the MappingStrategy to use to determine the AgiScript to run.
* @since 1.0.0
*/
public DefaultAgiServer(MappingStrategy mappingStrategy)
{
this(null, mappingStrategy);
}
/**
* Creates a new DefaultAgiServer that runs the given {@link AgiScript} for all requests.
*
* @param agiScript the AgiScript to run.
* @since 1.0.0
*/
public DefaultAgiServer(AgiScript agiScript)
{
this(null, new StaticMappingStrategy(agiScript));
}
/**
* Creates a new DefaultAgiServer and loads its configuration from an alternative resource bundle and
* uses the given {@link MappingStrategy}.
*
* @param configResourceBundleName the name of the conifiguration resource bundle (default is "fastagi").
* @param mappingStrategy the MappingStrategy to use to determine the AgiScript to run.
* @since 1.0.0
*/
public DefaultAgiServer(String configResourceBundleName, MappingStrategy mappingStrategy)
{
super();
if (mappingStrategy == null)
{
final CompositeMappingStrategy compositeMappingStrategy = new CompositeMappingStrategy();
compositeMappingStrategy.addStrategy(new ResourceBundleMappingStrategy());
compositeMappingStrategy.addStrategy(new ClassNameMappingStrategy());
if (ReflectionUtil.isClassAvailable("javax.script.ScriptEngineManager"))
{
MappingStrategy scriptEngineMappingStrategy =
(MappingStrategy) ReflectionUtil.newInstance("org.asteriskjava.fastagi.ScriptEngineMappingStrategy");
if (scriptEngineMappingStrategy != null)
{
compositeMappingStrategy.addStrategy(scriptEngineMappingStrategy);
}
}
else
{
logger.warn("ScriptEngine support disabled: It is only availble when running at least Java 6");
}
setMappingStrategy(compositeMappingStrategy);
}
else
{
setMappingStrategy(mappingStrategy);
}
if (configResourceBundleName != null)
{
this.configResourceBundleName = configResourceBundleName;
}
loadConfig();
}
/**
* Sets the TCP port to listen on for new connections.
* <p/>
* The default port is 4573.
*
* @param bindPort the port to bind to.
* @deprecated use {@see #setPort(int)} instead
*/
public void setBindPort(int bindPort)
{
this.port = bindPort;
}
/**
* Sets the TCP port to listen on for new connections.
* <p/>
* The default port is 4573.
*
* @param port the port to bind to.
* @since 0.2
*/
public void setPort(int port)
{
this.port = port;
}
/**
* Returns the TCP port this server is configured to bind to.
*
* @return the TCP port this server is configured to bind to.
* @since 1.0.0
*/
public int getPort()
{
return port;
}
private void loadConfig()
{
final ResourceBundle resourceBundle;
try
{
resourceBundle = ResourceBundle.getBundle(configResourceBundleName);
}
catch (MissingResourceException e)
{
return;
}
try
{
String portString;
try
{
portString = resourceBundle.getString("port");
}
catch (MissingResourceException e)
{
// for backward compatibility only
portString = resourceBundle.getString("bindPort");
}
port = Integer.parseInt(portString);
}
catch (Exception e) // NOPMD
{
// swallow
}
try
{
setPoolSize(Integer.parseInt(resourceBundle.getString("poolSize")));
}
catch (Exception e) // NOPMD
{
// swallow
}
try
{
setMaximumPoolSize(Integer.parseInt(resourceBundle.getString("maximumPoolSize")));
}
catch (Exception e) // NOPMD
{
// swallow
}
}
protected ServerSocketFacade createServerSocket() throws IOException
{
return new ServerSocketFacadeImpl(port, 0, null);
}
public void startup() throws IOException, IllegalStateException
{
SocketConnectionFacade socket;
AgiConnectionHandler connectionHandler;
try
{
serverSocket = createServerSocket();
}
catch (IOException e)
{
logger.error("Unable start AgiServer: cannot to bind to *:" + port + ".", e);
throw e;
}
logger.info("Listening on *:" + port + ".");
// loop will be terminated by accept() throwing an IOException when the
// ServerSocket is closed.
while (true)
{
try
{
socket = serverSocket.accept();
logger.info("Received connection from " + socket.getRemoteAddress());
connectionHandler = new FastAgiConnectionHandler(getMappingStrategy(), socket);
execute(connectionHandler);
}
catch (IOException e)
{
// swallow only if shutdown
if (isDie())
{
break;
}
else
{
logger.error("IOException while waiting for connections.", e);
// log error but continue
}
}
}
logger.info("AgiServer shut down.");
}
public void run()
{
try
{
startup();
}
catch (IOException e) // NOPMD
{
// nothing we can do about that and exceptions have already been logged
// by startup().
}
}
@Override
public void shutdown() throws IllegalStateException
{
// setting the death flag causes the accept() loop to exit when a
// SocketException occurs.
super.shutdown();
if (serverSocket != null)
{
try
{
// closes the server socket and throws a SocketException on
// Threads waiting in accept()
serverSocket.close();
}
catch (IOException e)
{
logger.warn("IOException while closing server socket.", e);
}
}
}
@Override
protected void finalize() throws Throwable
{
super.finalize();
if (serverSocket != null)
{
try
{
serverSocket.close();
}
catch (IOException e) // NOPMD
{
// swallow
}
}
}
public static void main(String[] args) throws Exception
{
final AgiServer server;
server = new DefaultAgiServer();
server.startup();
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
/**
* An InvalidCommandSyntaxException is thrown when the reader receives a reply
* with status code 520.
*
* @author srt
* @version $Id: InvalidCommandSyntaxException.java 938 2007-12-31 03:23:38Z srt $
*/
public class InvalidCommandSyntaxException extends AgiException
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3257002168165807929L;
private final String synopsis;
private final String usage;
/**
* Creates a new InvalidCommandSyntaxException with the given synopsis and
* usage.
*
* @param synopsis the synopsis of the command.
* @param usage the usage of the command.
*/
public InvalidCommandSyntaxException(String synopsis, String usage)
{
super("Invalid command syntax: " + synopsis);
this.synopsis = synopsis;
this.usage = usage;
}
/**
* Returns the synopsis of the command that was called with invalid syntax.
*
* @return the synopsis of the command that was called with invalid syntax.
*/
public String getSynopsis()
{
return synopsis;
}
/**
* Returns a description of the command that was called with invalid syntax.
*
* @return a description of the command that was called with invalid syntax.
*/
public String getUsage()
{
return usage;
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
/**
* An InvalidOrUnknownCommandException is thrown when the reader receives a reply
* with status code 510.
*
* @author srt
* @version $Id: InvalidOrUnknownCommandException.java 938 2007-12-31 03:23:38Z srt $
*/
public class InvalidOrUnknownCommandException extends AgiException
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3257002168165807929L;
/**
* Creates a new InvalidOrUnknownCommandException.
*
* @param command the invalid or unknown command.
*/
public InvalidOrUnknownCommandException(String command)
{
super("Invalid or unknown command: " + command);
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
/**
* A MappingStrategy determines which {@link org.asteriskjava.fastagi.AgiScript}
* is called to service a given {@link org.asteriskjava.fastagi.AgiRequest}.<p>
* A MappingStrategy can use any of the properties
* of an AgiRequest to do this. However most MappingStrategies will just use
* the script property, that is the name of the invoked AGI script as passed
* from Asterisk's dialplan.<p>
* Asterisk-Java ships with several mapping strategies that are available out
* of the box. If you have some special requirements that are not satisfied by
* any of the available strategies feel free to implement this interface and
* use your own strategy.
*
* @author srt
* @version $Id: MappingStrategy.java 938 2007-12-31 03:23:38Z srt $
*/
public interface MappingStrategy
{
/**
* Returns the AgiScript instance that is responsible to handle
* the given request.
*
* @param request the request to lookup.
* @return the AgiScript instance to handle this request
* or <code>null</code> if none could be determined by this strategy.
*/
AgiScript determineScript(AgiRequest request);
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
/**
* Interface for an AgiScript that provides a name for logging and management.
*
* @since 1.0.0
*/
public interface NamedAgiScript extends AgiScript
{
/**
* Returns the name of the script.
*
* @return the name of the script
*/
String getName();
}

View File

@ -0,0 +1,197 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import java.util.*;
/**
* A MappingStrategy that is configured via a resource bundle.<p>
* The resource bundle contains the script part of the url as key and the fully
* qualified class name of the corresponding AgiScript as value.<p>
* Example:
*
* <pre>
* leastcostdial.agi = com.example.fastagi.LeastCostDialAgiScript
* hello.agi = com.example.fastagi.HelloAgiScript
* </pre>
*
* LeastCostDialAgiScript and HelloAgiScript must both implement the AgiScript
* interface and have a default constructor with no parameters.<p>
* The resource bundle (properties) file is called
* <code>fastagi-mapping.properties</code> by default and must be available on
* the classpath.
*
* @author srt
* @version $Id: ResourceBundleMappingStrategy.java 1140 2008-08-18 18:49:36Z srt $
*/
public class ResourceBundleMappingStrategy extends AbstractMappingStrategy
{
private static final String DEFAULT_RESOURCE_BUNDLE_NAME = "fastagi-mapping";
private String resourceBundleName;
private Map<String, String> mappings;
private Map<String, AgiScript> instances;
private boolean shareInstances;
/**
* Creates a new ResourceBundleMappingStrategy using shared instances..
*/
public ResourceBundleMappingStrategy()
{
this(DEFAULT_RESOURCE_BUNDLE_NAME);
}
/**
* Creates a new ResourceBundleMappingStrategy with the given basename
* of the resource bundle to use.
*
* @param resourceBundleName basename of the resource bundle to use
*/
public ResourceBundleMappingStrategy(String resourceBundleName)
{
this(resourceBundleName, true);
}
/**
* Creates a new ResourceBundleMappingStrategy indicating whether to use shared
* instances or not.
*
* @param shareInstances <code>true</code> to use shared instances,
* <code>false</code> to create a new instance for
* each request.
* @since 0.3
*/
public ResourceBundleMappingStrategy(boolean shareInstances)
{
this(DEFAULT_RESOURCE_BUNDLE_NAME, shareInstances);
}
/**
* Creates a new ResourceBundleMappingStrategy with the given basename
* of the resource bundle to use and indicating whether to use shared
* instances or not.
*
* @param resourceBundleName basename of the resource bundle to use
* @param shareInstances <code>true</code> to use shared instances,
* <code>false</code> to create a new instance for
* each request.
* @since 0.3
*/
public ResourceBundleMappingStrategy(String resourceBundleName, boolean shareInstances)
{
super();
this.resourceBundleName = resourceBundleName;
this.shareInstances = shareInstances;
}
/**
* Sets the basename of the resource bundle to use.<p>
* Default is "fastagi-mapping".
*
* @param resourceBundleName basename of the resource bundle to use
*/
public void setResourceBundleName(String resourceBundleName)
{
this.resourceBundleName = resourceBundleName;
synchronized (this)
{
this.mappings = null;
this.instances = null;
}
}
/**
* Sets whether to use shared instances or not. If set to <code>true</code>
* all AgiRequests are served by the same instance of an
* AgiScript, if set to <code>false</code> a new instance is created for
* each request.<p>
* Default is <code>true</code>.
*
* @param shareInstances <code>true</code> to use shared instances,
* <code>false</code> to create a new instance for
* each request.
* @since 0.3
*/
public synchronized void setShareInstances(boolean shareInstances)
{
this.shareInstances = shareInstances;
}
private synchronized void loadResourceBundle()
{
ResourceBundle resourceBundle;
Enumeration keys;
mappings = new HashMap<String, String>();
if (shareInstances)
{
instances = new HashMap<String, AgiScript>();
}
try
{
resourceBundle = ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(), getClassLoader());
}
catch (MissingResourceException e)
{
logger.info("Resource bundle '" + resourceBundleName + "' not found.");
return;
}
keys = resourceBundle.getKeys();
while (keys.hasMoreElements())
{
String scriptName;
String className;
AgiScript agiScript;
scriptName = (String) keys.nextElement();
className = resourceBundle.getString(scriptName);
mappings.put(scriptName, className);
if (shareInstances)
{
agiScript = createAgiScriptInstance(className);
if (agiScript == null)
{
continue;
}
instances.put(scriptName, agiScript);
}
logger.info("Added mapping for '" + scriptName + "' to class " + className);
}
}
public synchronized AgiScript determineScript(AgiRequest request)
{
if (mappings == null || (shareInstances && instances == null))
{
loadResourceBundle();
}
if (shareInstances)
{
return instances.get(request.getScript());
}
else
{
return createAgiScriptInstance(mappings.get(request.getScript()));
}
}
}

View File

@ -0,0 +1,385 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import org.asteriskjava.util.LogFactory;
import org.asteriskjava.util.Log;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.Bindings;
import javax.script.ScriptException;
import java.io.*;
import java.util.regex.Matcher;
import java.util.List;
import java.util.ArrayList;
import java.net.URLClassLoader;
import java.net.URL;
import java.net.MalformedURLException;
/**
* A MappingStrategy that uses {@see javax.script.ScriptEngine} to run AgiScripts. This MappingStrategy
* can be used to run JavaScript, Groovy, JRuby, etc. scripts.
*
* @since 1.0.0
*/
public class ScriptEngineMappingStrategy implements MappingStrategy
{
protected final Log logger = LogFactory.getLog(getClass());
/**
* The binding under which the AGI request is made available to scripts.
*/
public static final String REQUEST = "request";
/**
* The binding under which the AGI channel is made available to scripts.
*/
public static final String CHANNEL = "channel";
private static final String[] DEFAULT_SCRIPT_PATH = new String[]{"agi"};
private static final String[] DEFAULT_LIB_PATH = new String[]{"lib"};
protected String[] scriptPath;
protected String[] libPath;
protected ScriptEngineManager scriptEngineManager = null;
/**
* Creates a new ScriptEngineMappingStrategy that searches for scripts in the current directory.
*/
public ScriptEngineMappingStrategy()
{
this(DEFAULT_SCRIPT_PATH, DEFAULT_LIB_PATH);
}
/**
* Creates a new ScriptEngineMappingStrategy that searches for scripts on the given path.
*
* @param scriptPath array of directory names to search for script files.
* @param libPath array of directory names to search for additional libraries (jar files).
*/
public ScriptEngineMappingStrategy(String[] scriptPath, String[] libPath)
{
this.scriptPath = scriptPath;
this.libPath = libPath;
}
/**
* Sets the path to search for script files.<p>
* Default is "agi".
*
* @param scriptPath array of directory names to search for script files.
*/
public void setScriptPath(String[] scriptPath)
{
this.scriptPath = scriptPath;
}
/**
* Sets the path to search for additional libraries (jar files).<p>
* Default is "lib".
*
* @param libPath array of directory names to search for additional libraries (jar files).
*/
public void setLibPath(String[] libPath)
{
this.libPath = libPath;
}
public AgiScript determineScript(AgiRequest request)
{
// check is a file corresponding to the AGI request is found on the scriptPath
final File file = searchFile(request.getScript(), scriptPath);
if (file == null)
{
return null;
}
// check if there is a ScriptEngine that can handle the file
final ScriptEngine scriptEngine = getScriptEngine(file);
if (scriptEngine == null)
{
logger.debug("No ScriptEngine found that can handle '" + file.getPath() + "'");
return null;
}
return new ScriptEngineAgiScript(file, scriptEngine);
}
/**
* Searches for a ScriptEngine that can handle the given file.
*
* @param file the file to search a ScriptEngine for.
* @return the ScriptEngine or <code>null</code> if none is found.
*/
protected ScriptEngine getScriptEngine(File file)
{
final String extension = getExtension(file.getName());
if (extension == null)
{
return null;
}
return getScriptEngineManager().getEngineByExtension(extension);
}
/**
* Returns the ScriptEngineManager to use for loading the ScriptEngine. The ScriptEngineManager is only
* created once and reused for subsequent requests. Override this method to provide your own implementation.
*
* @return the ScriptEngineManager to use for loading the ScriptEngine.
* @see javax.script.ScriptEngineManager#ScriptEngineManager()
*/
protected synchronized ScriptEngineManager getScriptEngineManager()
{
if (scriptEngineManager == null)
{
this.scriptEngineManager = new ScriptEngineManager(getClassLoader());
}
return scriptEngineManager;
}
/**
* Returns the ClassLoader to use for the ScriptEngineManager. Adds all jar files in the "lib" subdirectory of
* the current directory to the class path. Override this method to provide your own ClassLoader.
*
* @return the ClassLoader to use for the ScriptEngineManager.
* @see #getScriptEngineManager()
*/
protected ClassLoader getClassLoader()
{
final ClassLoader parentClassLoader = Thread.currentThread().getContextClassLoader();
final List<URL> jarFileUrls = new ArrayList<URL>();
if (libPath == null || libPath.length == 0)
{
return parentClassLoader;
}
for (String libPathEntry : libPath)
{
final File libDir = new File(libPathEntry);
if (!libDir.isDirectory())
{
continue;
}
final File[] jarFiles = libDir.listFiles(new FilenameFilter()
{
public boolean accept(File dir, String name)
{
return name.endsWith(".jar");
}
});
for (File jarFile : jarFiles)
{
try
{
jarFileUrls.add(jarFile.toURI().toURL());
}
catch (MalformedURLException e)
{
// should not happen
}
}
}
if (jarFileUrls.size() == 0)
{
return parentClassLoader;
}
return new URLClassLoader(jarFileUrls.toArray(new URL[jarFileUrls.size()]), parentClassLoader);
}
/**
* Searches for the file with the given name on the path.
*
* @param scriptName the name of the file to search for.
* @param path an array of directories to search for the file in order of preference.
* @return the canonical file if found on the path or <code>null</code> if not found.
*/
protected File searchFile(String scriptName, String[] path)
{
if (scriptName == null || path == null)
{
return null;
}
for (String pathElement : path)
{
final File pathElementDir = new File(pathElement);
// skip if pathElement is not a directory
if (!pathElementDir.isDirectory())
{
continue;
}
final File file = new File(pathElementDir, scriptName.replaceAll("/", Matcher.quoteReplacement(File.separator)));
if (!file.exists())
{
continue;
}
try
{
// prevent attacks with scripts using ".." in their name.
if (!isInside(file, pathElementDir))
{
return null;
}
}
catch (IOException e)
{
logger.warn("Unable to check whether '" + file.getPath() + "' is below '" + pathElementDir.getPath() + "'");
continue;
}
try
{
return file.getCanonicalFile();
}
catch (IOException e)
{
logger.error("Unable to get canonical file for '" + file.getPath() + "'", e);
}
}
return null;
}
/**
* Checks whether a file is contained within a given directory (or a sub directory) or not.
*
* @param file the file to check.
* @param dir the directory to check.
* @return <code>true</code> if file is below directory, <code>false</code> otherwise.
* @throws IOException if the canonical path of file or dir cannot be determined.
*/
protected final boolean isInside(File file, File dir) throws IOException
{
return file.getCanonicalPath().startsWith(dir.getCanonicalPath());
}
/**
* Returns the extension (the part after the last ".") of the given script.
*
* @param scriptName the name of the script to return the extension of.
* @return the extension of the script or <code>null</code> if there is no extension.
*/
protected static String getExtension(String scriptName)
{
if (scriptName == null)
{
return null;
}
int filePosition = scriptName.lastIndexOf("/");
String fileName;
if (scriptName.lastIndexOf("\\") > filePosition)
{
filePosition = scriptName.lastIndexOf("\\");
}
if (filePosition >= 0)
{
fileName = scriptName.substring(filePosition + 1);
}
else
{
fileName = scriptName;
}
final int extensionPosition = fileName.lastIndexOf(".");
if (extensionPosition >= 0)
{
return fileName.substring(extensionPosition + 1);
}
return null;
}
protected static Reader getReader(File file) throws FileNotFoundException
{
final InputStream is = new FileInputStream(file);
return new InputStreamReader(is);
}
protected class ScriptEngineAgiScript implements NamedAgiScript
{
final File file;
final ScriptEngine scriptEngine;
/**
* Creates a new ScriptEngineAgiScript.
*
* @param file the file that contains the script to execute.
* @param scriptEngine the ScriptEngine to use for executing the script.
*/
public ScriptEngineAgiScript(File file, ScriptEngine scriptEngine)
{
this.file = file;
this.scriptEngine = scriptEngine;
}
public String getName()
{
return file == null ? null : file.getName();
}
public void service(AgiRequest request, AgiChannel channel) throws AgiException
{
final Bindings bindings = scriptEngine.createBindings();
bindings.put(ScriptEngine.FILENAME, file.getPath());
bindings.put(REQUEST, request);
bindings.put(CHANNEL, channel);
// support for custom bindings
populateBindings(file, request, channel, bindings);
try
{
scriptEngine.eval(getReader(file), bindings);
}
catch (ScriptException e)
{
throw new AgiException("Execution of script '" + file.getPath() + "' with ScriptEngine failed", e);
}
catch (FileNotFoundException e)
{
throw new AgiException("Script '" + file.getPath() + "' not found", e);
}
}
}
/**
* Override this method if you want to add additional bindings before the script is run. By default the
* AGI request, AGI channel and the filename are available to scripts under the bindings "request", "channel"
* and "javax.script.filename".
*
* @param file the script file.
* @param request the AGI request.
* @param channel the AGI channel.
* @param bindings the bindings to populate.
*/
protected void populateBindings(File file, AgiRequest request, AgiChannel channel, Bindings bindings)
{
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi;
import java.util.Map;
/**
* A MappingStrategy that is configured via a fixed set of properties.<p>
* This mapping strategy is most useful when used with the Spring framework.<p>
* Example (using Spring):
*
* <pre>
* &lt;beans&gt;
* &lt;bean id="mapping"
* class="org.asteriskjava.fastagi.SimpleMappingStrategy"&gt;
* &lt;property name="mappings"&gt;
* &lt;map&gt;
* &lt;entry&gt;
* &lt;key&gt;&lt;value&gt;hello.agi&lt;/value&gt;&lt;/key&gt;
* &lt;ref local="hello"/&gt;
* &lt;/entry&gt;
* &lt;entry&gt;
* &lt;key&gt;&lt;value&gt;leastcostdial.agi&lt;/value&gt;&lt;/key&gt;
* &lt;ref local="leastCostDial"/&gt;
* &lt;/entry&gt;
* &lt;/map&gt;
* &lt;/property&gt;
* &lt;/bean&gt;
*
* &lt;bean id="hello"
* class="com.example.fastagi.HelloAgiScript"/&gt;
*
* &lt;bean id="leastCostDial"
* class="com.example.fastagi.LeastCostDialAgiScript"&gt;
* &lt;property name="rates"&gt;&lt;value&gt;rates.txt&lt;/value&gt;&lt;/property&gt;
* &lt;/bean&gt;
* &lt;beans&gt;
* </pre>
*
* LeastCostDialAgiScript and HelloAgiScript must both implement the AgiScript.<p>
*
* @author srt
* @version $Id: SimpleMappingStrategy.java 938 2007-12-31 03:23:38Z srt $
* @since 0.2
*/
public class SimpleMappingStrategy implements MappingStrategy
{
private Map<String, AgiScript> mappings;
/**
* Set the "path to AgiScript" mapping.<p>
* Use the path (for example <code>hello.agi</code>) as key and your
* AgiScript (for example <code>new HelloAgiScript()</code>) as value of
* this map.
*
* @param mappings the path to AgiScript mapping.
*/
public void setMappings(Map<String, AgiScript> mappings)
{
this.mappings = mappings;
}
public AgiScript determineScript(AgiRequest request)
{
if (mappings == null)
{
return null;
}
return mappings.get(request.getScript());
}
}

View File

@ -0,0 +1,238 @@
package org.asteriskjava.fastagi;
import org.asteriskjava.fastagi.reply.AgiReply;
import java.util.List;
import java.util.ArrayList;
import java.io.Serializable;
/**
* Contains the results of a speech recognition command.
*
* @see org.asteriskjava.fastagi.AgiChannel#speechRecognize(String, int)
* @see org.asteriskjava.fastagi.AgiChannel#speechRecognize(String, int, int)
* @see org.asteriskjava.fastagi.command.SpeechRecognizeCommand
* @since 1.0.0
*/
public class SpeechRecognitionResult implements Serializable
{
private static final long serialVersionUID = 0L;
private final AgiReply agiReply;
public SpeechRecognitionResult(AgiReply agiReply)
{
this.agiReply = agiReply;
}
/**
* Checks whether a DTMF digit was recieved.
*
* @return <code>true</code> if a DTMF digit was received, <code>false</code> otherwise.
* @see #getDigit()
*/
public boolean isDtmf()
{
return "digit".equals(agiReply.getExtra());
}
/**
* Checks whether speech was recognized.
*
* @return <code>true</code> if speech was recognized, <code>false</code> otherwise.
* @see #getText()
* @see #getScore()
* @see #getGrammar()
*/
public boolean isSpeech()
{
return "speech".equals(agiReply.getExtra());
}
/**
* Checks whether a timeout was encountered and neither a DTMF digit was received nor speech was recognized.
*
* @return <code>true</code> a timeout was encountered, <code>false</code> otherwise.
*/
public boolean isTimeout()
{
return "timeout".equals(agiReply.getExtra());
}
/**
* Returns the DTMF digit that was received.
*
* @return the DTMF digit that was received or 0x0 if none was received.
*/
public char getDigit()
{
final String digit = agiReply.getAttribute("digit");
if (digit == null || digit.length() == 0)
{
return 0x0;
}
return digit.charAt(0);
}
/**
* Returns the position where the prompt stopped playing because a DTMF digit was received or speech was
* recognized (barge in).
*
* @return the position where the prompt stopped playing, 0 if it was played completely.
*/
public int getEndpos()
{
return Integer.valueOf(agiReply.getAttribute("endpos"));
}
/**
* Returns the confidence score for the first recognition result. This is an integer between 0 (lowest confidence)
* and 1000 (highest confidence).
*
* @return the confidence score for the first recognition result or 0 if no speech was recognized.
*/
public int getScore()
{
final String score0 = agiReply.getAttribute("score0");
return score0 == null ? 0 : Integer.valueOf(score0);
}
/**
* Returns the text for the first recognition result. This is the text that was recognized by the speech engine.
*
* @return the text for the first recognition result or <code>null</code> if no speech was recognized.
*/
public String getText()
{
return agiReply.getAttribute("text0");
}
/**
* Returns the grammar for the first recognition result. This is the grammar that was used by the speech engine.
*
* @return the grammar for the first recognition result or <code>null</code> if no speech was recognized.
*/
public String getGrammar()
{
return agiReply.getAttribute("grammar0");
}
/**
* Returns how many results have been recoginized. Usually there is only one result but if multiple rules in
* the grammar match multiple results may be returned.
*
* @return the number of results recognized.
*/
public int getNumberOfResults()
{
final String numberOfResults = agiReply.getAttribute("results");
return numberOfResults == null ? 0 : Integer.valueOf(numberOfResults);
}
public List<SpeechResult> getAllResults()
{
final int numberOfResults = getNumberOfResults();
final List<SpeechResult> results = new ArrayList<SpeechResult>(numberOfResults);
for (int i = 0; i < numberOfResults; i++)
{
SpeechResult result = new SpeechResult(
Integer.valueOf(agiReply.getAttribute("score" + i)),
agiReply.getAttribute("text" + i),
agiReply.getAttribute("grammar" + i)
);
results.add(result);
}
return results;
}
public String toString()
{
final StringBuilder sb = new StringBuilder("SpeechRecognitionResult[");
if (isDtmf())
{
sb.append("dtmf=true,");
sb.append("digit=").append(getDigit()).append(",");
}
if (isSpeech())
{
sb.append("speech=true,");
sb.append("score=").append(getScore()).append(",");
sb.append("text='").append(getText()).append("',");
sb.append("grammar='").append(getGrammar()).append("',");
}
if (isTimeout())
{
sb.append("timeout=true,");
}
if (getNumberOfResults() > 1)
{
sb.append("numberOfResults=").append(getNumberOfResults()).append(",");
sb.append("allResults=").append(getAllResults()).append(",");
}
sb.append("endpos=").append(getEndpos()).append("]");
return sb.toString();
}
/**
* Container class for recognized speech.
*
* @see SpeechRecognitionResult#getAllResults()
*/
public static class SpeechResult implements Serializable
{
private static final long serialVersionUID = 0L;
private final int score;
private final String text;
private final String grammar;
private SpeechResult(int score, String text, String grammar)
{
this.score = score;
this.text = text;
this.grammar = grammar;
}
/**
* Returns the confidence score. This is an integer between 0 (lowest confidence)
* and 1000 (highest confidence).
*
* @return the confidence score.
*/
public int getScore()
{
return score;
}
/**
* Returns the text. This is the text that was recognized by the speech engine.
*
* @return the text
*/
public String getText()
{
return text;
}
/**
* Returns the grammar. This is the grammar that was used by the speech engine.
*
* @return the grammar
*/
public String getGrammar()
{
return grammar;
}
public String toString()
{
final StringBuilder sb = new StringBuilder("[");
sb.append("score=").append(score).append(",");
sb.append("text='").append(text).append("',");
sb.append("grammar='").append(grammar).append("']");
return sb.toString();
}
}
}

View File

@ -0,0 +1,40 @@
package org.asteriskjava.fastagi;
/**
* Mapping strategy that maps all requests to the same script instance.
*
* @since 1.0.0
*/
public class StaticMappingStrategy implements MappingStrategy
{
private AgiScript agiScript;
public StaticMappingStrategy()
{
}
/**
* Creates a new StaticMappingStrategy that maps all requests to the given script.
*
* @param agiScript the script to map to.
*/
public StaticMappingStrategy(AgiScript agiScript)
{
this.agiScript = agiScript;
}
/**
* Sets the AgiScript to map to.
*
* @param agiScript the AgiScript to map to.
*/
public void setAgiScript(AgiScript agiScript)
{
this.agiScript = agiScript;
}
public AgiScript determineScript(AgiRequest request)
{
return agiScript;
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi.command;
import java.io.Serializable;
/**
* Abstract base class that provides some convenience methods for
* implementing AgiCommand classes.
*
* @author srt
* @version $Id: AbstractAgiCommand.java 1013 2008-03-31 06:51:03Z srt $
*/
public abstract class AbstractAgiCommand implements Serializable, AgiCommand
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3257849874518456633L;
public abstract String buildCommand();
/**
* Escapes and quotes a given String according to the rules set by
* Asterisk's AGI.
*
* @param s the String to escape and quote
* @return the transformed String
*/
protected String escapeAndQuote(String s)
{
String tmp;
if (s == null)
{
return "\"\"";
}
tmp = s;
tmp = tmp.replaceAll("\\\"", "\\\\\""); // escape quotes
tmp = tmp.replaceAll("\\\n", ""); // filter newline
return "\"" + tmp + "\""; // add quotes
}
@Override
public String toString()
{
StringBuffer sb;
sb = new StringBuffer(getClass().getName()).append("[");
sb.append("command='").append(buildCommand()).append("', ");
sb.append("systemHashcode=").append(System.identityHashCode(this)).append("]");
return sb.toString();
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi.command;
/**
* AgiCommand that can be sent to Asterisk via the Asterisk Gateway Interface.<p>
* This interface contains only one method that transforms the command to a
* String representation understood by Asterisk.
*
* @author srt
* @version $Id: AgiCommand.java 938 2007-12-31 03:23:38Z srt $
*/
public interface AgiCommand
{
/**
* Returns a string suitable to be sent to asterisk.<p>
*
* @return a string suitable to be sent to asterisk.
*/
String buildCommand();
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi.command;
/**
* Answers channel if not already in answer state.<p>
* Returns -1 on channel failure, or 0 if successful.
*
* @author srt
* @version $Id: AnswerCommand.java 938 2007-12-31 03:23:38Z srt $
*/
public class AnswerCommand extends AbstractAgiCommand
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3762248656229053753L;
/**
* Creates a new AnswerCommand.
*/
public AnswerCommand()
{
super();
}
@Override
public String buildCommand()
{
return "ANSWER";
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi.command;
/**
* Breaks the Async AGI loop.
*
* @author srt
* @version $Id: AsyncAgiBreakCommand.java 1015 2008-04-04 21:56:36Z srt $
*/
public class AsyncAgiBreakCommand extends AbstractAgiCommand
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new AsyncAgiBreakCommand.
*/
public AsyncAgiBreakCommand()
{
super();
}
@Override
public String buildCommand()
{
return "ASYNCAGI BREAK";
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi.command;
/**
* Returns the status of the specified channel. If no channel name is given the
* returns the status of the current channel.<p>
* Return values:
* <ul>
* <li>0 Channel is down and available
* <li>1 Channel is down, but reserved
* <li>2 Channel is off hook
* <li>3 Digits (or equivalent) have been dialed
* <li>4 Line is ringing
* <li>5 Remote end is ringing
* <li>6 Line is up
* <li>7 Line is busy
* </ul>
*
* @author srt
* @version $Id: ChannelStatusCommand.java 938 2007-12-31 03:23:38Z srt $
*/
public class ChannelStatusCommand extends AbstractAgiCommand
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3904959746380281145L;
/**
* The name of the channel to query or <code>null</code> for the current
* channel.
*/
private String channel;
/**
* Creates a new ChannelStatusCommand that queries the current channel.
*/
public ChannelStatusCommand()
{
super();
}
/**
* Creates a new ChannelStatusCommand that queries the given channel.
*
* @param channel the name of the channel to query.
*/
public ChannelStatusCommand(String channel)
{
super();
this.channel = channel;
}
/**
* Returns the name of the channel to query.
*
* @return the name of the channel to query or <code>null</code> for the
* current channel.
*/
public String getChannel()
{
return channel;
}
/**
* Sets the name of the channel to query.
*
* @param channel the name of the channel to query or <code>null</code>
* for the current channel.
*/
public void setChannel(String channel)
{
this.channel = channel;
}
@Override
public String buildCommand()
{
return "CHANNEL STATUS"
+ (channel == null ? "" : " " + escapeAndQuote(channel));
}
}

View File

@ -0,0 +1,294 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi.command;
/**
* Plays the given file, allowing playback to be interrupted by the given
* digits, if any, and allows the listner to control the stream.<p>
* If offset is provided then the audio will seek to sample offset before play
* starts.<p>
* Returns 0 if playback completes without a digit being pressed, or the ASCII
* numerical value of the digit if one was pressed, or -1 on error or if the
* channel was disconnected. <p>
* Remember, the file extension must not be included in the filename.<p>
* Available since Asterisk 1.2
*
* @author srt
* @version $Id: ControlStreamFileCommand.java 938 2007-12-31 03:23:38Z srt $
* @since 0.2
*/
public class ControlStreamFileCommand extends AbstractAgiCommand
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3978141041352128820L;
/**
* The name of the file to stream.
*/
private String file;
/**
* When one of these digits is pressed while streaming the command returns.
*/
private String escapeDigits;
/**
* The offset samples to skip before streaming.
*/
private int offset;
private String forwardDigit;
private String rewindDigit;
private String pauseDigit;
/**
* Creates a new ControlStreamFileCommand, streaming from the beginning. It
* uses the default digit "#" for forward and "*" for rewind and does not
* support pausing.
*
* @param file the name of the file to stream, must not include extension.
*/
public ControlStreamFileCommand(String file)
{
super();
this.file = file;
this.offset = -1;
}
/**
* Creates a new ControlStreamFileCommand, streaming from the beginning. It
* uses the default digit "#" for forward and "*" for rewind and does not
* support pausing.
*
* @param file the name of the file to stream, must not include extension.
* @param escapeDigits contains the digits that allow the user to interrupt
* this command.
*/
public ControlStreamFileCommand(String file, String escapeDigits)
{
super();
this.file = file;
this.escapeDigits = escapeDigits;
this.offset = -1;
}
/**
* Creates a new ControlStreamFileCommand, streaming from the given offset.
* It uses the default digit "#" for forward and "*" for rewind and does not
* support pausing.
*
* @param file the name of the file to stream, must not include extension.
* @param escapeDigits contains the digits that allow the user to interrupt
* this command. May be <code>null</code> if you don't want the
* user to interrupt.
* @param offset the offset samples to skip before streaming.
*/
public ControlStreamFileCommand(String file, String escapeDigits, int offset)
{
super();
this.file = file;
this.escapeDigits = escapeDigits;
this.offset = offset;
}
/**
* Creates a new ControlStreamFileCommand, streaming from the given offset.
* It allows the user to pause streaming by pressing the pauseDigit.
*
* @param file the name of the file to stream, must not include extension.
* @param escapeDigits contains the digits that allow the user to interrupt
* this command. May be <code>null</code> if you don't want the
* user to interrupt.
* @param offset the offset samples to skip before streaming.
* @param forwardDigit the digit for fast forward.
* @param rewindDigit the digit for rewind.
* @param pauseDigit the digit for pause and unpause.
*/
public ControlStreamFileCommand(String file, String escapeDigits,
int offset, String forwardDigit, String rewindDigit,
String pauseDigit)
{
super();
this.file = file;
this.escapeDigits = escapeDigits;
this.offset = offset;
this.forwardDigit = forwardDigit;
this.rewindDigit = rewindDigit;
this.pauseDigit = pauseDigit;
}
/**
* Returns the name of the file to stream.
*
* @return the name of the file to stream.
*/
public String getFile()
{
return file;
}
/**
* Sets the name of the file to stream.
*
* @param file the name of the file to stream, must not include extension.
*/
public void setFile(String file)
{
this.file = file;
}
/**
* Returns the digits that allow the user to interrupt this command.
*
* @return the digits that allow the user to interrupt this command.
*/
public String getEscapeDigits()
{
return escapeDigits;
}
/**
* Sets the digits that allow the user to interrupt this command.
*
* @param escapeDigits the digits that allow the user to interrupt this
* command or <code>null</code> for none.
*/
public void setEscapeDigits(String escapeDigits)
{
this.escapeDigits = escapeDigits;
}
/**
* Returns the offset samples to skip before streaming.
*
* @return the offset samples to skip before streaming.
*/
public int getOffset()
{
return offset;
}
/**
* Sets the offset samples to skip before streaming.
*
* @param offset the offset samples to skip before streaming.
*/
public void setOffset(int offset)
{
this.offset = offset;
}
/**
* Returns the digit for fast forward.
*
* @return the digit for fast forward.
*/
public String getForwardDigit()
{
return forwardDigit;
}
/**
* Returns the digit for rewind.
*
* @return the digit for rewind.
*/
public String getRewindDigit()
{
return rewindDigit;
}
/**
* Retruns the digit for pause and unpause.
*
* @return the digit for pause and unpause.
*/
public String getPauseDigit()
{
return pauseDigit;
}
/**
* Sets the control digits for fast forward and rewind.
*
* @param forwardDigit the digit for fast forward.
* @param rewindDigit the digit for rewind.
*/
public void setControlDigits(String forwardDigit, String rewindDigit)
{
this.forwardDigit = forwardDigit;
this.rewindDigit = rewindDigit;
}
/**
* Sets the control digits for fast forward, rewind and pause.
*
* @param forwardDigit the digit for fast forward.
* @param rewindDigit the digit for rewind.
* @param pauseDigit the digit for pause and unpause.
*/
public void setControlDigits(String forwardDigit, String rewindDigit,
String pauseDigit)
{
this.forwardDigit = forwardDigit;
this.rewindDigit = rewindDigit;
this.pauseDigit = pauseDigit;
}
@Override
public String buildCommand()
{
StringBuffer sb;
sb = new StringBuffer("CONTROL STREAM FILE ");
sb.append(escapeAndQuote(file));
sb.append(" ");
sb.append(escapeAndQuote(escapeDigits));
if (offset >= 0)
{
sb.append(" ");
sb.append(offset);
}
else if (forwardDigit != null || rewindDigit != null
|| pauseDigit != null)
{
sb.append(" 0");
}
if (forwardDigit != null || rewindDigit != null || pauseDigit != null)
{
sb.append(" ");
sb.append(forwardDigit);
}
if (rewindDigit != null || pauseDigit != null)
{
sb.append(" ");
sb.append(rewindDigit);
}
if (pauseDigit != null)
{
sb.append(" ");
sb.append(pauseDigit);
}
return sb.toString();
}
}

View File

@ -0,0 +1,114 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi.command;
/**
* Deletes a family or specific keytree within a family in the Asterisk
* database.<p>
* Returns 1 if successful, 0 otherwise.
*
* @author srt
* @version $Id: DatabaseDelCommand.java 938 2007-12-31 03:23:38Z srt $
*/
public class DatabaseDelCommand extends AbstractAgiCommand
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3256719598056387384L;
/**
* The family (or family of the keytree) to delete.
*/
private String family;
/**
* The keyTree to delete.
*/
private String keyTree;
/**
* Creates a new DatabaseDelCommand to delete a family.
*
* @param family the family to delete.
*/
public DatabaseDelCommand(String family)
{
super();
this.family = family;
}
/**
* Creates a new DatabaseDelCommand to delete a keytree.
*
* @param family the family of the keytree to delete.
* @param keyTree the keytree to delete.
*/
public DatabaseDelCommand(String family, String keyTree)
{
super();
this.family = family;
this.keyTree = keyTree;
}
/**
* Returns the family (or family of the keytree) to delete.
*
* @return the family (or family of the keytree) to delete.
*/
public String getFamily()
{
return family;
}
/**
* Sets the family (or family of the keytree) to delete.
*
* @param family the family (or family of the keytree) to delete.
*/
public void setFamily(String family)
{
this.family = family;
}
/**
* Returns the the keytree to delete.
*
* @return the keytree to delete.
*/
public String getKeyTree()
{
return keyTree;
}
/**
* Sets the keytree to delete.
*
* @param keyTree the keytree to delete.
*/
public void setKeyTree(String keyTree)
{
this.keyTree = keyTree;
}
@Override
public String buildCommand()
{
return "DATABASE DELTREE " + escapeAndQuote(family)
+ (keyTree == null ? "" : " " + escapeAndQuote(keyTree));
}
}

View File

@ -0,0 +1,119 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi.command;
/**
* Deletes a family or specific keytree within a family in the Asterisk database.<p>
* Returns 1 if successful, 0 otherwise.
*
* @author srt
* @version $Id: DatabaseDelTreeCommand.java 1286 2009-04-04 09:40:40Z srt $
*/
public class DatabaseDelTreeCommand extends AbstractAgiCommand
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3256719598056387384L;
/**
* The family of the key to delete.
*/
private String family;
/**
* The keytree to delete.
*/
private String keyTree;
/**
* Creates a new DatabaseDelCommand to delete a whole family.
*
* @param family the family to delete.
*/
public DatabaseDelTreeCommand(String family)
{
super();
this.family = family;
}
/**
* Creates a new DatabaseDelCommand to delete a keytree within a given family.
*
* @param family the family of the keytree to delete.
* @param keyTree the keytree to delete.
*/
public DatabaseDelTreeCommand(String family, String keyTree)
{
super();
this.family = family;
this.keyTree = keyTree;
}
/**
* Returns the family of the key to delete.
*
* @return the family of the key to delete.
*/
public String getFamily()
{
return family;
}
/**
* Sets the family of the key to delete.
*
* @param family the family of the key to delete.
*/
public void setFamily(String family)
{
this.family = family;
}
/**
* Returns the the keytree to delete.
*
* @return the keytree to delete.
*/
public String getKeyTree()
{
return keyTree;
}
/**
* Sets the keytree to delete.
*
* @param keyTree the keytree to delete, <code>null</code> to delete the whole family.
*/
public void setKeyTree(String keyTree)
{
this.keyTree = keyTree;
}
@Override
public String buildCommand()
{
if (keyTree == null)
{
return "DATABASE DELTREE " + escapeAndQuote(family) + " " + escapeAndQuote(keyTree);
}
else
{
return "DATABASE DELTREE " + escapeAndQuote(family);
}
}
}

View File

@ -0,0 +1,104 @@
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.fastagi.command;
/**
* Retrieves an entry in the Asterisk database for a given family and key.<p>
* Returns 0 if is not set. Returns 1 if the variable is set and returns the
* value in parenthesis.<p>
* Example return code: 200 result=1 (testvariable)
*
* @author srt
* @version $Id: DatabaseGetCommand.java 938 2007-12-31 03:23:38Z srt $
*/
public class DatabaseGetCommand extends AbstractAgiCommand
{
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3256719598056387384L;
/**
* The family of the key to retrieve.
*/
private String family;
/**
* The key to retrieve.
*/
private String key;
/**
* Creates a new DatabaseGetCommand.
*
* @param family the family of the key to retrieve.
* @param key the key to retrieve.
*/
public DatabaseGetCommand(String family, String key)
{
super();
this.family = family;
this.key = key;
}
/**
* Returns the family of the key to retrieve.
*
* @return the family of the key to retrieve.
*/
public String getFamily()
{
return family;
}
/**
* Sets the family of the key to retrieve.
*
* @param family the family of the key to retrieve.
*/
public void setFamily(String family)
{
this.family = family;
}
/**
* Returns the the key to retrieve.
*
* @return the key to retrieve.
*/
public String getKey()
{
return key;
}
/**
* Sets the key to retrieve.
*
* @param key the key to retrieve.
*/
public void setKey(String key)
{
this.key = key;
}
@Override
public String buildCommand()
{
return "DATABASE GET " + escapeAndQuote(family) + " "
+ escapeAndQuote(key);
}
}

Some files were not shown because too many files have changed in this diff Show More