/*
* 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.internal;
import java.io.*;
import java.util.*;
import java.util.regex.*;
import org.asteriskjava.fastagi.reply.AgiReply;
/**
* Default implementation of the AgiReply interface.
*
* @author srt
* @version $Id: AgiReplyImpl.java 1009 2008-03-28 01:22:38Z srt $
*/
public class AgiReplyImpl implements Serializable, AgiReply
{
private static final Pattern STATUS_PATTERN = Pattern.compile("^(\\d{3})[ -]");
private static final Pattern RESULT_PATTERN = Pattern.compile("^200 result= *(\\S+)");
private static final Pattern PARENTHESIS_PATTERN = Pattern.compile("^200 result=\\S* +\\((.*)\\)");
private static final Pattern ADDITIONAL_ATTRIBUTES_PATTERN = Pattern.compile("^200 result=\\S* +(\\(.*\\) )?(.+)$");
private static final Pattern ADDITIONAL_ATTRIBUTE_PATTERN = Pattern.compile("(\\S+)=(\\S+)");
private static final Pattern SYNOPSIS_PATTERN = Pattern.compile("^\\s*Usage:\\s*(.*)\\s*$");
private static final String END_OF_PROPER_USAGE = "520 End of proper usage.";
private Matcher matcher;
/**
* Serial version identifier.
*/
private static final long serialVersionUID = 3256727294671337012L;
private List<String> lines;
private String firstLine;
/**
* The result, that is the part directly following the "result=" string.
*/
private String result;
/**
* The status code.
*/
private Integer status;
/**
* Additional attributes contained in this reply, for example endpos.
*/
private Map<String, String> attributes;
/**
* The contents of the parenthesis.
*/
private String extra;
/**
* In case of status == 520 (invalid command syntax) this attribute contains
* the synopsis of the command.
*/
private String synopsis;
/**
* In case of status == 520 (invalid command syntax) this attribute contains
* the usage of the command.
*/
private String usage;
AgiReplyImpl()
{
super();
}
AgiReplyImpl(List<String> lines)
{
super();
if (lines != null)
{
this.lines = new ArrayList<String>(lines);
if (!lines.isEmpty())
{
firstLine = lines.get(0);
}
}
}
public String getFirstLine()
{
return firstLine;
}
public List<String> getLines()
{
return lines;
}
public int getResultCode()
{
String result;
result = getResult();
if (result == null)
{
return -1;
}
try
{
return Integer.parseInt(result);
}
catch (NumberFormatException e)
{
return -1;
}
}
public char getResultCodeAsChar()
{
int resultCode;
resultCode = getResultCode();
if (resultCode < 0)
{
return 0x0;
}
return (char) resultCode;
}
public String getResult()
{
if (result != null)
{
return result;
}
matcher = RESULT_PATTERN.matcher(firstLine);
if (matcher.find())
{
result = matcher.group(1);
}
return result;
}
public int getStatus()
{
if (status != null)
{
return status;
}
matcher = STATUS_PATTERN.matcher(firstLine);
if (matcher.find())
{
status = Integer.parseInt(matcher.group(1));
}
return status;
}
public String getAttribute(String name)
{
if (getStatus() != SC_SUCCESS)
{
return null;
}
if ("result".equalsIgnoreCase(name))
{
return getResult();
}
return getAttributes().get(name.toLowerCase(Locale.ENGLISH));
}
protected Map<String, String> getAttributes()
{
if (attributes != null)
{
return attributes;
}
attributes = new HashMap<String, String>();
matcher = ADDITIONAL_ATTRIBUTES_PATTERN.matcher(firstLine);
if (matcher.find())
{
String s;
Matcher attributeMatcher;
s = matcher.group(2);
attributeMatcher = ADDITIONAL_ATTRIBUTE_PATTERN.matcher(s);
while (attributeMatcher.find())
{
String key;
String value;
key = attributeMatcher.group(1);
value = attributeMatcher.group(2);
attributes.put(key.toLowerCase(Locale.ENGLISH), value);
}
}
return attributes;
}
private boolean extraCreated;
public String getExtra()
{
if (getStatus() != SC_SUCCESS)
{
return null;
}
if (extraCreated)
{
return extra;
}
matcher = PARENTHESIS_PATTERN.matcher(firstLine);
if (matcher.find())
{
extra = matcher.group(1);
}
extraCreated = true;
return extra;
}
public String getSynopsis()
{
if (getStatus() != SC_INVALID_COMMAND_SYNTAX)
{
return null;
}
if (synopsis == null)
{
if (lines.size() > 1)
{
String secondLine;
Matcher synopsisMatcher;
secondLine = lines.get(1);
synopsisMatcher = SYNOPSIS_PATTERN.matcher(secondLine);
if (synopsisMatcher.find())
{
synopsis = synopsisMatcher.group(1);
}
}
}
return synopsis;
}
/**
* Returns the usage of the command sent if Asterisk expected a different
* syntax (getStatus() == SC_INVALID_COMMAND_SYNTAX).
*
* @return the usage of the command sent, <code>null</code> if there were
* no syntax errors.
*/
public String getUsage()
{
if (usage == null)
{
StringBuilder usageSB;
usageSB = new StringBuilder();
for (int i = 2; i < lines.size(); i++)
{
String line;
line = lines.get(i);
if (END_OF_PROPER_USAGE.equals(line))
{
break;
}
usageSB.append(line.trim());
usageSB.append(" ");
}
usage = usageSB.toString().trim();
}
return usage;
}
@Override
public String toString()
{
StringBuilder sb;
sb = new StringBuilder("AgiReply[");
sb.append("status=").append(getStatus()).append(",");
if (status == SC_SUCCESS)
{
sb.append("result='").append(getResult()).append("',");
sb.append("extra='").append(getExtra()).append("',");
sb.append("attributes=").append(getAttributes()).append(",");
}
if (status == SC_INVALID_COMMAND_SYNTAX)
{
sb.append("synopsis='").append(getSynopsis()).append("',");
}
sb.append("systemHashcode=").append(System.identityHashCode(this));
sb.append("]");
return sb.toString();
}
}