As a proof of concept, I'm building this extremely simple Twitter Friends crawler. Here's what it will do:
Execute CrawlJob for Twitter account "twitter-user-1"
Find all friends of "twitter-user-1"
Execute CrawlJob for all friends of "twitter-user-1"
Here's what my code looks like so far:
def main( args:Array[String] ) {
scalar {
grid.execute(classOf[CrawlTask], "twitter-user-1").get
}
}
class CrawlTask extends GridTaskNoReduceSplitAdapter[String] {
def split( gridSize:Int, arg:String): Collection[GridJob] = {
val jobs:Collection[GridJob] = new ArrayList[GridJob]()
val initialCrawlJob = new CrawlJob()
initialCrawlJob.twitterId = arg
jobs.add(initialCrawlJob)
jobs
}
}
class CrawlJob extends GridJob {
var twitterId:String = new String()
def cancel() = {
println("cancel - " + twitterId)
}
def execute():Object = {
println("fetch friends for - " + twitterId)
// Fetch and execute CrawlJobs for all friends
return null
}
}
I have Java services prepared for all twitter interaction. Need some examples to figure out how to create new jobs within an existing job and associate it with the original Task.
Thanks | Srirangan
How did I get around this?
Conceptually unite GridTasks and GridJobs. MySpecialGridTask can only have one MySpecialGridJob.
Then, it is easy to execute new GridTasks in the Task or the Job.
In the example above:
class CrawlJob extends GridJob {
var twitterId:String = new String()
def cancel() = {
println("cancel - " + twitterId)
}
def execute():Object = {
println("fetch friends for - " + twitterId)
// Fetch and execute CrawlJobs for all friends
// Execute Job Here
grid.execute(classOf[CrawlTask], "twitter-user-2").get
grid.execute(classOf[CrawlTask], "twitter-user-3").get
return null
}
}
Related
I'm new in gatling/scala
The main idea of my scenario: I need to pass each item from some prepared List of String into the method, and check that response correct
so it's my scenario
object ForeachScenario extends Scenario {
override def profile(): OpenInjectionStep = {
atOnceUsers(3)
}
val rules_new = List("one", "two", "three")
val custom_feed = rules_new.map(el=> Map("expressions_rules" -> el)).iterator
override def createScenario(): ChainBuilder = {
group(name()) {
tryMax(SCENARIO_MAX_RETRIES) {
tryMax(NUMBER_OF_ATTEMPTS) {
// Creating a user and his context
exec(
UserCreator.createUser(
"userName", "userUid"
)
)
}.exitHereIfFailed
.tryMax(NUMBER_OF_ATTEMPTS) {
feed(custom_feed)
.exec(
someClassWithMethod.method("${userName}", "${userUid}", "request-bodies/rulesDS/rules-expressions.json")
.requestBuilder
.check(status.is(200))
.check(jsonPath("$.evaluations[0].result").find.is("100"))
)
}
}
}
}
}
in general, it works as expected, but... I would like to change this code for using only one virtual user, I have some separate scenario for checking functionality related to UserCreator.createUser and in this case, the main task create a user and under his context check another API, so, for this task user creation for each element in my list is redundantly
override def profile(): OpenInjectionStep = {
atOnceUsers(1)
}
I can't understand how can I realize this, because feeder uses only the first item from the list in the case with one virtual user (atOnceUsers(1)), probably I can save somehow userName and UserUid
exec(
UserCreator.createUser(
"userName", "userUid"
)
)
and use them further OR probably have to use another approach for iteration?
can somebody help me with that?
I'm following this codelab to build an paging3 app with github API and a local DB. While the first 2 pages load fine, the mediator hits a loop when trying to load the 3rd page when scrolling to bottom - the same PagingState is passed to load() function over and over.
Just wondering if anyone knows what could be the possible root cause here?
Some implementation details:
RemoteMediator: (the prevPage and currentPage is from github API's pagination response header and saved to a local DB.)
// RepositoryMediator
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, Repository>
): MediatorResult {
return when (loadType) {
LoadType.REFRESH -> {
fireRequestForPage(1, true /*clear DB*/)
return Success(endOfPaginationReached = false)
}
LoadType.APPEND -> {
// !!!!!!! kept getting the same state when APPEND is triggered, resulting in same currentPage and nextPage
// get currentPage, nextPage from state.lastItemOrNull
if(currentPage < nextPage) {
fireRequestForPage(nextPage)
Success(endOfPaginationReached = false)
} else {
return Success(endOfPaginationReached = true)
}
LoadType.PREPEND -> {
// get currentPage, prevPage from state.firstItemOrNull
if(currentPage > prevPage) {
fireRequestForPage(prevPage)
Success(endOfPaginationReached = false)
} else {
return Success(endOfPaginationReached = true)
}
}
}
}
Observable: I'm using liveData instead of flow to from the Pager:
fun searchRepositoryWithUserId(userLoginName: String): LiveData<PagingData<Repository>> {
// need to create a new Pager each time because the search query is different
return Pager(
config = PagingConfig(pageSize = PAGE_SIZE, enablePlaceholders = false),
remoteMediator = RepositoryMediator()
) {
repoDao().getRepositoriesOfUser(userLoginName)
}.liveData
}
Dao: just a plain query
#Query("SELECT * FROM repository_table WHERE login = :ownerLoginName")
fun getRepositoriesOfUser(ownerLoginName: String): PagingSource<Int, Repository>
For anyone interested, the fix is from Dao, need to update the query to sort on reponame, otherwise the query will return the same last Page for PagingSource even if there're new items inserted into DB, confusing the Mediator.
#Query("SELECT * FROM repository_table WHERE login = :ownerLoginName ORDER BY repository_name ASC")
fun getRepositoriesOfUser(ownerLoginName: String): PagingSource<Int, Repository>
Had a similar issue just now. Trying to sort by different fields had led to RemoteMediator getting stuck in a loop on different page numbers.
Turns out I couldn't rely on item ID's assigned by backend to be primary keys for my Room DB Entity. Assigning primary key ID's locally (starting from zero) seems to have fixed the issue.
I'm trying to create a service in the Android App that consumes a SOAP API. Sent values and returned values are XML.
Previously i used FormUrlEncoded + JSON in another API and worked, but with XML i'm struggling as the API seems that is not being called (HttpLoggingInterceptor don't show and also the Mockup service don't show any petition).
If i change to FormUrlEncoded my service i can see that the request is done (i checked it with HttpLoggingInterceptor, but if i remove the FormUrlEncoded seems like service is not called never.
My NetModule where is create the retrofir, parser, etc:
#Module
class NetModule {
#Provides
#Singleton
fun provideRetrofit(): Retrofit {
val client =
OkHttpClient.Builder()
.addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
})
.build()
val strategy = AnnotationStrategy()
val serializer = Persister(strategy)
return Retrofit.Builder()
.baseUrl(BuildConfig.API_URL)
.client(client)
.addConverterFactory(SimpleXmlConverterFactory.create(serializer))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
}
#Provides
#Singleton
fun provideFilesService(retrofit: Retrofit): FilesService =
retrofit.create(FilesService::class.java)
}
My FilesService.kt where the interface is defined is:
import com.liderasoluciones.enviotest.data.model.FileSendResponse
import com.liderasoluciones.enviotest.data.model.FileSendEnvelope
import io.reactivex.Flowable
import retrofit2.http.*
interface FilesService {
#Headers(
"Content-Type: application/soap+xml",
"Accept-Charset: utf-8"
)
#POST("mockWSSMTSoap")
fun sendFile(#Body body: FileSendEnvelope): Flowable<FileSendResponse>
}
My model for the Body, Request and data is FileSendEnvelope.kt and is:
import org.simpleframework.xml.Element
import org.simpleframework.xml.Root
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.NamespaceList;
#Root(name = "GetInfoByState", strict = false)
#Namespace(reference = "http://www.webservicetest.net")
class FileSendData {
#Element(name = "FileName", required = false)
var name: String? = null
}
#Root(name = "soap12:Body", strict = false)
class FileSendBody {
#Element(name = "GetInfoByFile", required = false)
var fileSendData: FileSendData? = null
}
#Root(name = "soap12:Envelope")
#NamespaceList(
Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance"),
Namespace(prefix = "xsd", reference = "http://www.w3.org/2001/XMLSchema"),
Namespace(prefix = "soap12", reference = "http://www.w3.org/2003/05/soap-envelope")
)
class FileSendEnvelope {
#Element(name = "soap12:Body", required = false)
var body: FileSendBody? = null
}
From the RemoteDataSource class is where i call the api:
class RemoteFilesDataSource(private val filesService: FilesService,
private val genericResponseEntityMapper: GenericResponseEntityMapper):
FilesDataSource {
override fun sendFile(userToken: String): Flowable<GenericResponseEntity> {
var petitionEnvelope = FileSendEnvelope()
var petitionBody = FileSendBody()
var petitionData = FileSendData()
petitionData.name = "test.png"
petitionBody.fileSendData = petitionData
petitionEnvelope.body =
return filesService.sendFile(petitionEnvelope)
.map { it.result }
.map { genericResponseEntityMapper.transform(it) }
}
}
At this moment i'm not taking so much care about the XML sent or parse the response, i just "want to check" that the API is called.
I tried to follow this info:
https://github.com/asanchezyu/RetrofitSoapSample
http://geekcalledk.blogspot.com/2014/08/use-simple-xml-with-retrofit-for-making.html
Even are java examples and i'm using Kotlin but no luck.
Any help is appreciated.
Thanks in advance.
Have you tried to use text/xml for your Content-type in your header? (and try it without the Accept-Charset header as well)
#Headers(
"Content-type: text/xml"
)
I have 2 simple APIs:
GET /users/me/photos controllers.api.UserController.getMyPhotos
GET /users/:userId/photos controllers.api.UserController.getPhotos(userId: Int)
Here's getPhotos:
def getPhotos(userId: Int) = SecuredAction.async {
logger.info(s"Searching for user $userId's photos")
userPhotosRepo.findByUserId(userId).map {
photos => Ok(Json.toJson(photos))
}
}
Here's getMyPhotos:
def getMyPhotos = SecuredAction.async { request =>
request.identity.id.map { currentUserId =>
logger.info(s"Searching for current user's photos")
getPhotos(currentUserId) // doesn't work
}.getOrElse(Future.successful(InternalServerError))
}
How can I make getMyPhotos proxy through to getPhotos without creating a helper method they both call?
Here you can use reverse routing provided by Play Framework
[full package].routes.[controller].[method]
In your case
routes.api.UserController.getPhotos(request.identity.id)
If you want the result of first action
val ans: Result = Redirect(routes.api.UserController.getPhotos(request.identity.id))
I hope that's what you were trying to ask.
EDIT:
For your concern this should be a proper way to do it
def getPhotos(userId: Long) = SecuredAction.async {
userPhotosRepo findByUserId(userId) map {
photos => Ok(Json.toJson(photos))
}
}
def getMyPhotos = SecuredAction.async { request =>
request.identity.id map { id =>
Redirect(routes.HomeController.getPhotos(id))
}
}
In Scala + Play, how to put a variable into response ?
In page
#lastName #firstName
In application controller:
def index = Action {
implicit request =>{
request.setAttribute("lastName", "john"); // not work
Ok(views.html.index("xxx"))
}
}
if in java servlet , we can do this way:
request.setAttribute("name", "value");
request.getRequestDispatcher("page.jsp").forward(request, response);
how to do the same in Scala + Play ?
You want to use view/page variables.
In your view:
#(myStringVar: String)
<b>Hello #myStringVar</b>
Your controller:
def index = Action {
implicit request => {
Ok(views.html.index(myStringVar = "Ooo!"))
}
}
Ref: https://playframework.com/documentation/2.5.x/ScalaTemplates#Overview