Примеры динамического кода акшена и веб-сервисов

Материал из BiTel WiKi

Перейти к: навигация, поиск

Динамическим кодом в данном случае можно как писать новые экшены (практическое значение имеют больше веб-экшены, т.е. экшены веб-интерфейса) и веб-сервисы, так и обёртывать существующие, т.е. заменять их, а внутри вызывать родительский метод, или не вызывать в зависимости от обстоятельств. Этим можно полностью заменить функционал такой, как запуск скрипта до и после акшена. Помимо того, что область применения шире, ещё динамичемским кодом просто быстрее, удобнее и надёжнее. В данном разделе рассмотрим примеры скриптов, совершенно аналогичные упомянутым в разделе «примеры скриптов до и после акшена», за исключением задачи "проверка смены статуса", которую в старом механизме реализовать вообще невозможно, т.к. смена статуса реализована только в веб-сервисах и событий там никаких нету.

Динамические экшены

В случае старых экшенов в конфигурацию сервера прописываются динамические классы, и то, что они заменяют. Динамический класс позволяет получить, чтобы потом заменить (обернуть) вызов метода родного класса. Параметр в конфиге примерно такой:

dynaction:<модуль>.<режим.><экшенкласснаме>=дин.класс

Примеры:

dynaction:contract.ActionCheckContractLimitUpdate=дин.класс
dynaction:ru.bitel.bgbilling.plugins.crm.ActionUpdateRegisterTask=дин.класс
dynaction:contract.web.ActionAdditionalAction=дин.класс

Класс может быть простой кастомный, унаследованный от самого корневого класса, но удобнее наследовать от самого перегружаемого класса, если потенциально нужна хоть какая-то логика из него. Внутри дин.класса при необходимости надо сделать явным образом вызов родительского метода (super.doAction, например). Если нужно только вывести ошибку, например, то унаследованный метод не нужно вызывать, очевидно. При поиске реализации соответствующего экшена сначала ищутся динамические классы прописанные. Дальше ничего не проверяется, что нашлось то и вернулось, т.е. если прописан dynaction, но косячный, то дальше не ищется, незачем.

Для нашего примера прописать нужно следующее:

dynaction:contract.ActionUpdateContractLimit=ru.xxx.ActionUpdateContractLimit
dynaction:ru.bitel.bgbilling.plugins.crm.ActionUpdateRegisterTask=ru.xxx.ActionUpdateRegisterTask
package ru.xxx;
 
import java.sql.SQLException;
 
import ru.bitel.bgbilling.common.BGException;
import ru.bitel.bgbilling.common.BGMessageException;
import ru.bitel.common.Utils;
 
/**
 * Перегруженный экшен для проверки некоторых параметров:
 * 2. Скрипт реализующий запрет изменения "лимита" договора в случае если поле комментарий пустое.
 * 
 * В конфиг сервера прописывается:
 * dynaction:contract.ActionUpdateContractLimit=ru.xxx.ActionUpdateContractLimit
 * @author dimon
 */
public class ActionUpdateContractLimit
	extends bitel.billing.server.contract.action.ActionUpdateContractLimit
{
	@Override
    public void doAction() 
    	throws SQLException, BGException
	{
		//[2]
		//module=contract
		//action=UpdateContractLimit
		//comment=%ED%E5%E3%E5%ED
		// получаем параметры как в экшене
		String comment = getParameter( "comment", "" );
		// если 1) комментарий пустой => ругаемся
		if( Utils.isBlankString( comment ) )
		{
			throw new BGMessageException( "Введите комментарий" );
		}
		// иначе вызываем родительский метод
		super.doAction();
	}
}
package ru.xxx;
 
import java.sql.SQLException;
import java.util.Date;
 
import bitel.billing.common.TimeUtils;
 
import ru.bitel.bgbilling.common.BGException;
import ru.bitel.bgbilling.common.BGMessageException;
import ru.bitel.bgbilling.plugins.crm.common.model.RegisterTask;
import ru.bitel.bgbilling.plugins.crm.server.dao.RegisterTaskManager;
import ru.bitel.common.Utils;
 
/**
 * Перегруженный экшен для проверки некоторых параметров:
 * 1. Скрипт реализующий запрет изменения "срока" задачи в плагине CRM всем кроме того кто задачу создал, а так же кроме отдельно обозначенного администратора.
 * 4. CRM: Нужно сделать так чтобы задачу нельзя было закрыть если поле "Резолюция" пустое.
 * 
 * В конфиг сервера прописывается:
 * dynaction:ru.bitel.bgbilling.plugins.crm.ActionUpdateRegisterTask=ru.xxx.ActionUpdateRegisterTask
 * @author dimon
 */
public class ActionUpdateRegisterTask
	extends ru.bitel.bgbilling.plugins.crm.server.action.ActionUpdateRegisterTask
{
	/** ид отдельно обозначенного администратора */
	private final int ADMIN_USER = 1;
 
	@Override
    public void doAction() 
    	throws SQLException, BGException
	{
		// [1]
		// module=ru.bitel.bgbilling.plugins.crm
		// action=UpdateRegisterTask
		// id=32
		// target_date_and_time=21.04.2010+00%3A00
		// получаем параметры как в экшене
		int id = getIntParameter( "id", -1 );
		Date targetDate = getDateParameter( "target_date_and_time", "dd.MM.yyyy HH:mm", null );
		if( targetDate == null )
		{
			targetDate = getDateParameter( "target_date", "dd.MM.yyyy", null  );
		}
		// получаем таск
		RegisterTaskManager manager = new RegisterTaskManager( con );
		RegisterTask task = manager.getTaskById( id );
		// если 1) юзер не админ, и 2) юзер не тот кто создал задачу, то 3) проверяем время и если оно не такое => ругаемся
		if( userID != ADMIN_USER && userID != task.getCreateUserId() && !TimeUtils.dateEqual( targetDate, task.getTargetDate() ) )
		{
			throw new BGMessageException( "Вам нельзя менять срок задачи" );
		}
		// [4]
		// module=ru.bitel.bgbilling.plugins.crm
		// action=UpdateRegisterTask
		// status=2
		// resolution=%F0%E5%E7%EE%EB%FE%F6%E8%FF
		// получаем параметры как в экшене
		int status = getIntParameter( "status", 0 );
		String resolution = getParameter( "resolution", "" );
		//System.out.println("status="+status);
		//System.out.println("resolution="+resolution);
		// если 1) статус "закрыто" и 2) резолюция пустая => ругаемся
		if( status == 2 && Utils.isBlankString( resolution ) )
		{
			throw new BGMessageException( "Для закрытия заполните резолюцию" );
		}
		// иначе вызываем родительский метод
		super.doAction();
	}
}

Динамические веб-сервисы

Динамический класс позволяет заменить (обернуть) вызов метода вебсервиса. Параметр в конфиге такой:

dynservice:<модуль>.<интерфейс_сервиса>=<дин.класс>

Например:

dynservice:ru.bitel.bgbilling.kernel.contract.status.ContractStatusMonitorService=дин.класс

Внутри дин.класса при необходимости надо перегрузить нужный метод (или несколько), а после сделать (или не сделать, если обёртка отработала сама всё, например, вывела ошибку) явным образом вызов соответствующего родительского метода (super.blabla(foo,bar)). При поиске реализации сервиса сначала ищется среди динамических классов, но если в динкоде класс заявлен, но косячный, то дальше не ищем, незачем.

Для нашего примера прописать нужно следующее:

dynservice:ru.bitel.bgbilling.kernel.contract.status.ContractStatusMonitorService=ru.xxx.ContractStatusMonitorServiceImpl
package ru.xxx;
 
import java.util.Date;
 
import javax.jws.WebService;
 
import ru.bitel.bgbilling.common.BGException;
import ru.bitel.bgbilling.common.BGMessageException;
import ru.bitel.bgbilling.kernel.contract.status.common.ContractStatusMonitorService;
import ru.bitel.common.Utils;
 
/**
 * Перегруженный вебсервис для проверки некоторых параметров:
 * 3. Скрипт реализующий запрет изменения "Статуса" договора в случае если поле комментарий пустое.
 * 
 * В конфиг сервера прописывается:
 * dynservice:ru.bitel.bgbilling.kernel.contract.status.ContractStatusMonitorService=ru.specsvyaz.ContractStatusMonitorServiceImpl
 * @author dimon
 */
@WebService(endpointInterface = "ru.bitel.bgbilling.kernel.contract.status.common.ContractStatusMonitorService")
public class ContractStatusMonitorServiceImpl
	extends ru.bitel.bgbilling.kernel.contract.status.server.service.ContractStatusMonitorServiceImpl
	implements ContractStatusMonitorService
{
	@Override
	public void changeContractStatus( int[] cids, int statusId, Date dateFrom, Date dateTo, String comment )
	    throws BGException
	{
		//System.out.println("\t!\tchangeContractStatus");
		// [3]
		// ContractStatusMonitorService:changeContractStatus
		// @WebParam( name = "comment" ) String comment
		if( Utils.isBlankString( comment ) )
		{
			throw new BGMessageException( "Введите комментарий" );
		}
		super.changeContractStatus( cids, statusId, dateFrom, dateTo, comment );
	}
}

--dimOn 12:00, 28 ноября 2012 (UTC)

Личные инструменты